3D - A Parkour Game (Difficulty: 5)
CreatiCode last edited by info-creaticode
In a previous tutorial, you built a project with an avatar running on a bridge. In this tutorial, we will build upon that project to create a parkour game. The player will control the runner to collect as many coins as possible without hitting any obstacles along the way.
Please open the project from the previous tutorial, and save a copy of it. Give it a meaningful name like “A Parkour Game”.
Now please add a new empty sprite named “Game Items”. We will add and manage all game items from this sprite, such as roadblocks and coins.
Similar to the other sprites, we will broadcast a “add game items” message from the “Main” sprite:
and then handle this message in the “Game Items” sprite:
We will need to specify where to place the game items. Although we can place an item in any position, it is much simpler if we treat the bridge deck as a grid, and only place items at the center of each grid cell.
For example, we can divide the deck into 3 columns. The deck is 300 units wide, so each column will be 100 units wide. The center of these 3 columns will be x = -100, x = 0 and x = 100.
Similarly, we can divide the deck into many rows, with each row 100 units wide. The center of the rows will be y = 100, y = 200, etc.
With these columns and rows defined, we can use them to specify where to place objects. For example, if we want to place a mushroom in column 3 row 2, then its position will be x = 100 and y = 200.
For another example, if we want to place a rock in column 1 row 3, then its position will be x = -100 and y = 300.
To store the position of the game items, let’s use a table. Please go to the “Variables” category, and make a new table named “items”.
Since we are dividing the deck into 3 columns, let’s create 3 columns named “1”, “2” and “3”. Although you can manually make these changes, it is faster to use these 4 blocks:
Let’s also add 60 empty rows to this table, so that we can use them to place game items at y position of 100 to 6000. A repeat loop like this can be used to add these empty rows:
Now let’s add some data to the new table to specify the positions of items we want to place on the deck. Suppose we want to place a roadblock in row 3 column 2. We can write the letter “b” in the table like this:
Now let’s add some more roadblocks. For example, in row 7, we add 2 roadblocks in column 1 and column 3:
You can add more data if you like, but this is good enough for us to start coding.
Since we will use many roadblock objects in the scene, and they are all the same, we can just add one roadblock first, then make many copies of it.
Since the roadblock model is not available in the CreatiCode platform, we can not use the “add model” block. Instead, we can find one on a third-party website like Sketchfab.com. A search for “road block” returns many models, and we will use the highlighted model in this tutorial:
You can download the model in GLB format, then share it as a community model. You do not need to do this step if you just want to use the same model.
When adding this community model, please set its height to 50, so that it is not too big. Also, give it the name “b”, which is the same as the letter we use in the table to represent roadblocks.
The roadblock should now appear in the same position as the runner avatar:
We will be making copies of this first roadblock and placing them on the deck. We don’t need to show this first roadblock itself. Therefore, we can just move it down to hide it under the bridge:
In case you are curious, you can still see this object if you set the follow camera to “Free” mode:
Now we are going to go through every cell in the “items” table, and read the content in it. We will need to use 2 for-loops. We will need 2 new variables named “row” and “col” for these 2 for-loops. The “row” variable should go from 1 to 60, since there are 60 rows in the “items” table. The “col” variable should go from 1 to 3, since there are 3 columns in the table.
Given the row number and column number of any cell, we can read out its value, and store it in a new variable named “item type”.
As we check every cell in the table, the value of the variable “item type” will be either “” or “b”. If it is “b”, that means we should place a roadblock at that column and that row.
To make a copy, we need to select the first roadblock object we have added, and then use the “copy object” block.
After making the copies, we still need to move them to the target row and column on the deck. We need to calculate the X and Y positions using the row and column numbers:
X position: if the column number is 1, then x is -100; if column number is 2, then x is 0; if column number is 3, then x is 100. Although we can use 3 “if” blocks, it is simpler to use these blocks to calculate the x position:
Y position: for row 1, the y position is 100; for row 2, the y position is 200. So we can simply multiply the row number by 100 to get the Y position:
Combining the blocks above, we can move the copied objects like this:
Now we get the 3 roadblocks that correspond to the 3 “b” letters in our table. One in row 3 and 2 in row 7.
When we have to make many copies, the code above can be slow. To speed it up, we can define a new block named “add items”, and set it to “run without screen refresh”.
After that, move all the blocks for adding the roadblocks into the definition of this new block:
When we add more items later, this change will make our program run faster.
Now let’s start to work on the “Runner” sprite.
As the runner moves on the deck, we need to check if the runner is blocked by any roadblocks. Since we already know the position of all the roadblocks from the “items” table, we just need to find out the current position of the runner, and look it up in the table.
Note that we only need to do the checking when the runner arrives at a new row. For example, the first row is at the Y position of 100. So we do not need to do anything until the runner is at the Y position of 100. After that, we can wait until the runner is at the Y position of 200 to check again.
We can implement the idea above using these new blocks in the Runner sprite. A new variable “new row” is used to represent the next row where we will check the runner. It starts as 1. When the runner’s Y position is at least 100 (1 times 100), we show its exact Y position in a speech bubble and then increase “new row” to 2. Later, when the runner passes the Y position of 200 (2 times 100), we would show her Y position again and increase “new row” to 3, etc.
Now we see the Y position of the runner as she passes each row on the deck:
Now we know the runner’s row position, we also need to know which column she is in. There are only 3 columns on the deck. The middle column (column 2) is between x of -50 and 50. Therefore, if the X position of the player is less than -50, then she is in column 1; if her X position is more than 50, then she is in column 3.
Now we can see her column number printed out:
Given that we know the runner’s current row number and column number, we can read the “items” table to find out the type of item at that position. If it is the letter “b”, then we know the runner is colliding with a roadblock. We should stop the forever loop right away, and broadcast a message of “game over”.
When the Runner sprite receives the “game over” message, it should stop the runner and the transformer object named “t” (which controls the follow camera).
As shown, the runner will be stopped at the roadblock:
To make it more interesting, we should turn the runner to face the camera, and show a “Defeat” animation:
This is what it looks like:
Besides showing the defeated animation, we should also show a big message that says “GAME OVER”. This can be easily done using a label widget or a speech bubble. Here is how to do it using a speech bubble.
Here is the result:
Besides roadblocks, we also need to place some coins on the bridge deck. To get started, we should pick some cells in the table and add the letter “c”. For example, here are 3 of them in row 3, 5 and 7:
Now let’s switch to work with the “Game Items” sprite.
Similar to the roadblocks, we will add one coin first, then make many copies of it. As shown, please add a “Stylized Coin” model (also from Sketchfab) and name it “c”. It should be hidden below the bridge as well.
We can reuse the same code to copy the roadblock for copying the coin. In addition, we can make the coins spin around the Z-axis.
Here are the new coins added to the deck:
Now let’s work on the Runner sprite.
We can detect if the runner is touching a coin similar to how we check for roadblocks. We will need to create a new variable “score” to keep track of how many coins the runner has collected. It should be set to 0 when the game starts.
Whenever the runner is touching a coin, we should increase the score by 1:
Now we can see the score variable will increase as the runner touches each coin:
After a coin has been touched by the runner, it should be removed from the scene. To do that, we first need to go to the “Game Items” sprite, and give each coin a unique name. For example, we can form a name by joining the coin’s row number and column number:
In the “Game Item” sprite, we need to handle a new message “remove item”, which will take the name of the coin to be removed as a parameter. You need to create a new variable “item name”, and select it in the “when I receive” block. After that, we can remove the object using that name:
Now we switch back to the “Runner” sprite, and broadcast the “remove item” message when we know the coin to be removed. We can join the column and row numbers to get its name, and provide that as a parameter when we broadcast the message:
Now the coin will disappear when the runner collects it:
If the runner manages to run through all 60 rows, then the game has been completed successfully. For a simple illustration, let’s declare the player has won after the runner passes 10 rows. This can be implemented in the Runner sprite by broadcasting a new message “success”:
The code for handling the “success” message is very similar to the code for handling the “game over” message. We just need to change the animation and the word we print on the screen:
Here is what it looks like:
Now you have created all components of a game, it’s time for you to make it a complete game. Here are some example ideas:
- Item Map: Obviously, you should add more data to the “items” table to specify where to put more roadblocks and coins.
- Score Display: You can use a label to display the score nicely. Also, whenever the runner picks up a coin, you can show “+1” next to it using a speech bubble.
- Other Items: Besides roadblocks and coins, you can add other types of objects, such as plants, road signs, treasure chests, etc.
- Simpler Controls: Currently, the player has too much control in the X position of the runner. To make it simpler, you can only allow the runner to run forward at X of -100, 0 or 100. For example, when the player presses the right arrow key, you would make the runner avatar run to the right until its X position is 100.
- Jump and Slide: You can allow the runner to jump over the roadblocks, or slide under some obstacles. Note that you can check the Z position of the runner to see if she is jumping over the roadblock.
- Sound Effects: You can play sounds throughout the game, such as when the runner picks up a coin, when the game is over/completed, etc.