Flash Tutorial Links:
Play Games: HTML5 Tutorials:

Snake Game Tutorial

There really aren't many other games where you play as the snake. Imagine, a Snake, the good guy!

History of Snake

Snake originated from the arcades as Blockade in the 1970s, but it found massive fame only after NOKIA made it a preloaded game on its phones in 1998. Players control a snake that grows longer as it eats, and you need to take care while navigating the snake's head by avoiding its own body and the walls.

Download the Game Files

The files you need to create this game can be downloaded from here.

Part 1

import flash.display.*;
import flash.events.*;
import flash.ui.*;

public class Snake extends MovieClip
{
    private var score, life, framesElapsed:Number;
    private var p1speedX, p1speedY:Number;
    private var spacePressed, readyToMove, gotoWin, gotoLose:Boolean;
    private var left,right,up,down:Boolean;
    private var snakes:Array;
    private var mcFood:Food;

The 3 standard packages are imported. You will almost always need display and events. As for ui, it'll be useful to import it in too.

The following variables will be used for the game. score keeps track of the score for the player. life keeps track of the number of attempts the player has, and framesElapsed is an artificial mechanism to update the position of the snake in half time, i.e. make the snake move slower. Since the game is running at 30fps, if we update the movement of the snake every once per fps, the snake may move too fast to handle.

p1speedX indicates the snake's current speed in the horizontal direction. A value of -1 will mean that the snake should be travelling to the left, while a value of 1 will mean that the snake should be travelling to the right. p1speedY, likewise, keeps track of the speed in the vertical; A value of 1 means the snake is moving down, and -1 means moving up.

spacePressed and readyToMove are used to track if the player hits the SPACEBAR so as to start the game.

gotoWin and gotoLose are standard boolean variables you'll see throughout the tutorials. Once they are set to true, the game jumps to the respective Win or Lose frames.

left indicates the player's intention to move horizontally. It will be set to true when the player hits the "A" key. Likewise for right, up and down for the respective keys.

The array snakes will contain all the body parts of the snake, and mcFood is the variable to point to the current Food object that spawns.

Part 2

    //All Start Functions
    public function startMenu()
    {
        stop();
        btnStartGame.addEventListener(MouseEvent.CLICK, gotoStartGame);
        btnHowToPlay.addEventListener(MouseEvent.CLICK, gotoHowToPlay);
    }
    
    public function startHowToPlay()
    {
        btnBack.addEventListener(MouseEvent.CLICK, gotoMenu);
    }
    
    public function startWin()
    {
        btnBack.addEventListener(MouseEvent.CLICK, gotoMenu);
    }
    
    public function startLose()
    {
        btnBack.addEventListener(MouseEvent.CLICK, gotoMenu);
    }

Take a look at the ActionScript embedded in the different frames in the FLA file. You will see that in the menu labelled frame, it has a single function call to startMenu. Likewise, the win labelled frame will call startWin.

All the functions here handle those calls. We often refrain from writing codes in the FLA file so that everything can be seen in the AS file, and it helps tremendously in debugging your codes.

Basically, the function calls here only set up the codes for the buttons in that frame to make them function.

Part 3

    public function startGame()
    {			
        score = 0;
        life = 3;
        framesElapsed = 0;
        p1speedX = 1; //snake starts moving right
        p1speedY = 0;
        up = false;
        down = false;
        left = false;
        right = false;
        spacePressed = false;
        readyToMove = false;
        gotoWin = false;
        gotoLose = false;
        snakes = new Array();
        
        //Create 1st body part of snake and push it into the array
        var snakeHead = new SnakePart();
        snakeHead.x = 400;
        snakeHead.y = 300;
        snakes.push(snakeHead);
        addChild(snakeHead);
        
        addEventListener(Event.ENTER_FRAME,update);
        stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownHandler);
        stage.addEventListener(KeyboardEvent.KEY_UP,keyUpHandler);
        

        stage.focus = this;
    }

startGame is called in the frame labelled game.

This will be the heaviest start-kind-of-function as you can see. Basically, the role of this function is to kick start all the necessary variables and states in the game. You can see that we set the score to 0, because, well, at the start of the game, the player should start with 0 score.

I decided to make the snake start moving to the right, hence I used a p1speedX of a value 1. If you decide to make it move in other directions, do experiment with having p1speedX as -1, or p1speedY as 1 or -1. However, do note that either one of the variables should be 0, otherwise your snake will be moving diagonally.

