This page is part of the Snake in MIT Scratch Tutorial.
Moving the Snake at Regular Intervals
Throughout the game the snake should keep advancing in the direction it is facing while the player tries to steer it and avoid crashing.
The requirements for the movement system can be summarized as follows:
- Twice a second the snake should move one space at a time in the direction it is facing.
- If the player’s input causes the snake to change direction then the snake should move immediately.
- After changing the direction the snake should wait half a second before moving again.
The movement system requires a regular event that can be interrupted by player actions.
To implement such a feature the core logic of the game must be considered.
Game Logic Flow
The logic of the game can be divided into two parts.
- Initialize game data.
- The Game Loop.
The first step is to set all the game variables to the values they should have at the start of the game. E.g. set the score to zero and create the snake.
The second step is a loop that repeats during the entire course of the game.
The loop repeats these two actions:
- Check input.
- Update the game objects.
The entire flow of the game boils down to the cycle of checking for input and then updating the game objects accordingly.
Initializing Game Data
In the Game Controller sprite of the Scratch project there is a function called Initialize Game Data.
The function is called when the green flag is clicked in Scratch to launch the game.
It sets important data that never changes while the game is running or restarted.
The function sets fixed data such as the grid sizes and defines a variable for each direction the snake can face.
Another function called Start New Game is used to set up a new game when the player presses space on the menu:
Many variables are set in order to put the game in the state it needs for a new game. Briefly they are:
- A message is broadcast to let other sprites prepare for a new game.
- The Game Running variable is set to 1 to signify that a game is in progress.
- The snake’s direction is set to Direction Right.
- The Scratch timer block is reset so it can be used to track time.
- A Direction Changed flag is set to 0. This is used when processing input.
- The Score is set to 0 and hidden from view.
- The snake’s body is created using the Create Snake function.
- The Move Apple message is broadcast to place the apple in a random location.
- The values that track whether the snake crashed or the game was won are reset.
The Start New Game function is called every time the game starts including when the game is restart after the snake crashes.
It differs from the Initialize Game Data function in that the variables can change during the course of the game and need to be reset each time.
The Game Loop
The game loop is the process of repeatedly checking for user input and updating game objects accordingly.
All the events that occur during the Snake game loop are shown in the following flow chart:
The first step in the logic flow of the system is to initialize the game data. This puts the game in the state it should be at the start of a new game.
Next the system enters into the game loop. The system repeatedly checks to see if there is any user input (e.g. the user pressing one of the arrow keys) or if the time since the last move is greater than the wait time.
If the snake is due to be moved the system calculates its next position and checks if the snake has eaten an apple, won the game or crashed then the system takes the appropriate action.
Winning or losing the game will cause the game loop to end. If the system reaches the end of the game loop without the game ending then the timer is reset and the system goes back to check for input again.
The system checks for user input before checking if the move timer has expired.
If the input caused the snake to change direction the system jumps past the timer check causing the snake to move immediately.
The timer is reset at the end of the game loop so the next snake move will have the normal delay time.
The process of deciding if the snake has changed direction based on user input is described in more detail in Section 6.
Updating Game Objects
After processing the keyboard input the system updates all the game objects to reflect what is currently happening.
There are four parts to this process:
- Decide if the snake should move.
- Calculate the snake’s next position.
- Determine the consequences of moving to this position.
- Resetting the timer.
Deciding if the Snake Should Move
These two conditions decide if the snake should move:
- User input caused the snake to change direction.
- Enough time has passed since the last time the snake moved that it is time to move again.
Calculate the Snake’s next Position
The system uses the current position of the snake’s head and the direction that it is currently traveling to calculate the next position that the head will occupy after moving.
Determine the Consequences of Moving to this Position
There are three possible outcomes when the snake moves to a new position:
- Crash: The next square is already occupied by a body part resulting in a game over.
- Apple: If there is an apple the snake should grow.
- A special case can arise here where after growing the snake completely fills the screen and the game is won.
- Empty: The square is empty and a normal move occurs.
Resetting the Timer
The timing mechanism used to determine when to move is reset every time the snake moves.
Movements caused by player input will reset the timer the same as movements caused by the timer.
After the player changes direction there will be the same delay before the snake moves again.
The Scratch Game Loop
The Scratch implementation enters into the game loop when when the backdrop switches to game.
A variable called Game Running records that a game is active.
As long as Game Running = 1 the game loop will keep looping.
When the snake dies or the game is won Game Running is set to zero.
The Game Running value is checked at the start of each game loop:
Deciding Whether to Move the Snake
There are two things that can cause the snake to move:
- The user pressed an arrow key causing the snake to change direction.
- The amount of time that the snake waits between moves has passed.
This if statement in the game loop checks these two conditions:
The Handle Input function is used to check the keyboard input. It is explained in detail in Section 6.
If the snake has changed direction the Direction Changed value will be 1.
The time since the snake last moved is measured using two components:
- Timer Block: A Scratch block that counts how much time has passed since it was last reset.
- Snake Move Wait Constant: The time in seconds that the snake should wait between moves.
On each cycle of the game loop the value of the Timer Block is compared to the Snake Move Wait Constant.
If the value of the Timer Block is greater than the Move Wait Constant that means that enough time has passed since the timer was last reset and it is time to move the snake.
After each move the Timer Block is reset to zero again.
The Timer Block
Scratch provides a Timer block. The value of this block starts at zero and then counts the time in seconds.
It can be reset using the reset timer block. This will put the timer back to zero and it will start counting up again.
More information on the Timer block can be found in the scratch wiki:
Snake Move Wait Constant
The value of the Snake Move Wait is the amount of time (in seconds) that the snake should wait between moves.
In the game project this value is set to 0.5 so the snake will wait half a second between each move.
On each cycle of the game loop the value of the Timer block is compared to the Snake Move Wait constant. If the timer’s value is greater than the move wait value then it is time to move.
The value of the Move Wait Constant is set as part of the Initialize Game Data function.
Calculating the Snake’s Next Position
This process is contained in the Calculate Next Position function that is described in Section 7.
The next position of the snake’s head is stored using two variables called Snake Next X and Snake Next Y.
Determining the Consequences of Moving
In the game loop the lose condition is checked first after calculating the next position:
The Check Lose function will look at the next position and determine if that causes the snake to crash. If the snake dies then it sets the Snake Crashed variable to 1.
The method that the Check Lose function uses to determine if the snake has crashed is explained in Section 8.
The Snake Crashed variable is checked after calling Check Lose. If Snake Crashed = 1 then the Game Running value is set to 0 so the game loop will exit and the backdrop is switched to the Game Over screen.
The check to see if the square is empty or if it contains an apple is done as part of a function called Update Snake:
The Snake Next X and Y variables are compared with the Apple X and Y values. If the position is the same the Grow Snake function is called, the score is increased and messages are broadcast to update other sprites.
If the values do not match a normal move is performed.
After calling the Update Snake function in the game loop the system checks to see if the win condition has been met:
The Check Win function will set the Game Won variable to 1 if the win condition has been satisfied.
If the game has been won the Game Running variable is set to 0 so that the game loop will no longer continue and the backdrop is changed to the You Win screen.
The Check Win function is as follows:
It compares the length of the snake to the size of the grid. If they are the same then the snake must fill all of the grid squares and the Game Won variable is set to 1.
Resetting the Timer
Finally the timer block is reset to create the delay before the next move. This action is performed both when an apple is eaten and during a normal move:
The system also resets the Direction Changed variable which is used to detect keyboard input and broadcasts a message letting other parts of the system know that the snake has been updated (e.g. Snake Part Clones know to update their position).
After this the system loops around again to check if it’s time to move the snake.
The Complete Scratch Game Loop
Previously the various components of the game loop have been described.
This is the complete game loop as it appears in the project:
While the game is running a loop is used to repeatedly check for user input and update game objects.
The loop has been designed to check conditions in such an order that the snake will move using a timer or when user input is received.
Next Section: Using the Arrow Keys to Control the Snake