Skip to main content

How To Kill

Three steps in and we're already onto the fun stuff - adding bullet spawners. In this post I'll add an object to represent a bullet spawner, give it a bunch of configuration parameters, and then place a couple of them on the playfield.


Bullet spawners are usually pretty simple objects - they just spawn a number of bullets at regular intervals. What makes them interesting is the configuration parameters that can be used to create intricate patterns of bullet hell. You only really need a handful of simple parameters before you can start to create complex patterns, so it might surprise you to see how little code is required.

Let's first talk about how I want my spawner to act, then I'll dive into how I make that happen

The Ideal Spawner

Having already written a few spawners before now, I realise that my ideal spawner stays in one place, fires salvos of bullets in an evenly spaced arc and rotates after every salvo. Each salvo should fire one or more times. The spawner should also be able to reverse its rotation direction every so often. So what sort of configuration parameters do I need for that?
  • Firing
    • Each salvo to fire in an arc from between 0 and 360 degrees, with any number of bullets evenly spaced across that arc
    • Each salvo made up of n discrete firings
  • Direction
    • An initial direction
    • Amount to rotate after every salvo
    • Optionally reverse direction every n salvos
  • Timing
    • An initial delay before the shooting starts
    • Delay between each salvo
    • Delay between each firing in the salvo
This all fits neatly into a small configuration structure:



This is just one type of spawner, with one type of bullet. Over time I'll add different bullet types (homing, lasers, more..) and different spawners (maybe even ones that move), but for now let's get the basics down.

How It Works

The spawner is defined as an object:


The constructor is simple - it just remembers the config and set a few initial parameters. All of the important code goes into the update() function. I use a number of counters and timers to track the state of the spawner (waiting to fire a salvo, delay between salves, etc.).

The code starting at line 25 is what fires the bullets. The bullets are spread out across an arc, so if you have three bullets and a 90% arc then you will see one fired at -45degrees, one at 0 and one at +45. The maths for this is to fire bullet n at (n / (spreadCount -1) * spreadAngle - (spreadAngle / 2))

This works nicely, but there are a couple of special cases that need dealing with. The first case is where there is only one bullet - here its pretty obvious that the bullet should actually fire from the middle of the arc, or 0 degrees, however wide the arc is. The second case is when the arc is set to 360 degrees, ie: a complete circle. If we use the normal "spread bullets evenly across the arc" code then you will actually only see n-1 bullets. Think about it - if you fire four bullets in a 360 degrees arc you get one at -180, one at +180 and two in-between. -180 and +180 are actually the same direction, so it will only look like you have three bullets. To fix this I just use a spread count that is one bigger than normal - then the rest of the maths works out fine. This is what the code at line 31 does.

Apologies if this function is a bit complex. I tried writing it as a state machine instead but it was even harder to follow. You don't really need to understand how it works to get the most out of it, so don't worry if you don't get it to start with.

Now it's just a simple case of creating a couple of spawner objects in the init() function and adding them to the objects list:


Wrapping Up

I talked about what a spawner is, and how they work. Then I defined a simple bullet spawner, made it into an object and added a couple of these to the playfield.

The code for this step is here, and the playable online version is here. Why not grab the code and start playing around with the configuration parameters for the spawners yourself?

Next?

I really want to add collision next, but before I do that I'm going to need to take a detour into an object manager. This will let me put different object types into their own groups, and that will make it really easy to, say, collide the player against just the bullets.

Once collision is done I'm not sure what I'll go on to next. Feel free to leave suggestions and requests in the comments ;)

Comments

Popular posts from this blog

Set The Controls For The Heart Of The Sun

When we last met, I had just started work on a level editor. I'd got as far as adding the ability to select an object and move it around, and then I added an undo/redo system using the command pattern. That was a good start, but dragging items around the level is only fun for so long. What I really want to be doing is.. ..editing the properties of the bullet spawners! And I want to be doing this in realtime as the game plays so that I can immediately see what effect my changes have made to the gameplay of the level.

World In Motion

In the last post I touched on how easy it is to score in this game - you can just camp out on the score bullet spawner and watch the points rack up. I'm going to add a little delay to the score bullets so that they start out in a deactivated and uncollectable state, and then change to active and collectable after a short time - say, half a second. To make it clear what state they are in I'm going to add code to let me change the look of Objects and allow them to be animated.

The Long And Winding Road

I started this blog back in November of last year. My aim was to document the development of a Bullet Hell shoot-em-up, written in JavaScript. Here we are, six months later, and lots has happened. With 20 posts already written, I thought that now would be a good time to take stock of what I've already done, and to look to the future and see what's to come.