Today was the finale of this years Global Game Jam. If you don’t know such types of events yet, basically one has 48 hours to complete a game for a given theme, either alone or as a team. The beauty of Global Game Jam (compared to the also cool Ludum Dare) is, it’s at predefined locations so you meet with people in person. This year I went again to SRH and it was a real blast.
We were a team of four and did some sort of reverse theme fitting: we all thought of what type of game we would like to do and then see how to bring the theme into it. We decided on a combination of a vertical scrolling bullet hell shooter in a steampunk setting.
As I love bullet hell games, I started with the bullet hell designer and want to share some thoughts on that. The beauty about bullet hell is in my opinion the awesome patterns they can create, depending on how many bullets are spawned and in which direction they are shot with which speed. Coding this manually seemed like the wrong approach so I started working on a tiny DSL to describe the patterns. There are three main parameters:
- Spawn Pattern
- Rotation Pattern
- Speed (could also be a pattern, but I decided on an constant for simplicity)
Here some examples of the final version:
|Simple Gun with three shots a time||Spawn: 600,x,50,x,50,x|
|360° Tesla||Rotation: 1,5 |
|Spraying Machine/Gatlin Gun||Rotation: 30,1,loop 1,50,1000,delay,2,-1,loop 1,50|
Behind the scenes
So what is described there? Values are always to be read in tuples. The first value is a time in milliseconds after which something should happen. In case of a rotation that is the degrees of the Y-axis. When spawning it is the trigger to instantiate a bullet (simply an x but could be anything, e.g. to define specific types of bullets to spawn).
There are 3 special constructs: loop, delay and sync.
Even though the whole pattern is repeated once it finishes, it often times becomes necessary to do one or multiple loops in-between. Loop will have a parameter in the first value for how many tuples (that occurred before) should be repeated. The second value of the loop is the number of loops that should be done. The Gatling gun will for example rotate 1 degree every 30 ms 50 times in the example above. Then it will wait for 1 second and then do a fast sweep back 1 degree every 2 ms 50 times. In case the next rotation pattern should only start once the complete spawning pattern has finished, “0, sync” can be used.
To work with these patterns I created a PatternParser (for some usage examples see the tests) that offers high-level methods to query for the current action, the time when the next step is due and a command to advance the pattern one step forward.
Once the logic was done I added a way to set which type of bullet prefab to spawn and a hit prefab if these bullets hit something. This is what we ended up with in the end in the final game:
If you think this could be useful, feel free to use the code and extend it. It would be awesome to see what great ideas others can come up with!