This article has links to websites or programs outside of Scratch and Wikipedia. Remember to stay safe while using the internet, as we cannot guarantee the safety of other websites. |
This article or section may not have content matching Scratch Wiki editing standards. Please improve it according to Scratch Wiki:Guidelines and Scratch Wiki:Editing Conventions. (February 2020) |
The game loop is a method for writing games. The entire game runs in one loop, which handles the updating and drawing of all the sprites in the game. The updating makes changes to the sprite and all the drawing happens when the draw message is received. This style of programming is called modular design and makes games easier to design and change. [1]
State Machines
Control over program execution is performed by a state machine. State machines help organize our code as the behavior being modeled grows more complicated.[2] For this tutorial, we will create a simple top-down shooter using a game loop to control all the sprites.
The Main Loop
Create a sprite called main loop and use the scratch editor to hide it permanently. The backbone of the game loop is the loop, which triggers the update and drawing blocks by broadcasting messages. It also controls the frame rate.[3]
Place this code in the main loop sprite.
when gf clicked set [game state v] to [start] reset timer forever set [old time v] to (timer) broadcast [update v] and wait broadcast [display v] and wait set [delta time v] to ((timer) - (old time)) end
What it Does
The game loop broadcasts the "update" message, a message to recalculate the game's data based on new information, such as pressed keys. The "display" message tells sprites to update the screen to reflect the updated data. The body of the game loop is sometimes known as a "tick". The "delta time" variable gets the execution time of a tick, so programmers may give their sprites constant speeds despite frame rate changes that occur from processing contention.
The Update Message
The update message updates the game's variables and handles the game logic. Every sprite will have its own update block.
Code for the player spaceship sprite.
when I receive [update v] if <(game state) = [play]> then set [show? v] to [true] if <key [left arrow v] pressed?> then change [x v] by ((-10) * (delta time)) end if <key [right arrow v] pressed?> then change [x v] by ((10) * (delta time)) end if <key [space v] pressed?> then create clone of [laser v] end else set [show? v] to [false] end
What it Does
This code is basically self-explanatory; the spaceship is moved with the left and right arrow keys, and the space bar shoots a laser.
Code for the enemy sprite..
when I receive [update v] if <(game state) = [play]> then if <(my state) = [attacking]> then if <touching [laser v]?> then set [my state v] to [exploding] else change [y v] by ((-10) * (delta time)) if <(y) < (-160)> then set [game state v] to [lose] // If the enemy gets to the player, then the game is lost. end end if <(my state) = [exploding]> then delete this clone end end else set [show? v] to [false] delete this clone end
What it Does
This is the behavior of the enemy sprite. This sprite has its own state machine because it has different behaviors for advancing towards the player and dying.
when I receive [update v] change [y v] by ((60) * (delta time)) if <<(y) > (180)> or <touching [enemy v]?>> then delete this clone end
What it Does
This is the code for the laser. The laser moves up, and disappears if it hits an enemy or goes off the top of the screen (y > 180).
Code for the play button sprite.
when I receive [update v] set [x v] to [0] set [y v] to [-100] if <<(game state) = [start]> or <(game state) = [lose]>> then set [show? v] to [true] end
What it Does
Every game tick your play button is going to check to see if you finished playing and are ready to play again.
As you can see, different sprites respond with different behavior to the same message/ state change.
The Initialization Message
Some states are not called during the main loop but they are still states that your sprites will enter during your game. The initialization state (sometimes called the 'create' or '_ready' in godot) is only called once before the sprite enters/transitions into one of the states in the main loop.
Place this code in your enemy sprite.
when I receive [init enemies v] set [clone? v] to [true] set [y v] to [160] repeat (5) set [x v] to [-240] repeat (23) change [x v] by (20) go to x: (x) y: (y) create clone of (myself) end change [y v] by (-20) end set [clone? v] to [false]
What it Does
This code creates 5 rows of 20 enemy sprites at the top of the screen. You will have to adjust the size and length of the rows to support your sprites size.
Place this code in your laser sprite
when I start as a clone hide set [x v] to ([x v] of [player v]) set [y v] to ([y v] of [player v]) set [clone v] to [true] set [show? v] to [true]
What it Does
This code initializes the laser sprites (it can only be called once when the sprite starts as a clone) position and visibility.
Controlling the Game
The player needs some way to control when the game starts, so let's include this code in the play button.
Place this code in your play button sprite
when this sprite clicked broadcast [init enemies v] and wait set [game state v] to [play] set (show? v) to [false]
What it Does
It shows the button at the start and after the player loses, and clicking it transitions the game to the playing state.
These "game states" keep our code manageable, even when it grows complicated. The "game state" is held in a a global variable so that all sprites can use it to control their own behavior and the behavior of other sprites. For example, the spaceship can only moved when the "game state" is set to "play".
The State Machine
With the game loop concept, what code runs is controlled by a 'state machine'. A state machine is a set of logical states, and your game will move/transition from one state to another, when certain conditions are met. For example, every game tick the enemy sprite checks if <(y) < (-160)> then
and if this is true then the state machine transitions from the *play* state into the *lose* state.
The Draw Message
The draw message tells the sprites to update their appearances based on the changes made in the update block.
Place this code in the player sprite and the button sprite.
when I receive [draw v] if <(show?) = [true]> then go to [front v] layer show else hide end go to x: (x) y: (y)
Place this script in the enemy sprite and the laser sprite.
when I receive [draw v] if <(clone?) = [true]> then if <(show?) = [true]> then show else hide end go to x: (x) y: (y) end