Build an Endless Runner Game from Scratch: Obstacles and Enemies

Welcome to the sixth part in our Endless Runner tutorial series! Our game is starting to shape up and feel more polished. After completing today's steps, it will be much more interactive and fun to play. We will add two more events that will create some exciting new challenges for the players. First, we'll add the ability for our hero to fire a small bolt to clear obstacles that come toward him. Keep in mind that the little "blueish" image is being fired from our monster. The images we're working with are not especially professional-looking since they are just for practice. After the monster has the ability to fire some bolts, we will also add events which will send obstacles coming back toward him. After that, we'll create two types of obstacles: the first is a spike wall that will sit on the ground and travel at the same speed as the ground, and the second is a ghost that will fly in from the upper right side of the screen toward the player.

So, let's get started! The first thing that we need to do is to make sure we have all of the assets in the right place. Download the file attached to this tutorial, and in the "new" folder you will find three new assets. You can also just right-click on the images and save them in the correct folder. The images should be named spikeBlock.png, ghost.png, and blast.png.

Open up your main.lua file that can be found in the "old" folder of the tutorial downloads. We will start by giving our players the ability to fire because we don't want to leave them defenseless as they are bombarded with new challenges! We can add this ability in three steps. The first will be instantiating 5 bolts and putting them in a group. Rather than creating and destroying objects every time we want to use them, we can be more efficient by preparing them and storing them off-screen until we need to use them. We are actually going to be doing the same thing for each of the three different images, so go ahead and add this code in between where we declare the variable speed and where we create our blocks.

Notice that they all have some common features. We need to go through and name them in case we ever want to reference them individually. We give them an id, also giving us more future reference options. We give them their offscreen x and y coordinates (we stack similar images on top of each other). Another thing we give them all is the variable 'alive'. This is set to false by default as they will be sitting off the screen. Giving the sprites this variable will allow us to quickly check whether the sprite is in use or not. The only sprite that has anything different is the ghost sprite. For ghost sprites we'll add a speed variable so that we can have ghosts moving at random speeds. We'll also set the alpha of the ghosts to .5 so that they appear more, shall we say, ghostlike!

The next two things that we need to do are to create their respective display groups, then add those groups to the screen display group so that we will be able to see them in the game. Add these right beneath the other display groups' instantiation.

Next, go down to the section where we add everything to screen. Add those display groups in with the rest. I would make the new order look something like this:

Once you have everything in there, it should look something like this if you were to run it in the iPhone 4 perspective:

After getting that in place, we'll add the function that updates all of the bolts that our monster shoots. Add the following function beneath the checkCollisions() function.

The above function is going to have two main responsibilities. The first is to update the position of the blast and check to see if it collided with anything. You can see that when it collides with something, the way we destroy it is to simply move it off-screen and set isAlive to false. This will get the bolt ready to be used again. Something else that you might have noticed is that we only instantiate five bolts. So, what happens if all five bolts are already in play and the user tries to fire another blast? Nothing! With the way it is set up right now, the user is limited to only having five active blasts at one time. This is easy to change by instantiating more at the beginning of the game, but it shows you how to set limits to players. This is also a method we will use to make sure that 50 ghosts don't randomly generate all at once on the screen, instantly killing the player.

Next we need to go down to the touched function to give the player the ability to shoot. Change the touched function to match the following:

Lastly, be sure to add updateBlasts() to the main update function and you should be ready to go. Give that a try and see the awesome power that our monster has now! After running it you should see something like this:

Now that the players can defend themselves, let's go ahead and give them some challenges. Both of these next events will be overcome by simply shooting them once. After they are in place, however, it will be easy for you to change them to suit your own project. We will start with the spiked wall.

The spiked wall will simply be placed on top of the current ground and move at the same constant speed as the ground around it. First thing to do is add the updateSpikes function. Right below the updateBlasts() function add the following code:

This will do the same thing as our updateBlast function. It will simply update the position of the spiked wall and check to see if it went off the screen (which it currently can't do because it would hit the player first). Just in case, though, we'll check to make sure. The last thing we need to do is make an event for it. In checkEvent() below the other checks add this:

We are going to actually add our wall in the updateBlocks() function. That way we are sure to have the current groundLevel. Right before you call checkEvent() insert the following:

The last thing to do in order to get this up and running is add the collision detection to see if our player ran into it or not. Put this right below the section in checkCollisions() where we check the collisions between the blocks and the monster.

Be sure to add updateSpikes() to the main update function again and give it a run! You should now have these spikes in your monster's path.

Give that a whirl and practice shooting them down. Remember to test to make sure the collisions are working correctly with the blasts. Also make sure that running into the walls actually kills the player. Once you have tested that and are ready for more, start putting the code in place for the ghost.

Putting the ghost in is pretty much identical to putting the wall in. The biggest difference between the two is that for the ghost we are going to randomize where it comes in at as well as how fast it travels. We'll also make the ghosts move up and down so that they are always moving to where the user is. Special details like that will make the obstacles feel entirely different to the user, even though they work in such a similar way.

Let's start again by adding the updateGhosts() function. While you're at it, go ahead and add updateGhosts() to the main update function as well.

Next go back into the checkEvent() function and add this below the previous checks:

This time instead of getting the ghosts moving from the updateBlocks function, we will do it in the runEvent() function. Add this below the other if statements:

Once that is in there we need to check for collisions between the monster and the ghosts. Add this to checkCollions() right after we do the work for the spiked walls:

You should now have everything in place, including the ghosts to dodge!

The game should now be a lot more fun and challenging for users. In the next tutorial we will add two more things that will make our game feel more complete: (1) a scoring system, and (2) monster death! We covered a lot in this tutorial, so if you have any questions, please sound off in the comments below. Thanks for reading!

Tags:

Comments

Related Articles