Introduction: Advanced Game Development Using Scratch 3.0
This Instructable is aimed at someone with a moderate level of experience using the Scratch block-code platform and who is looking to create a slightly more advanced game.
Looking back on the year of 2020, one of the good experiences I will remember, is embarking on a journey of discovering code blocks with my two sons (aged 7 and 9). My wife and I decided to incorporate the basics of coding into their homeschooling curriculum and we discovered what boundless creativity is wrapped up in the seriously user-friendly coding platform called Scratch. They quickly learnt the basic elements of coding as we worked through all the tutorials and then took up the challenge to collaborate and develop their first serious game.
For our game we chose to create a retro-style, space invader themed, laser blasting game called Astro Fleet.
Here's a link to our Scratch Project: https://scratch.mit.edu/projects/468547398
Scratch has a great community that encourages sharing of projects and allows one to "remix" any project that is shared to the public. And there are many other advanced games available on Scratch to learn from. The challenge though, is that without proper comments in their code, it can at times be tedious to decipher.
With that in mind, we decided to focus this Instructable on describing steps to code different elements of our game in a general nature, and focus on features we would expect more advanced game developers will be interested in discovering.
The steps of this Instructable are generally sequential, however they are also written to be independent allowing you to focus on a particular feature you are trying to add to your game. So feel free to jump down to a specific step which describes what you're currently working on. Also note that there are many other resources available online. Scratch has a comprehensive list of coding techniques with tutorials which we found helpful and can be found at the Scratch Wiki.
Step 1: Planning the Game
Step 2: Adding Sprites and Backdrops
Step 3: Making Sprites Move - Using the keyboard
Step 4: Making Sprites Move - Shooting projectiles (laser)
Step 5: Making Sprites Move - Objects falling at random (asteroids)
Step 6: Making Sprites Move - Objects moving in a pattern
- Using the glide to... block
- Using a sine wave function
- Rotating around another moving sprite
Step 7: Using Costumes to Create Animations
Step 8: Advanced Sprite Clones with List Variables
Step 9: Debugging Tips and Techniques for Scratch
- A Scratch account
- Basic understanding of Scratch coding and the website interface
- Reference resource to coding different scripts: The Scratch Wiki
- Resources for finding sprites, sounds and music: OpenGameArt.org
Step 1: Planning the Game
For the most part, Scratch is really flexible allowing you to add different components to your project as you go. But it's always a good idea to spend some time planning the main elements of your game. Without going into a lot of detail, here are some things you should consider:
- What is the type of game you are trying to create?
- How will a player win or lose when playing your game? What is the goal of your game?
- Try to consider your title screen and main menu early on in game development. Although it will evolve along with your game, and you'll probably still be adding final touches to it at the very end - it's good to start setting it up from the beginning so that you will have a space (backdrop or sprite) where much of the initiation code blocks can be placed. For example clearing of variables and other initiating code elements.
- Will this be a single or multi-player game? A multi-player game could involve two people controlling different sprites using the same keyboard or having each person play sequentially and compare performance (like highest score or shortest time).
- What will be the main sprites or characters of your game? Remember to consider text such as labels and headings as separate sprites from your game characters.
- Think about reducing the number of sprites by using different costumes and/or clones for the same sprite.
- Consider the different backdrops you may include. Will they be stationary or moving backgrounds?
- How will you control the sprites or characters in your game? Using the keyboard or mouse or other method?
- Event triggers are things to consider throughout the project. But it is helpful to think about how different sprites might interact (e.g. what happens when the laser sprite touches the asteroid sprite), or different aspects of the game might be triggered (e.g. what happens when the player clicks on a menu button or if a variable reaches a certain value).
Step 2: Adding Sprites and Backdrops
Adding sprites or backdrops is relatively simple. You can select from a range of built-in options or upload an image file (preferably .png file with transparent background).
Click on the sprite icon at the bottom-right of the screen to view different options for selecting/creating or uploading a new sprite.
Step 3: Making Sprites Move - Using the Keyboard
Making things move is one of the main features of Scratch and there are several ways to get your sprites moving - either in response to direct controls, or by means of timed instructions. Let's start by looking at controlling your main sprite (which in our case is the space ship) using the keyboard.
- When key pressed event (pic. 1)
Using the "When ... key pressed event is intuitively usually one of the first code block options selected to control the movement of a sprite. Using the arrow keys, one would then need four different event blocks for each arrow key. The drawback of this method is that movement is not as responsive when holding down a key. So if smooth movement is desired, I recommend using sensing blocks described in the next method.
- Using sensing blocks and IF-statements in a forever loop (pic. 2)
The forever loop is triggered when receiving a broadcast message after the Play button is pressed. The loop cycles through four IF-statements each checking if a key has been pressed using the Sense blocks. In our game we allow the player to use a variety of methods to control the space ship. They can use the standard arrow keys, or WASD keys. Each option is separated by OR-blocks in the IF-statement.
The actual movement of the sprite is controlled by the "change x by" and "change y by" movement blocks, followed by a number that will change its x and/or y position coordinate. The larger the value of this number, the faster the movement will appear.
In our game we also set two global variables (ShipX and ShipY) which are used as position reference for locating the laser sprite when it is triggered with the spacebar.
Step 4: Making Sprites Move - Shooting Projectiles (Laser)
The following Scratch Wiki for shooting projectiles describes different methods we found helpful. In our game we used a combination of these options (two sprites, one cloning itself), so that we could differentiate when either the laser or the space ship hits an object.
Points to take note of:
- Using a clone method allows the player to shoot multiple times without having to wait until the first laser touches an object or edge of the screen.
- The forever loop waits until the spacebar key is not pressed. This allows control over how many clones are created so that only one is created for each time the spacebar is pressed.
- When the laser sprite starts as a clone, move forward until it hits an object or edge of the screen. Since the laser can hit several different sprites during the game, we wanted to avoid having a long string of OR statements to check if either of them are touching the laser sprite, and instead used the "Laser Hit" global variable.
- Remember to always "delete this clone" instead of just hiding the clone at the end of the script. Hidden clones remain active and can slow down the processing of your code.
Step 5: Making Sprites Move - Random Falling Objects (Asteroids)
Scratch has a few different options for creating random movements of sprites. Many of these are found in the Motion section of the code blocks. In the case of our game, the asteroid field was created by:
- Initiate a new clone of the asteroid sprite every 0.5 seconds within a forever loop and IF-statement.
- It is important to make use of LOCAL variables when working with clones so that the variable will essentially only apply to that clone. To create a local variable, when creating a new variable, be sure to select the option "For this sprite only".
- The variable AsteroidX is set at a random variable between -200 and 200 (which are the extents of the x-axis).
- AsteroidY value is set near the top of the screen. In general, be careful not to set this value too high which will cause the sprite to touch the edge of the screen and trigger it to disappear (if this has been included in your code).
- Switch to the Asteroid costume to ensure it is showing the correct image for the asteroid.
- Set ghost effect to 0 (a precursor to having any remaining asteroids fade out at the end of Level 1).
- For added effect and making things interesting, we chose to also randomize the size of the sprite between 15 to 30% and then use the show command block.
- Another local variable "speed" was selected randomly between -3 and -5. This value determines the speed at which the asteroid moves down the screen.
- Within a Repeat Until code block, the y-value of the clone is changed and AsteroidY value updated. This is repeated until the clone reaches near the bottom of the screen or the Level is completed.
- Finally remember to delete the clone.
Step 6: Making Sprites Move - Objects Moving in a Pattern
Often you may wish to move sprites to a specific x and y location. Or possibly you wish to move sprites in a coordinated pattern. In this section we look at three different scenarios:
- Simple structured movements using the "Glide (... secs) to x:... y:..." movement block.
- Oscillation movements using a sine-wave function
- Rotating one sprite around another moving sprite
Using the "Glide to" movement block(pic. 1)
A simple example in our game of using this movement block is when used to control the play button gliding into position on the title screen. Use the "Go to x: y:" block to control instantaneous movement to the start position of the glide movement. Then use the Glide to block for 0.5 sec to the ending position. In our case we wanted to create the effect of a slight over travel and move back to the final position - so we incorporated two Glide to blocks.
Oscillation Movement using a Sine-Wave Function (pic. 2)
After surviving the asteroid field of Level 1 in our game, the player faces down waves of blue energy balls that oscillate from sided to side as they move down the screen towards the space ship. This oscillating movement is created by using a series of variables in a repeat loop and in combination with a sine function:
- It's not shown in pic. 2, but the energy balls are created as clones in the same way that the asteroids are created (see step 5.1. above).
- Xpos and Ypos are local variables associated to each energy ball clone, and the Xpos is randomly selected between the extents of the screen.
- After initializing some of the variables a repeat loop is initiated and continues until the clone reaches the bottom of the screen or the level is complete.
- The variable "angle" starts out as zero and is increased by 5 with each loop repetition. The angle variable is used with the sine function to calculate a new movement position with each loop.
- The "size" variable is also calculated using the sine function. A few steps down in the code, the size of the clone is updated using this variable. And the oscillating nature of the sine function make the clone's size become larger and smaller, and creates the visual illusion that the clone is moving closer or further away (into the screen).
- Side-to-side movement is controlled by using the "Go to x: y:" block with an embedded sine function to calculate the x-position. The multiplier value of 50 determines the amplitude of the oscillation.
- When the timer runs out and the end of Level 2 is reached, all remaining clones are faded out using the ghost effect.
- Even though clones are not visible as a result of the ghost effect, always remember to include the "delete this clone" block at the end of your script.
Rotating a Clone around another Moving Sprite (pic. 3 and pic 4)
A visually impressive movement sequence that can be controlled, is to maintain a circular motion of one or more clone sprites around another sprite - even while the central sprite is moving!
- One of the key aspects to controlling this type of movement is to understand and use reference coordinates for the main (center) sprite. In the case of our game, this was the Big Boss and we kept track of its coordinates using GLOBAL variables BossX and BossY.
- Start by creating the clones of the sprite which will be circling the central sprite. We created three fighter jets separated by 0.2 seconds delay. I had to play around with the timing to have them spaced out equally around the Big Boss. This was dependent on the speed with which they traveled and the radial distance from Big Boss.
- Start a new script when starting as a clone, and define a LOCAL variable to represent an angle.
- Create a forever loop and start by adding a block to increase the angle variable. The larger this value, the faster the clones will rotate around the central sprite.
- Set the x- and y-coordinates of each clone by calculating its value at an offset from BossX and BossY values. This offset is calculated as the sine and cosine of the angle variable, multiplied by a factor which controls the radial offset.
- Finally, use the "point towards " code block to ensure that the clones remain pointed in the correct orientation as they fly around the sprite.
- As the central sprite moves and the global variables (BossX and BossY) update, the circling clones will update accordingly and move with the central sprite.
Step 7: Using Costumes to Create Animations
Animating your sprites provides that additional element of dynamic motion to your game. In Scratch, this is done using Costumes. These are a series of different images all related to the same sprite and can be coded to appear on command or displayed sequentially using a repeat loop. The example we'll look at in our game, is when an asteroid is hit initiates the animation for an explosion.
- Start by selecting the Costumes tab for the sprite you wish to animate.
- Upload or create the series of images as additional costumes. In some cases you may find a sprite sheet online (i.e. one image containing a grid of smaller images). In that case you will need to separate the sprite sheet into individual image files first. We used the free image editing software called GIMP to do this.
To slice the image, first add horizontal and vertical guides along the grid pattern of the sprite sheet. Then use the Image>Transform>Guillotine command to slice along the guides.
- Make sure that uploaded costumes are in the proper order. It is helpful to name each image file and costume using a sequential number.
- In the code editor, add an appropriate trigger or condition which will initiate the animation. In our case, when the laser touches a clone of the laser sprite, it initiates a repeat block along with a next costume block. The number of repetitions depends on the number of costumes of your animation.
- Finally, hide the sprite, or delete the clone if this is the desired effect you need.
Step 8: Advanced Sprite Clones With List Variables
Clones have been used extensively throughout some of the examples previously discussed. In this step however, I'll dig a bit deeper into how we combined the use of list variables to assign clone ID's and keep track of each clone's status. This was necessary at Level 3 of our game where we manipulated a grid of clone fighters (4 rows and 7 columns) and wanted to make them more resilient, taking three laser hits before exploding.
(Side note): Our success in coding the complexities of all of these clones simultaneously was part of the inspiration for the title of our game...attack of the Mars clones!
I've already added comments to the code scripts (pics 1 to 4). But I'll go through each and script with some short descriptions.
- The first script (pic. 1) essentially runs a forever loop and initiates further code when the main IF-statement is true - namely Level 3 is reached and remaining fighters is equal to zero.
- When the IF-statement is true, the script calls a separate code block (pic. 2) dedicated to initializing relevant variables.
- From there, the loop contains two main nested repeat loops which are responsible for creating clones for rows and columns of the clone fighters.
- Before actually creating each clone, three list variables are created. Two of them are dedicated to tracking x- and y-coordinates for each clone, and the third keeps track of each clone using a variable FighterID. The FighterXpos and FighterYpos list variables start out empty and will later be populated with the coordinates when the clone is in its final grid position.
- When starting as a clone (pic. 3), the first few code blocks focus on gliding the clone fighter to its grid location. Once there, the list variables are updated with their current position.
- Once RowCounter is equal to the NumberOfRows variable, this is an indicator that all the clones are in position.
- The second portion of the script focuses on moving the clones at random in the direction of where the space ship sprite is (using the shipX variable as reference).
- Having the list variables for the clone's x and y locations allows us to control it to glide back to it's original grid position after attacking.
- The last script (pic. 4) keeps track of when a clone touches the laser sprite and controls when a clone should be eliminated with an explosion.
- As previously mentioned, it takes three hits to eliminate a clone. This is facilitated by nesting three IF-statements. Within each, the FighterID value changes to a different status, which is then used to proceed to the next nested statement.
- Finally, an explosion is shown using a repeat loop, changing the sprite costume, and finally deleting the clone.
Step 9: Debugging Tips and Techniques for Scratch
Throughout your project and especially at the end, you will need to go through a systematic process of making sure everything works as intended. And in cases where it doesn't, try to identify the source of the problem. This process is known as debugging. The fact that Scratch allows for multiple sprites to each run their own code simultaneously makes it somewhat difficult to debug with code spread apart. For this reason I generally try to keep code related to a particular sprite together. Debugging can become frustrating and tedious, but there are some techniques that you can follow in a systematic way to try to identify the source of the problem.
Steps I found helpful include showing variable values on the screen while code is run. At other times it is also helpful to pull apart the code blocks and steadily add back the blocks until the problem occurs.
The following Scratch Wiki for Debugging Scripts discusses the additional steps to the process quite thoroughly and makes suggestions on how to approach debugging your code.
Step 10: Play the Game! :-)
Hope this Instructable was helpful to you in some way as you make your own creation from Scratch. Remember to have fun while coding!
And have fun taking a crack at beating my score playing Astro Fleet.
Here's the link again to play and remix our project:
Runner Up in the
Block Code Contest