How to make a PICO-8 game: Part 7

Outnumbered

If you remember (it was before Christmas, so I realise you might not), the last thing we did on our game was make it harder. This was done by making the enemy speed up, but there’s another way – why not spawn more enemies?

Part 7: Spawning

Up until now, we’ve referred to the enemy’s position variables as ex and ey, and used the variables d and dinc to determine their speed and how much they speed up by. If we decide to add a second enemy, we can use more varables – ex2, ey2, d2 and dinc2 perhaps. And for a third enemy, ex3 and ey3 and so on. Simple, yes?

Well yes, but terribly inefficient. Not least because we need the associated code to alter them too. What if, instead, we can just say “make an enemy with these attributes” as many times as we like, and then say “just update all the enemies and draw them on the screen please and thanks”? That’d be like magic, right?

Magic in the form of an enemy object. In PICO-8, objects take the form of specially constructed tables, with keys and values. For example, we can create an “empty” enemy called “en” like this:

and then give it some attributes as key/value pairs:

and so on.

Then, we can be clever and create lots of these and put them all in another table, called “enemies”. We can then perform tasks on all the enemies in the enemies table in one go!

Let’s start with a function to make enemies and add them to the enemies table.

Firstly, initialise the enemies table at the end of the _init function:

and add this function to the end of our code:

To create an enemy we call the make_enemy() function, sending it the variables for sprite number, x and y coordinates, d (“speed” of the enemy), how many “animation ticks” there are currently, and how many animation ticks there are in total. en.frame is also added in the function to give the starting animation frame modifier. I’ll explain the animation stuff later.

In PICO-8, these objects can also have functions inside them. This is handy if we want to, say, draw all our enemies – we can just call each enemy’s draw function.

Before the “add” command in the make_enemy function, add this:

The “this” in this function refers to “what you pass to the function”, which is the object en. So this.x means en.x, and this.y means en.y. Got it?

We can call this function, for all enemies, with just one line of code, which we put in the _draw() function:

Which literally means “for each item in the enemies table, trigger that item’s draw function”.

And that’s enough for today. However, we need to do some code tidying as a lot of bits are no longer needed now we’ve turned enemies into objects! The stuff in _init() about ex and ey, can go, as can d. In the _draw() function, we don’t need the single-enemy spr code any more either.

At this point, our code is actually broken as there are still references to the old way of dealing with enemies (collisions and moving them in particular), but don’t worry – we’ll fix that next time!

Our code so far, broken and all:

 

Leave a Reply