Build a Classic Snake Game in AS3

In this tutorial I would like to show you how easy it is to create a classic "Snake" game in Flash. I will try to explain everything easily, step by step, so that you can develop the game further to your needs! The Game will be developed in AS3 and I will use the FlashDevelop IDE.


Introduction

The game won't be complex. Whenever we hit a wall, it will restart the game. After eating an apple the snake will grow, and a 'new' Apple will appear. (Actually, it will be the same apple, but I'll explain this later.)

One of the most important aspects of the game is the code's reaction to KEY_DOWN events. The snake will only then change its direction after a tick has passed, not immediately after a keypress. This means that, if the snake is going right, and you press down and left very fast, the snake will go down, not down AND left. Without this 'feature' the snake would allow us to go left while we are going right, which would mean it hit itself.


Let's Look at the Game Already!

Let's take a look at the final result we will be working towards:


Step 1: Creating the Project

In FlashDevelop, create a new Project, and inside the 'src' folder create a 'com' folder. In the 'com' folder create a new class, and call it 'Element.as'.

Set the dimensions of the project to 600x600px.

The FlashDevelop project structure

Step 2: Wait... What's an Element?

The snake is make up of blue squares, which I call elements. We will create an Element Class, which draws the element. The red apple is going to be an element too, so we will extend the code with a few more lines.

Therefore we won't create a new class for the apple. (But if you really want to, you can.)


Step 3: Writing the Element Class

The Element class creates a square. It doesn't draw it on the stage, it just creates it. The registration point of the element - the position referred to by its x- and y-coordinates - is in the top-left.

After opening the Element.as you will see something like this:

First we need this to extend the Shape class, so we can use the graphics object to draw the square. After this, create two variables: one for the direction (if it's part of the snake), and one for the score value (if it's an apple), and then change the parameters of the constructor function:

Now fill the function with some code:

Now, whenever we create an element, it will draw a rectangle and set the score value of the element to 0 by default. (It won't put the rectangle on stage, it just draws it within itself. Notice that we have not called the addChild() function.)

Let's finish this class and then we can finally test how much we have done already:

We created four functions to change the directions and the value of the apple. We achieved this by using setters and getters. More about Setters/Getters in this article!


Step 4: Testing the Element Class

Open Main.as now.

Import the com.Element class and create an Element in the init() function:

First we create the testElement variable which holds our element. We create a new Element and assign that to our testElement variable. Note the arguments we passed: first we give it a color, then the alpha, width and height. If you look in the Element class's Element function, you can see how it uses this data to draw the rectangle.

After creating the Element, we position it and put it on the stage!


Step 5: Setting Up the Variables

Look at the following code. I wrote the functions of the variables next to them (notice that we imported the necessary classes too):

The most important variable is the snake_vector. We will put every Element of the snake in this Vector.

Then there is the markers_vector. We will use markers to set the direction of the snake's parts. Each object in this Vector will have a position and a type. The type will tell us whether the snake should go right, left, up, or down after 'hitting' the object. (They won't collide, only the position of the markers and the snake's parts will be checked.)

As an example, if we press DOWN, an object will be created. The x and y of this object will be the snake's head's x and y coordinates, and the type will be "Down". Whenever the position of one of the snake's Elements is the same as this object's, the snakes elements direction will be set to "Down".

Please read the comments next to the variables to understand what the other variables do!


Step 6: Writing the attachElement() Function

The attachElement() function will take four parameters: the new snake element, the x and y coordinates, and the direction of the last part of the snake.

Before we put the element on the stage we should position it. But for this we need the direction of the snake's last element, to know whether the new element has to be above, under, or next to this.

After checking the direction and setting the position, we can add it to the stage.

Now we can use this function in the init() function:

We create the first 10 Elements, and set the direction of them to 'R' (right). If it is the first element, we call attachElement() and we change its alpha a bit (so the "head" is a slightly lighter color).

If you wish to set the position somewhere else, then please keep the following in mind: the snake has to be placed on a grid, otherwise it would look bad and would not work. If you wish to change the x and y position you can do it the following way:

Setting the x position: (snake_vector[0].width+space_value)*[UINT], where you should replace [UINT] with a positive integer.

Setting the y position: (snake_vector[0].height+space_value)*[UINT], where you should replace [UINT] with a positive integer.

Let's change it to this:

And the snake's first element is set onto the 20th space in the x-grid and 10th space in the y-grid.

This is what we've got so far:


Step 7: Writing the placeApple() Function

This function does the following:

  1. It checks whether the apple was caught. For this we will use the caught parameter, and set its default value to true, in case we don't pass any value as parameters in the future. If it was caught, it adds 10 to the apple's score value (so the next apple is worth more).
  2. After this the apple has to be repositioned (we don't create new apples) at a random grid position.
  3. If it is placed on the snake, we should place it somewhere else.
  4. If it is not on the stage yet, we place it there.

There will be some math here, but if you think it through you should understand why it is so. Just draw it out on some paper if necessary.

  • boundsX will hold how many elements could be drawn in one row.
  • randomX takes this boundsX, multiplies it with a Number between zero and one, and floors it. If boundsX is 12 and the random Number is 0.356, then floor(12*0.356) is 4, so the apple will be placed on the 4th spot on the x-grid.
  • boundsY will hold how many elements can be drawn in one column.
  • randomY takes this boundsY, multiplies it with a Number between zero and one, and floors it.
  • Then we set the x and y position to these numbers.

In the for loop, we check whether the apple's new x and y positions are identical to any of the snake_vectors elements. If so, we call the placeApple() function again (recursive function), and set the parameter of it to false. (Meaning that the apple was not caught, we just need to reposition it)

(apple.stage) returns true if the apple is on the stage. we use the '!' operator to invert that value, so if it is NOT on the stage, we place it there.

The last thing we need to do is call the placeApple() function at the end of the init() function.

Notice that we pass false as the parameter. It's logical, because we didn't catch the apple in the init() function yet. We will only catch it in the moveIt() function.

Now there are only three more functions to write: the directionChanged(), moveIt() and the gameOver() functions.


Step 8: Starting the moveIt() Function

The moveIt() function is responsible for all of the movement. This function will check the boundaries and check whether there is an object at the x and y position of the snake's head. It will also look for the apple at this position.

For all of this, we will use our timer variable.

Add two more lines in the end of the init() function:

Look at the comments in the sourcecode, to see which block of code does what.

Now we need to code the movement. For this we jump into the switch block, which will run on every snake part, because of the for loop.

First we need to check the direction of the current element.

When the direction of the part is set to "R", for instance, we need to add something to its current X position (the space_value plus the width of the snake part).

With this in mind, we can fill it out:

After testing the code, you should see that the snake is moving, and going off the stage and never stops. (You may need to refresh the page - or just click here to load it in a new window.)

So we need to stop the snake


Step 9: Writing the gameOver() Function

This function is going to be the shortest. We just clear the stage and restart it:

That's it. We set the dead variable to true, stop the movement with the timer, remove every child of the class and call the init() function, like we just started the game.

Now, let's get back to the moveIt() function.


Step 10: Continuing the moveIt() Function

We will use the gameOver() function in two places. The first is when we check if the head is out of bounds, and the second is when the snake hits itself:

This is the code we have now:


Step 11: The directionChanged() Function

We want to listen to the keyboard, so we can actually control the snake. For this we need to put some code into the init() function and the gameOver() function.

Put this at the end of the init() function (setting up the listener function):

And this at the end of the gameOver() function:

Now create a new function:

What goes into the if block?

  • The direction of the head should be rewritten.
  • The marker object has to be set correctly.
  • The last_button variable should be set to the last button pressed.

Repeat this three more times, and we will have this:

We need one more thing to test it. In the moveIt() function we have something like this:

Here we need another for loop, to check every snake's part against every marker on the stage, and check whether they collide. If they do, we need to set the snake's part's direction to the marker's type. If it's the last snake part which collides with the marker, we need to remove the marker from the markers_vector, too, so the snake parts don't collide with it any more.

Now if you play with it it looks okay, but there is a bug in there. Remember what i said at the beginning of the tutorial?

For instance, if the snake is going to the right and you press the down-left combo very fast, it will hit itself and restart the game.

How do we correct this? Well it's easy. We have our flag variable, and we will use that for this. We will only be able to change the directions of the snake when this is set to true (Default is false, check the init() function for that).

So we need to change the directionChanged() function a little. The if blocks' heads should be changed: add a && flag clause at the end of every 'if'.

If you test it now, it won't work because the flag is always false.

When do we need to set it to true then?

After a move/tick we can allow the users to change directions, we just don't want to change it twice in one tick. So put this at the very end of the moveIt() function:

Now test it, and there is no bug any more.


Step 12: Finishing the Game

Now the only thing we need to do is the 'apple-check'

Remember this at the very beginning of the moveIt() function?

This is what we need to do in there:

  • Call the placeApple() function. (We don't set the parameter to false; we leave it as it is. The default is true.)
  • Show the current score
  • Attach a new element to the snake's last part.

Now everything should work fine. Try it out:

Here is the whole Main class again:


Step 13: Summing It All Up

Congratulations! You have just created a nice game. Now you can develop it further, and create a super apple or something. For that I recommend using another function called placeSuperApple() and a new class named SuperApple. Whenever you catch a super apple, the snakes parts could lengthen by three elements, perhaps. This could be set with setters/getters in the SuperApple class.

If you wish to do this, and you get stuck somewhere, just leave me a comment here.

Thank you for your time!

Tags:

Comments

Related Articles