2D Physics - Bouncing Balls Game (Difficulty: 5)
-
Introduction
We will build a bouncing ball game using the 2D physics library. The player will use the mouse to shift the green board at the bottom, which will bounce the yellow ball into the blue target balls.
Step 1 - Create A New Project
To get started, create a new project in the CreatiCode playground and remove the Sprite1. Rename the “Empty1” sprite as “Targets.” We will be using this sprite to manage all the target balls.
Step 2 - Change Stage Size
In this game, the ball moves up and down a lot, so it is more fun if the stage window is taller, especially if we play it on mobile phones or iPads. Therefore, let’s change the size of the stage first. You can click the “Edit” menu at the top, and change the height of the stage and the canvas from 360 to 500:
After that, the stage will look like this:
Step 3 - Draw a Dark Backdrop
In the Stage, switch to the “Backdrops” tab, and draw a large rectangle in any dark color you like. It will make it easier to spot the player’s ball.
Step 4 - Add Targets Costumes
Now switch to the “Targets” sprite, and add 2 costumes from the library: “Ball-b” and “Ball-c”. Rename them as “blue” and “pink”. In addition, change the sprite’s size from 100 to 45, so we can place more target balls on the stage.
Note: if you find the ball to look like an oval on the stage, you just need to save the project, and then reload the page.
Step 5 - Initialize the 2D Physics World
Since we will be using the 2D physics engine, we should initialize it at the very beginning of the program. A suitable place to do it is in the Stage. Please add these blocks to the Stage:
We are initializing the 2D physics world with no gravity in any direction. Although this is less realistic, it makes the game easier to play since the ball will be going in straight lines. You can add some gravity later if you like.We are also setting the 4 borders around the stage to bounce the ball with 100% restitution so that the ball will not lose any speed when it hits the borders.
Lastly, we will broadcast a new message, “set up game”, so that all sprites can initialize themselves, knowing that the physics engine is already initialized at this point.
Step 6 - Add Private Variables “x” and “y” to “Targets”
Now switch to the “Targets” sprite and add 2 new variables, “x” and “y”. They will be used to store the x and y positions of each clone of the target sprite.
Make sure they are set to be “For this sprite only”. Such variables are also called “private variables” because no other sprites can see them. When we make clones of a sprite, each clone will have its own “x” and "y’ variables as well.
Step 7 - Nested For-Loops
Now, we will try to make many clones of the Targets sprite at different x and y positions.
Our work start when we receive the “set up game” message. For the range of x position, we know the stage width is 480, so the left stage edge is at x of -240, and the right edge is at x of 240. So, the x position of the target balls should be within that range, such as -220 to 220. We will use a step size of 20, so the x variable takes the value of -220, -200, -180, until 220.For the y position of the target balls, we will make it start at y of 0, which is the center of the stage. That way, all target balls will appear on the top half of the stage. The height of the stage is 500, so the top border is at y of 250. We can set the target ball to go up to y of 240.
Step 8 - Make Clones of Targets
Next, we can add clones at each of the x and y positions inside the nested loop. To do that, we need to move the Targets sprite itself to each of these locations and then make a clone at that spot. We will assign an ID to each clone, so we can identify them later. The ID will be joining the x and y positions of that clone using the “" symbol. For example, if a clone’s x is 0 and y is -20, then its ID is "0-20”.
Now, if you run the program, you will see how the clones are added one by one:
Step 9 - Speed Up
As shown above, adding the target balls takes a bit too long, because each time a new clone is added to the stage, the stage is redrawn. We can easily speed up this process by defining a custom block, “make clones.” The key is to set this block to “run without screen refresh.” This is much faster because we will not redraw the stage until all target balls have been added.
We can move all the blocks into this new block’s definition:
Now, it almost takes no time to add these target balls:
Step 10 - Enable Physics for Target Balls
To use the 2D physics engine to manage all these balls, we need to enable physics for them. This can be done after each clone is created:
Note that we set each clone with a “fixed” physics body so it will not move. And their shapes are circles. We also make their restitution 100% so that the player ball will bounce off them fully.
Step 11 - Testing Physics
The target balls are not moving since they are “fixed.” But to test if our code is working so far, we can apply these two temporary changes to make the balls fall:
-
Set the gravity to -300 along the y direction in the Stage:
-
Set the target balls to be “dynamic” in the Targets sprite:
With these two changes, the target balls will start to fall and [censored]p into each other:
We have verified the code is working so far. Please revert these two temporary changes.
Step 12 - Draw a Map
To make our game more interesting, we need to change the “map” of the target balls, which controls their location and type. For example, we should have two types of target balls: blue ones can be canceled out, and pink ones will stay on the stage (similar to walls).
To do that, we can add target balls of different colors according to a map. We will use the “touching color” block to determine the color of different points on the map, so as the Targets sprite travels through the stage, it will add different target balls based on the color of the map at its location.
Now, let’s add a new sprite named “Map” with an empty canvas. Then, draw a map with a blue rectangle, a pink rectangle, and a black rectangle. Note that their exact colors do not matter so long as they are three different colors.
Step 13 - Receive the Show/Hide the Map
We will show this map before we add the target balls, and then hide the map after the target balls are all added. Therefore, let’s add these two message handlers in the Map sprite:
Step 14 - Show the Map
In the Target sprite, let’s send out the message to show the map. Note that we are waiting for the message to be processed before adding the clones, which makes sure the map is visible when we add the target balls:
Step 15 - Test If Touching Blue
In the Targets sprite, after we move to the given x and y position, we will insert a step to check if we are touching the blue color. We can use the color reader tool to sample the blue color from the stage:
Step 16 - Set “my color” to “blue”
Since different target balls may have different colors, we will define a new variable, “my color,” to store each clone’s color. It should also be a private variable since each clone can have a different color.
Step 17 - Create a Clone Using “my color”
Now, we can dynamically determine which costume to use when we create a new clone. We need to create the clone after setting “my color”, and switch to the costume with the name of “my color”:
Step 17 - Set “my color” to “pink”
Now, we can add another similar “if” block to check if the original sprite touches the pink color on the map.
If the sprite is not touching either the blue or pink color on the map, it will not create any clones at that spot, leaving an empty space.
Step 18 - Hide the Map
When we are done with adding the target balls, we will hide the map:
Now, if you run the project, you will have different target balls based on the map:
Step 19 - Adjust the Map Costume
Since we add target balls based on the map, it is very easy to change their layout if we don’t like it. For example, suppose we want to make these two changes:
- There are two rows of pink balls, and we only need one row
- We want to add more empty space in the middle
We can open the costume editor of the Map sprite, and edit the map accordingly:
After that, run the project again, and our target balls are changed as well:
Note that this is just an example. You can design the map in any way you like.
Step 20 - Show and Hide the Original Sprite
In the Targets sprite, the original sprite travels through the map to make clones of itself. So after all the clones are created, we should hide the original sprite. In addition, we should show it before adding the clones so that the clones are visible as well.
Step 21 - Add a Bouncing Board
Next, let’s add a new empty sprite named “Board”. It will represent the board that the player controls. In its costume editor, add the “Ball-d” costume from the library, which is a green ball.
After that, change its size to 400, so it becomes a big ball.
Note that you can also draw the costume yourself, but you need to make sure of two things:- It is properly circular, not oval, since we will assign a circular physics body to it.
- Its center is at the center of the costume.
Step 22 - Set up Initial Board Position
When the Board sprite receives the “set up game” message, it should first move to the center bottom of the stage. If it is too low, it is hard for players on phones to drag the board; if it is too high, there is not much time to react to falling balls. Therefore, the y position of -220 seems a reasonable choice:
The board will be cut off at the bottom, but that’s still fine since we only use its top edge to bounce the ball.
Step 23 - Enable Physics for the Board
We need to add a circular physics body to the board as well, so that the ball will bounce off it. Its type will be “movable”, which means it will not move due to forces or collision, but we can still change its position in our code.
Step 24 - Shift the Board By Mouse
To allow the player to control the board, we need to repeatedly set its x position to the x position of the mouse pointer:
Now, if you run the project, you can move the board with the mouse (no need to press the mouse button):
Step 25 - Add the Ball Sprite
Next, we will add another empty sprite, and then add the yellow “ball-a” costume. Set its size to 50 so it is not too big.
Step 26 - Initialize the Ball
When the Ball sprite receives the “set up game” message, it should move to a starting position, which can be the center of the stage:
Step 27 - The START Button
We should not enable physics for the ball right away. Since the ball will start to move, and the player may not be ready. A much better way is to add a “START” button, so the player can click that button whenever he/she is ready.
We can add that button in the Stage sprite.
It will look like this:
Step 28 - When the START Button is Clicked
When the START button is clicked, we should broadcast another message, “start game”, so all the other sprites can take further actions if necessary. We will also remove the button itself.
Step 29 - Enable Physics for the Ball
When the Ball sprite receives the “start game” message, it should enable physics for itself. The ball’s restitution is set to 100% as well so it doesn’t lose any momentum when bouncing off other objects. We will set its initial speed to be 300 in the up direction.
Now, our game can already be played:
Step 30 - Maintain Ball Speed
You have probably found one issue with the ball: it slows down after a few rebounds. This can be due to a few reasons, such as friction with other objects or inaccuracy of the physics simulation. There is a simple solution to it: we can repeatedly set the ball’s speed back to 300 along its current direction:
Now, the ball will keep moving at a fast speed:
Step 31 - Collision Between the Ball and the Targets
When the yellow ball hits any of the blue target balls, we need to remove that target ball. To do that, we need to detect such collision events. We can ask the physics engine to broadcast a message when that happens in 3 steps:
-
In the Targets sprite, add a new variable named “info”. It will be used to store the information about the collision.
-
Also in the Targets sprite, add a “when I receive message with parameter” block. The message will be a new message of “hit target”, and the parameter will be stored in the “info” variable:
-
In the Ball sprite, ask the physics engine to broadcast the “hit target” message upon collision with the Targets sprite:
Now turn on the monitor for the “info” variable and run the game. You will see that whenever the yellow ball collides with a target ball, the “info” changes to show the collision information:
The “info” variable contains 4 parts separated by commas:- Sprite Name: that’s the name of the sprite hit by the yellow ball, which is always “Targets” in this case
- x: the x position of the sprite (clone) hit by the yellow ball
- y: the y position of the sprite (clone) hit by the yellow ball
- Clone ID: the clone ID of the sprite (clone) hit by the yellow ball
Step 32 - Check Which Target Ball Has Been Hit
Recall that all the target balls are clones of the Targets sprite. Whenever the yellow ball hits any target ball, it will broadcast the “hit target” message, so all the clones will receive that message. Therefore, each clone will need to check whether itself is the one being hit by the yellow ball.
To do that, we can extract the clone ID from the “info” variable, using the “part of” operator that splits the “info” by commas. Then, we compare that with the clone ID of this clone. Add these blocks to the Targets sprite:
Step 33 - Remove the Target Ball
If a clone finds that itself is the ball being hit, and it is a blue target ball, then we need to remove it from the stage. Note that we not only need to delete the clone but also need to remove its physics body from the physics engine. Otherwise, even if we do not see the sprite, its invisible physics body will still block the yellow ball.
Now, we can try to play the game. Can you see any problem with it?
Step 34 - Delay the Deletion
There is one problem: the yellow ball sometimes does not rebound when it hits a blue ball, and it erases several balls simultaneously.
The reason is that when we receive the “hit target” message, the physics engine may not be done with all the calculations for rebounding the yellow ball off the blue target ball. So, if we remove the blue target ball too soon, the yellow ball will continue in its current direction.
The solution is to add a small delay before we remove the blue target ball, such as 0.01 seconds:
Now the problem is gone:
Step 35 - Failing to Catch the Ball
If the player fails to catch the yellow ball using the board, then the player has failed. We can repeatedly check if the y position of the ball is below a threshold in the same forever loop that we have added before. We will broadcast a “game over” message. We will also remove the physics behavior of the ball so it no longer moves. We must also “stop this script” so the forever loop stops running. Otherwise, it will repeatedly broadcast the “game over” message.
In the Ball sprites, add these blocks:
Step 36 - The “Game Over” Screen
The Stage is the best place to handle the “game over” message since that’s where we handle all game state logic. We can show a red text using a new label, with a transparent background and no border:
Test if it works by letting the ball fall off:
Step 37 - Counting the Target Balls
The player wins if all the blue target balls are canceled out. To keep track of the number of blue target balls, we need to use a new variable, “target count.”
In the Targets sprite, we can add to the “target count” whenever we add a new blue ball:
As shown, the target count is 200 for this example:
Step 38 - Reduce the Target Count
In the Targets sprite, whenever a blue ball is removed, we need to reduce the “target count” by 1. And when the count reaches 0, the player has completed the game, so we broadcast a “success” message.
Step 39 - The Success Screen
In the Stage, when we receive the “success” message, we can show a label that says “YOU WON”. This is very similar to how we handle the “game over” message.
To test it, we can temporarily change the Targets sprite to add only 1 blue ball:
Then we can run the game to completion easily:
Step 40 - Sounds for Hitting the Ball
To make the game more fun, let’s add some sound effects. First, in the Target sprite, add the sound “Hit 5”, and play it whenever a blue ball is canceled. Also add a sound “Hit 4”, and play it when the yellow ball hits a pink target ball.
Step 41 - Sounds for End of Game
In the Stage, let’s add the sounds “Failure 1” and “Success 3”, then play them when we receive the “game over” or “success” messages:
Advanced Feature - Ball Splitting
By this time, we have a very basic game that can be played. In the steps below, we will add a new feature: when a blue target ball is canceled, we will randomly generate a reward that falls to the floor, and if the player catches that reward, each yellow ball will split into two.
Step 42 - Randomly Generate a Reward
In the Targets sprite, whenever a blue target ball is cancelled, we will draw a random number between 1 and 100, and if it is more than 90 (10% of the time), then we will broadcast a message “add reward”. In this message, we attach a parameter that contains the x and y positions of this target ball. For example, if the ball is at x of 20 and y of 30, the parameter will be “20|30”.
Step 43 - Add the Reward Sprite
Add the “Star” costume from the library as a new sprite, and name it “Reward”.
In this sprite, add a new variable “reward info”, and use it to store the parameter attached to the “add reward” message:
Step 44 - Clone the Reward Star
In the Reward sprite, we will first move the sprite to the same position as the blue target ball that’s canceled out, and then create a clone at that spot:
Note that we are using the “part of” operator again to split the reward info into 2 parts by the “|” symbol.
Step 45 - Make the Reward Star Fall
When the clone of the reward star is created, we will let it fall gradually:
To test this code, we can temporarily change the Targets sprite to always broadcast the “add reward” message:
And this is what we get:
Can you spot any problems?
Step 46 - Hide the Original Sprite and Show the Clones
The first problem is that we always see a star that is not falling. Since all clones will fall, that star must be the original sprite. To fix it, we need to hide the original sprite and show the clones:
Now we get rid of the star that doesn’t fall:
Step 47 - Only Handle the Message from the Original Sprite
There is a more subtle problem: when a new star is added, the old stars would disappear. This is because the “add reward” message is received by the original sprite and all the clones, so all of them move to the new position at the same time. We are actually seeing several stars overlapping and falling together.
To fix this issue, we need to make sure only the original sprite would respond to the “add reward” message. We just need to check the “clone ID”, which should be “originalsprite” if it is not a clone.
After this step, the reward stars are working correctly:
Step 48 - Remove the Star
For each of the clones of the reward star, if it falls to the bottom without touching the Board, we should remove this clone. We can check its y position like this:
We can see that the stars will disappear at the bottom:
Step 49 - Catch the Star
If the star touches the Board sprite before it falls too low, then we should not only delete it, but also send a message “split ball”, so that we will split all the yellow balls in the stage into 2 balls.
Step 50 - Clone the Yellow Ball
Now, we need to work on splitting the yellow ball into 2 balls. Since there will be more than one yellow ball, we will have to use clones. Therefore, we first need to move all the existing logic in the Ball sprite into the clone like this:
Now when we start the game, a clone of the yellow ball will be created:
Step 51 - Hide the Original and Show the Clone
We will need to take the same step as earlier, where we show the original sprite at game set-up time, hide it when the game starts, and then show each new clone:
Now the game looks the same as before:
Step 52 - Split the Ball into 2 Balls
In the Ball sprite, when it receives the “split ball” message, it should create a new clone of itself. But we also need to check the clone ID to make sure we do not clone the original sprite, which is hidden.
Now, the number of yellow balls will double each time we catch a star reward. Note: make sure you save the project before running this step, since it might add too many balls and slow down your browser.
Step 53 - Count the Yellow Balls
For the last step, we need to change the game-over condition. Currently we declare game over if the yellow ball falls too low. However, since we may have more than one yellow ball now, we should only do that when all the yellow balls are gone.
First, we need to keep track of the yellow balls using a new variable “ball count”. It will start as 0, and increase by 1 whenever a new clone is added:
Step 53 - Reduce the Ball Count
Whenever we delete a clone of the yellow ball, we should reduce the count by 1. If the count becomes 0, then we should declare “game over”. Also, we should delete the yellow ball clone when it falls too low:
Step 54 - Limit the Ball Count
Sometimes, there may be too many yellow balls, and it will slow down the computer. To make sure this game can be played on most computers, we should limit the number of yellow balls. In the Ball sprite, before we create a new clone, we should make sure the ball count is less than a threshold, such as 10:
Note: sometimes, we may still get more than 10 balls because the “split ball” message is received by all clones at the same time, so they may all find the “ball count” is less than 10 at the same time. This is often called a “race condition”. You can pick a smaller threshold if you do not want to have many balls.
Step 55 - Clean Up
Now the game is complete! Change the Targets sprite back so it only generates a new reward 10% of the time (or a lower probability):
We should also stop the ball from moving when the game is finished in the Ball sprite:
Here is the final gameplay demo:
Enhancement Ideas
Congratulations on completing this fairly complex project. You can now extend it into your own game. Here are some ideas worth exploring:
-
Level Maps: You can design maps of different difficulty levels by updating the costume of the Map sprite. You can have multiple maps, and when the player passes one level, restart the game with a more difficult map.
-
New Target Ball Types: Currently we only have blue and pink target balls, but you can add other types. For example, you can add a silver target ball type, which will take multiple hits before it is removed.
-
New Reward Types: Currently we only have one reward type, which splits every yellow ball into 2 balls. You can design other types of rewards, such as slowing down the yellow balls, or always keeping the yellow balls alive as they bounce off the bottom border, or making the yellow balls much bigger, etc.
-
Timer and Leaderboard: You can keep track of how long it takes a player to complete the challenge, and then add a leaderboard that shows the top players with the shortest game time.
-
-