snakes is instantiated to an empty array right at the start. Immediately after, we create a new SnakePart (refer to the library in the FLA, it is basically a black square that will be used to denote the snake's body as well as its head). snakeHead is the temporary variable to hold this SnakePart, and we create it at a position of (400,300). We push it into the snakes array, hence the very first element of the snakes array is always the head of the snake. Remember to call the addChild function, otherwise you will not see it visible.

The game loop is created in the game by adding an event listener that listens to the ENTER_FRAME event. So, if you set the fps of the game to 30, this update function will run 30 times a second (assuming the computer is able to handle the complexity of each game loop).

What "stage.focus = this" does is to set the focus back into the game. When you clicked on a button to get from the Menu frame into the game, the focus is actually given to the button. Hence, if the game is played using the keys on the keyboard, they will not work unless you click on the game screen again to give it focus. You can try commenting this off to see what I mean.

Part 4

    //All Goto Functions
    private function gotoStartGame(evt:MouseEvent)
    {
        btnStartGame.removeEventListener(MouseEvent.CLICK, gotoStartGame);
        btnHowToPlay.removeEventListener(MouseEvent.CLICK, gotoHowToPlay);
        gotoAndStop("game");
    }
    
    private function gotoHowToPlay(evt:MouseEvent)
    {
        btnStartGame.removeEventListener(MouseEvent.CLICK, gotoStartGame);
        btnHowToPlay.removeEventListener(MouseEvent.CLICK, gotoHowToPlay);
        gotoAndStop("howtoplay");
    }
    
    private function gotoMenu(evt:MouseEvent)
    {
        btnBack.removeEventListener(MouseEvent.CLICK, gotoMenu);
        gotoAndStop("menu");
    }

These functions handle the interaction when the player clicks on the buttons in the menu, how to play section, etc.

Before it jumps to the right frame, it removes the event listener from the button first. This is just good programming practice.

Part 5

    private function keyDownHandler(evt:KeyboardEvent)
    {
        if (evt.keyCode == Keyboard.A) 
        {
            //1st Player Left Key
            left = true;
        }
        else if (evt.keyCode == Keyboard.D)
        {
            //1st Player Right Key
            right = true;
        }
        
        if (evt.keyCode == Keyboard.W) 
        {
            //1st Player Up Key
            up = true;
        }
        else if (evt.keyCode == Keyboard.S)
        {
            //1st Player Down Key
            down = true;
        }
        
        if (evt.keyCode == Keyboard.SPACE) 
        {
            spacePressed = true;
        }
    }
    
    private function keyUpHandler(evt:KeyboardEvent)
    {
        if (evt.keyCode == Keyboard.A)
        {
            left = false;
        }
        else if (evt.keyCode == Keyboard.D)
        {
            right = false;
        }
        else if (evt.keyCode == Keyboard.W)
        {
            up = false;
        }
        else if (evt.keyCode == Keyboard.S)
        {
            down = false;
        }
        
        if (evt.keyCode == Keyboard.SPACE) 
        {
            spacePressed = false;
        }
    }

The keys A and D are used to move the player left and right. I avoid using the actual Left and Right keys because sometimes, browsers do not trap the keys very well and they ended up moving the scroll bars of the browsers instead. Likewise, W and S are used for moving up and down.

You should also notice that I did not move the player directly inside the key down handler function. Instead, I just set the player's intention, which is denoted by the variable up, down, left or right to true.

This is important because all actual game changing codes like moving the player will be better placed inside the game loop itself (i.e. the update function). In future when we want to implement a pause function to the game, this coding practice will make our lives much easier too.

Part 6

    public function update(evt:Event)
    {
        handleUserInput();
        handleGameLogic();
        handleDraw();
        
        if (gotoWin)
            triggerGoToWin();
        else if (gotoLose)
            triggerGoToLose();
    }

This is how the game loop will look like. I've further broken down what the game loop should be doing by creating 3 other functions.

handleUserInput will take care of the player's inputs, be it mouse, or keyboard.

handleGameLogic will almost always be the biggest function. It handles everything from updating the player's movements, bullets' movements if any, to even more fanciful stuff like calculating advanced enemy AI.

handleDraw does little, but it is important in presenting the game states to the player by updating the UI. For example, if the player gains score, the Score textfield will be updated here to reflect the correct score.

After these 3 functions have executed, the gotoLose variable is checked to see if it is true. If so, the triggerGoToLose function will be called, and the game will end thereafter.

Part 7

   private function handleUserInput()
    {
        //Handle player 1 position
        
        //if player wants to move left but snake is not
        //already moving right
        if (left && (p1speedX != 1)) 
        {
            p1speedX = -1;
            p1speedY = 0;
        }
        //if player wants to move right but snake is not
        //already moving left
        else if (right && (p1speedX != -1 ))
        {
            p1speedX = 1;
            p1speedY = 0;
        }
        //if player wants to move up but snake is not
        //already moving down
        else if (up && (p1speedY != 1))
        {
            p1speedY = -1;
            p1speedX = 0;
        }
        else if (down && (p1speedY != -1))
        {
            p1speedY = 1;
            p1speedX = 0;
        }
        
        if (spacePressed)
            readyToMove = true;
    }

The handleUserInput function will take care of the user's interactions with the game.

Before we assign the snake to move in any particular direction just by examining whether up, down, left or right is true, we need to check if the player's intention IS a valid movement. In this case, we use (left && (p1speedX != 1) because if the snake is moving right (indicated by p1speedX == 1), then we should not allow the snake to change direction and move left. It would crash into its own body!

If it is a valid move, we will happily set p1speedX or p1speedY to its respective value. Otherwise, nothing will happen.

Part 8

    private function handleGameLogic()
    {
        if (!readyToMove)
            return;  

        framesElapsed++;
        
        //Update the new position of the snake's head
        if (framesElapsed % 2 == 0)
        {
            //Update motion of the snake's body
            for (var i = snakes.length - 1; i >= 1; i--)
            {
                snakes[i].x = snakes[i-1].x;
                snakes[i].y = snakes[i-1].y;
            }
        
            if (p1speedX > 0)
            {
                snakes[0].x += 20;
            }
            else if (p1speedX < 0)
            {
                snakes[0].x -= 20;
            }
            else if (p1speedY > 0)
            {
                snakes[0].y += 20;
            }
            else if (p1speedY < 0)
            {
                snakes[0].y -= 20;
            }
            
            //Check for collisions between the snake and its own body
            for (var i = snakes.length - 1; i >= 1; i--)
            {
                if ((snakes[0].x == snakes[i].x) &&
                    (snakes[0].y == snakes[i].y))
                {
                    collided();
                    break;
                }
            }
        }
        
        //Check for collisions between the snake and the walls
        if (snakes[0].y < 0)
        {
            collided();
        }
        else if (snakes[0].x > 800)
        {
            collided();
        }
        else if (snakes[0].x < 0)
        {
            collided();
        }
        else if (snakes[0].y > 600)
        {
            collided();
        }
        
        //Add new food items
        if (mcFood == null)
        {
            //Create a new food item
            mcFood = new Food();
            mcFood.x = Math.random() * 700 + 50;
            mcFood.y = Math.random() * 500 + 50;
            addChild(mcFood);
        }
        
        //Check for collisions between food item and Snake
        if (mcFood != null)
        {
            if (snakes[0].hitTestObject(mcFood))
            {
                //Add score
                score += 100;
                if (score >= 5000)
                    gotoWin = true;
                
                removeChild(mcFood);
                mcFood = null;
                
                //Add a body
                var newPart = new SnakePart();
                newPart.x = snakes[snakes.length-1].x;
                newPart.y = snakes[snakes.length-1].y;
                snakes.push(newPart);
                addChild(newPart);
            }
        }
    }

The handleGameLogic will handle how the game moves the snake and updates the position of all its body parts along with it, as well as create the food at a random position.

The first line of code acts as a pause for the game. If the variable readyToMove is false, return is called, and nothing within handleGameLogic will continue to run. But if the spacebar is pressed, readyToMove will be set to true, and the game continues.

 

We will only do the following code once every 2 frames (by using framesElapsed % 2 == 0) so as to slow the speed of the snake. framesElapsed is that artificial mechanism to ensure that.

Take note that the sequence of codes here is very important. We need to update the motion of the snake's body FIRST before moving the snake head, otherwise the snake will keep dying as you move the body parts onto its head. Anyway, the trick here is to form this for loop that loops from the last element of the snakes array (which is the last body part) to the 2nd body part (i.e. the first body part after the snake's head). As we loop through these elements, we move each current body part onto the position of the body part in front of it. So, as we reach the end of the for loop, the 2nd body part will be at the snake head's position.

