Skip to content
Noxalus edited this page Jun 25, 2017 · 10 revisions

Improvements

BulletML is a powerfull language that allow us to write complex bullet pattern in only few lines.

But a lot of things can't be done or are not done the proper way.

This document presents a list of changes that will improve BulletML and the parser for me, even if most of these suggestions would break the retro compatibility with former BulletML scripts.

What we can't do with BulletML

It's possible that one or more of these following things are actually feasible with BulletML, if it's the case, please tell me how.

  • Draw specific patterns with bullets like an object or write text => It's not as easy as it sounds, but with <changeDirection>, <changeSpeed> and <wait> tags, we can draw almost everything.
  • Fire ellipsis or perform some 3D like effect
  • Fire sequence bullets simultaneously (if we want to fire left and right spirals at the same time for instance) => It's possible using multiple <action label="top#"></action> tags, but it's limited to the pattern's beginning.

FPS independent

Make it FPS independent: BulletML assumes that the game runs at 60 FPS, it doesn't use time but frame as reference. It's a big mistake because it implies that the bullet patterns will not be executed at the same speed on every devices. A fork already did some changes to fix this depency to the framerate, but I would like to go further replacing all references of frame by time in the BulletML language. It means that <wait> and <term> tags will take time in milliseconds instead of frame.

New tags

Graphic specific tags

A BulletML script doesn't have anything related to the graphic part of bullets.

<color>

RGBA -> Between 0 and 1. Take the values from <red>, <green>, <blue>, <alpha> and <opacity> child nodes. If we don't use attributes for these values, it's because we want to be able to use math expression like that:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE bulletml SYSTEM "bulletml.dtd">
<bulletml>
  <action label="top">
    <fire>
      <bullet>
        <speed>1</speed>
        <color>
          <red>$rand</red>
          <green>$rand</green>
          <blue>$rand</blue>
          <alpha>1.0</alpha>
          <opacity>0.5</opacity>
        </color>
      </bullet>
    </fire>
  </action>
</bulletml>

<scale>

<sprite>

This implies to give a list of specific assets to the instance of BulletML manager. Should we specify the sprite dependencies in the BulletML pattern file?

<changeColor>

With a <color> and a <term> nodes. It will be possible to hide a bullet updating its alpha value.

<changeScale>

<changeSprite>

Use sprite ID. We need to give a Dictionary<Id, Sprite> as a parameter of the MoverManager?

No <term> tag, the switch takes effect immediately.

<trail>?

<bullet>
    <trail>10</trail> <!-- Size of the trail -->
</bullet>

<createAnimation>?

<vanishAnimation>?

<sound>

Into <fire> tag to play sound:

<fire>
    <sound>10</sound> <!-- Sound index -->
    <bullet />
</fire>

Other tags

<changePosition>

To teleport a bullet to another location.

<life>

In ms exactly like for a particle engine. => Or use the existing <vanish> tag passing a additional attribute (none, outofbound, time).

<bounce>

Or <collide>, to change the bullet's behaviour when it touches the game area border.

<bullet>
    <collide>
        <action>
            <changeDirection>
                ...
            </changeDirection>
        </action>
    </collide>
</bullet>

<offset>

To be able to spawn a bullet with an offset relative to its original spawn position.

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE bulletml SYSTEM "bulletml.dtd">
<bulletml>
  <action label="top">
    <fire>
      <bullet>
        <speed>1</speed>
        <offsetX type="absolute">100</offsetX> <!-- 100 pixels offset on the world X axis -->
        <offsetY type="relative">-100</offsetY> <!-- -100 pixels offset on the local bullet Y axis -->
      </bullet>
    </fire>
  </action>
</bulletml>

<main>

Or <start> or <mainAction> to remove the specific case of the <action label="top">

Infinite loop

Instead of writing <times>9999</times>, we should have a specific value (0 or -1) that means the loop is infinite:

<repeat>
    <times>0</times>
    <action>
        <fire>
            <bullet />
        </fire>
    </action>
</repeat>

It should be the same behaviour if we omit the <times> tag. Make sure to properly raise an error when we parse an infinite loop without <wait> tags!

New variables

Loop index variables

<repeat>
    <times>10</times>
    <action>
        <fire>
            <bullet>
                <direction>$index * (360 / $maxIndex)</direction>
            </bullet>
        </fire>
    </action>
</repeat>

Game area width and height

$width and $height.

Keeping the sequence attribute, adding these variable will allow us to do more things.

Time

$gameTime and $patternTime

Distance to player

$playerDistance, specific to each bullet.

Create mutable variables

BulletML is very clever and simple to use, especially because it's possible to make complex patterns without using custom variables or conditions. But this is also its main limitation, and some patterns are simply impossible to reproduce. Let's take the example of Touhou Satori's last spell cards: it's just a rotating pattern with a variable angle updated according to time.

Tweening

Some tags change a bullet state over time (<changeDirection>, <changeSpeed>, and <accel> tags) with a linear interpolation. It will be great to be able to specify what kind of interpolation we want through a new attribute:

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE bulletml SYSTEM "bulletml.dtd">
<bulletml>
  <action label="top">
    <fire>
      <bullet>
          <speed>1</speed>
          <action>
            <changeSpeed tweening="cubic">
              <speed>10</speed>
              <term>100</term>
            </changeSpeed>
          </action>
      </bullet>
    </fire>
  </action>
</bulletml>

Default direction

It makes a lot more sense if the default direction is absolute instead of aim.

Update original pattern's spawn position

Generally, a pattern is triggered by a moving entity, and it seems logical than if the entity is moving, the pattern's spawn position moves too. Actually, it's not the case, the bullets spawn position is relative to a root bullet fired only once, so even if the moving entity changes its position, the root bullet doesn't move.

Lasers

To remove

  • Useless attribute horizontal or vertical in the bulletml tag.
  • No root bullet anymore, the only ones bullets that we shoud see is the ones fired by a <fire> tag.
  • Replace <changeDirection>, <changeSpeed> and <accel> tags by a global modifier like an <update> or a <change> tags that can change direction, speed and acceleration at the same time.
  • Remove <bulletRef>, <fireRef> and <actionRef> tags and use already existing <bullet>, <fire>, <action> tags with a ref attribute => we can use a kind of inheritance still keeping the useful <param> tag.
  • Remove <times> tag and make it an attribute of the <repeat> tag instead. => Wrong idea: we can't use math expression into node's attributes.
  • Replace all <term> tags by <time> (in ms)

BulletMLX

Another person also thought of some improvements of the BulletML language and called it BulletMLX.