I have previously written about the shmup that Jeff and I have been working on as the first title for the game company we are building. My first article on this blog was about that game. I have also written about how I believe developers should not spend their time reinventing what already exists. So today I want to talk about the bullet engine in our game, specifically the markup language we use to create bullet patterns: BulletML.
“Why XML? WHY?!”
BulletML is a dialect of XML. These days it feels like XML has lost much of its popularity, usurped by formats like JSON, particularly in the arena of web development. But my experience in game development also gives me the sense that XML is on a decline, to the point where I believe we should offer a justification for why we use XML in our game.
We have one BulletML document for each bullet pattern. So I will begin by showing you an example of such a document.
<?xml version="1.0"?> <!DOCTYPE bulletml SYSTEM "bulletmlx.dtd"> <bulletml type="vertical"> <action label="top"> <fire> <direction type="absolute">180</direction> <bulletRef label="basic"/> </fire> </action> <bullet label="basic"> <speed>1</speed> <color red="0" blue="180" green="240"/> </bullet> </bulletml>
You may notice we use a different document type definition (DTD) than the original BulletML DTD. This is because we expand on the language with some custom elements for our game. We refer to this version as BulletMLX and later I will discuss some of our additions.
It is fair to say that BulletML is not the most obvious, self-documenting format in the world. For example, the
<action> node is not only unclear regarding its purpose, but it also has an attribute that seems entirely arbitrary. Does the
top attribute value mean the top of the screen? The top of the player?
Actually it indicates the primary action of the pattern, i.e. the ‘top level’ action. So what about the
<bullet> node then?
I am not going to explain every detail of BulletML; consult the official reference if you want to read about everything in the language. But I am going to provide a brief crash course on BulletML so that you can understand the behavior of the example document above.
<bullet> nodes define the what of the pattern while the
<action> nodes define the how. The example above defines a bullet with the label
basic, the name for that particular type of bullet. The tags within the
<bullet> node define some basic properties: its speed and its color. But notice that there is no markup for how the game fires the bullet. That is the purpose of
<action> nodes. That tag contains a
<fire> node, which is the primitive action in BulletML. As you might expect it describes how the game should fire the bullet. But which bullet? That is where the
<bulletRef/> tag comes into the picture. It references the
<bullet> by its name, telling the game to shoot that bullet. The
<direction/> tag accepts a variety of attribute values, but in this example the ‘absolute’ direction is the degree indicating where to fire the bullet relative to the screen itself. So the value of 180 means to shoot straight down.
That is the basics of BulletML. The separation between bullets and actions may seem pointless at first. But in reality it affords us much more creative control of bullet patterns. We can define multiple types of
<bullet> nodes in a single document and have multiple
<action> tags which shoot those bullets in a variety of ways. Here is a longer example demonstrating what we can do with patterns:
<?xml version="1.0"?> <!DOCTYPE bulletml SYSTEM "bulletmlx.dtd"> <bulletml type="vertical"> <action label="top"> <repeat> <times>5</times> <fire> <direction type="aim">0</direction> <bulletRef label="slow"/> </fire> <wait>60</wait> <repeat> <times>30</times> <fire> <direction type="aim">0</direction> <bulletRef label="fast"/> </fire> <wait>5</wait> </repeat> </repeat> </action> <bullet label="fast"> <speed>4</speed> <size>5</size> <color red="0" blue="180" green="240"/> </bullet> <bullet label="slow"> <speed>1</speed> <size>20</size> <color red="200" blue="70" green="0"/> </bullet> </bulletml>
Here we see two types of bullets, repetition in the action, pauses in between shots, and a different type of aiming.
BulletML is useful for our shmup because it lets us create a tool-box of bullet patterns. The longer example above hopefully gives you some indication of how we can put together a library of bullets and then write various actions for them. Being able to re-use bullet definitions across different actions lets us mix up the shape of patterns such that one type of bullet does not always fire the same way.
Another benefit to using BulletML is that we define the shots for the player in exactly the same way. We associate bullet patterns with enemies in other XML files—we created a similar markup language for defining enemies. We effectively treat the player as an enemy when it comes to her bullet patterns. Being able to apply the same system of bullet pattern definitions for every ‘actor’ in the game is quite convenient.
(Update: 30 June 2015) BulletMLX is now on GitHub.
We extend BulletML for our game with a backwards-compatible DTD which we will release, along with related tools, for any game developers to use as free software. Some of the additions we implemented:
<playSound/>node for use in actions.
Attributes to affect bullets and actions based on the game’s difficulty setting. We have five difficulty settings at the moment, in this order: Love, Easy, Normal, Hard, Hate.
Size and shape properties for bullets. These affect bullets that we render using the primitive graphics functions of the LÖVE engine.
Support for using images for bullets. This is in contrast to the properties above, because for graphically fancy patterns we want to be able to use image files.
Shaders for any type of bullet.
I feel like some of these should have been part of BulletML from the beginning, such as controlling size and shape. For example, our
<shape/> tag allows us to create bullets that are circles, ovals, straight-line lasers, and so forth.
If you are developing a shmup then consider using BulletML to define the shots in your game. It has proven to be a flexible and useful system for us. And while the XML format may not be the most loved in the world it works well in terms of organization and creating a ‘library’ of patterns. The official site has a Java implementation and an applet that shows what you can do with BulletML. When our game is complete we will release our bullet engine for LÖVE with its support for our BulletMLX extension, for free.
In the mean time check out BulletML. Just messing around with patterns in the applet is fun.