Thereafter, we update the snake's head according to what p1speedX or p1speedY is.

At this point in time, the snake head and the rest of its body parts would have been where they should be. We can now safely check for collisions between the snake and its own body.

To do that, we need not use the hitTest functions because the movieclips are too close together. Instead, since the body parts move in discrete amounts, we can safely compare the exact position of each body part with the head only. For a collision to occur, it can only occur between each body part and the head, since no two body parts can hit each other.

If a collision is detected, we execute the collided function.

To check for colliisions with the side walls, we simply check for the snake head's position with respect to the top wall (y < 0), left wall (x < 0), right wall (x > 800) and the bottom wall (y>600).

To create new food items, we check if it is currently missing from the stage Whenever the snake eats it, the food object is removed and set to null, hence to check if it is missing from stage, we simply check if the variable mcFood is null.

This portion of code will always execute when the food is eaten, and it will be created at a random x and y position.

We will then check if the snake head has hit the food; A hit here means the snake eats it up. If that happens, we add 100 to the player's score, check if he has won (winning is set to 5000 points in this tutorial), and remember to remove the mcFood object.

We will also increase the length of the snake by creating a new SnakePart, putting it at the position of the current last body part, and pushing it into the array. When the snake next moves, the body parts will sort themselves out into place according to our codes above.

Part 9

    private function handleDraw()
    {
        //Handle display
        if (!readyToMove)
            txtHitSpaceBar.visible = true;
        else
            txtHitSpaceBar.visible = false;
            
        txtScoreP1.text = String(score);
        txtLife.text = String(life);
    }

Typically, we use the handleDraw function to update the UI displays. In this case, we check if the readyToMove variable is current true or false. If it is false, the player will not be able to move, and it can be quite confusing if you do not give the player a visual indicator that he must hit the spacebar. The txtHitSpaceBar textfield was created for this purpose.

We update the text field that shows the score (txtScoreP1). Since score is a number data type, we need to cast it into a string by using String(score) before assigning it to the text field.

We will also display the player's life.

Part 10

    private function triggerGoToWin()
    {
        clearGame();
        removeEventListener(Event.ENTER_FRAME, update);
        gotoAndStop("win");
    }
    
    private function triggerGoToLose()
    {
        clearGame();
        removeEventListener(Event.ENTER_FRAME, update);
        gotoAndStop("lose");
    }

The two functions triggerGoToWin and triggerGoToLose are called whenever the respective win or lose states happen.

To prevent the game from continuing to run, we will remove the event listener to ENTER_FRAME, hence stopping the game loop.

Part 11

    //Misc Functions
    private function resetGame()
    {
        //remove all food
        removeChild(mcFood);
        mcFood = null;
        
        //remove all of snake body except first
        for (var i = snakes.length - 1; i >= 1; i--)
        {
            removeChild(snakes[i]);
            snakes.splice(i,1);
        }
        
        //Center the snake's head
        snakes[0].x = 400;
        snakes[0].y = 300;
        
        readyToMove = false;
    }
    
    private function clearGame()
    {
        //remove all food
        if (mcFood != null)
        {
            removeChild(mcFood);
            mcFood = null;
        }
        
        //remove all of snake body
        for (var i = snakes.length - 1; i >= 0; i--)
        {
            removeChild(snakes[i]);
            snakes.splice(i,1);
        }
    }
    
    private function collided()
    {
        life -= 1;
        
        if (life > 0)
            resetGame();
        else
            gotoLose = true;
    }

When the game is reset, we remove the food movieclip, the snake body parts and reset the snake's head to the center of the screen again.

Download the Game Files

The files you need to create this game can be downloaded from here.

The Game

Now's the time to test your reflexes. See how long your snake can grow!




How To Play

Objective: Collect all the food pellets that pop up. Avoid hitting the walls or your snake's body

Controls: W - Move Snake North, S - Move Snake South, A - Move Snake West, D - Move Snake East


Content on this page requires a newer version of Adobe Flash Player.

Get Adobe Flash player

Flash Resources
Preloader FPS Display Sounds & Music
Keycodes Name Generator
Game Development Resources
Sprite Sheets


Posted by liam

on 2014-06-05 09:00:04

hey im trying to do this game in flash but my action scrip keeps coming up with errors sayint there needs to be another package and there isnt one can you please help


Posted by Ali Ahmad

on 2014-03-18 13:56:57

Hello Nice tutorial but where do you go on flash are using action script 2 or 3


Flash Tutorial Links:
Play Games: HTML5 Tutorials:
gaming tools download on app store now!
Home | About Us | Contact Us
Powered by Make Flash Games. All Rights Reserved.
By Joseph Tan