3D - Bloxorz Game (Difficulty 6)
-
Introduction
In this tutorial, you will learn to reproduce a classic puzzle game called “Bloxorz”. In this game, the player rotates a box on a platform to reach the target hole:
You will practice using parenting to make objects rotate around any point, using a table for level design, and also a little bit of the 3D physics engine.
Step 1 - A Starfield Scene
To get started, please create a new project on the CreatiCode playground, remove the Sprite1 with the dog, and rename the “Empty1” sprite as “Main”.
In the Main sprite, add the following blocks. They will create an empty 3D scene, display the 3D axes, and add a nice skybox as the background with stars in space.
This is what you should get:
Step 2 - Add a New Camera
By default, when you add the skybox, it will also zoom out the camera. However, in this game, we are going to use objects that are very small. Please use the following block to add a new camera, which will replace the existing camera:
This camera will have a distance of 10 from the center of the world. In addition, we have disabled user input for the keyboard and the mouse pointer. This way, the user can not change the view of the camera, and all key presses will be used to rotate the player’s box.You should get an output like this. Do you see any issues here?
Step 3 - Configure the Camera
You have probably noticed a problem: we can no longer see the beautiful starfield in the background. That’s because the background is too far away. To fix the problem, we need to change the camera’s setting to make it view objects within a distance of 1000000:
Now we can see both the 3D axis near us and the starfield that’s very far away:
Step 4 - Add the Player Box
Now let’s add the box that the player controls. It should be 1 by 1 by 2, and given the name of “p”. You can pick any texture you like. We need to move it to the position of x = 1, y = 1, and z = 1. Since its height is 2, and z position is 1, its bottom will be at the level of z = 0 exactly.
It should look like this:
Step 5 - Add the “Platform” Sprite
Now please add a new empty sprite named “Platform”, which will be used to manage the platform boxes.
To initialize it, send a message from the Main sprite to “add platform”,
then receive it in the Platform sprite:
Step 6 - Add the First Brick for the Platform
The platform will consist of many bricks (boxes). To keep it efficient, we will use a common technique: we will add one brick, then make many copies of it.
Here are the blocks for adding the first brick. To keep our level design simple, we will make each brick 1 unit by 1 unit in the x and y dimensions. It should be fairly thin, with a thickness of 0.1. Give it a name like “g”, and feel free to pick any texture for it.
This brick will look like this when we zoom in on it:
Step 7 - Move the First Brick Away
Now we will move this brick away by setting its z position to a very large value, so our camera does not see it. This way, we can place all the copied boxes according to our level design map.
Step 8 - Use a Table to Represent Box Positions
To build up the platform, we will need to add a lot of boxes, and place them in different positions. Ideally, we would like to be able to view the map visually, so it is easy to create or change the map. For that reason, we will use a table to represent the map.
For example, the following is a table with 3 columns named “1”, “2” and “3”, which represent x positions of 1/2/3. It also has 3 rows, which represent y positions of 1/2/3. This way, each item in the table can be used to represent whether there should be a brick box at that position. For example, for column 1 and row 1, if we put the letter “b” there to represent “brick” (you can choose to use any letter), then it means we would like to place a box at x = 1 and y = 1. The 7 items in the table with “b” in them will translate to 7 bricks that form the letter “H”.
Now please create a new table named “map”.
Step 9 - Add 20 Empty Columns to the Table
Although we can manually add new columns to the table, it is much faster to do it using blocks. First, create a new variable “x”, then add the following for-loop to insert 20 columns. It will insert a column named “1” at column 1, then insert a column named “2” at column 2, etc.
You will get 20 columns with no rows in the table:
Note that if anything goes wrong, you can use the following block to delete all rows and all columns in the table to restart, but make sure you don’t run this block by accident.
Step 10 - Add 20 Empty Rows to the Table
We can also quickly add some empty rows to the table using blocks. Create a new variable “y”, and then use a for-loop like this to add 20 rows:
Now there are 20 empty rows in the table:
Step 11 - Add Some Data to the Table
Now let’s add some letters to the table to represent 3 rows of boxes, with 5 boxes in each row. You can click on any table cell to edit it, and you can also press the TAB key on your keyboard to jump to the next cell on its right.
Step 12 - Define the “Add Box” Block
Now let’s define a new block for adding a new box at a given x/y position. It should take 2 inputs of x and y. In its definition, we will first select the first brick we added named “g”, and then make a copy of it. Note that we need to share data between the original box and the copied boxes, which will save a lot of time and computer memory when we copy many boxes.
We will name each copy using its x and y positions. For example, if x is 5 and y is 6, then the box’s name will be “5_6”. We would be able to manipulate this box later using its name (such as moving or removing it).
Lastly, we will place this box at the given x/y position. Its z position should be -0.05, because its height is 0.1, and we want the top face of the box to be at z position of 0.
Step 13 - Add Boxes Based on the Map Table
Now we are ready to add the boxes for the platform. The idea is that we will read the type of each item in the table, and use a new variable “type” to store this information. Whenever we find an item’s type is “b”, we add a box at that position. Note that we are making use of the fact that the value of “x” is both the column name and the x position, and the value of “y” is both the row number and the y position.
15 boxes will be added as a result:
Step 14 - Change the Camera’s Position
To view the platform more clearly, let’s go back to the Main sprite, and change the camera’s view distance to 9, and change its target position to x of 3 and y of 2:
Now we get this view:
Step 15 - Add Some Gaps Between Boxes
Currently, it is a bit hard to tell the boundary between the boxes of the platform. We can add a small gap between them by shrinking the boxes a little bit. In the Platform sprite, we can change the first box’s size from 1 x 1 to 0.96 by 0.96:
As a result, we can see a clear gap between the boxes:
Step 16 - Add an Anchor for Rotation
Now we are ready to make the player box rotate on the platform. The challenge here is that we can not simply rotate the box around its own center point. Instead, we need to rotate it around one of its edges. The solution is to use a parent object as the rotation “anchor”. When the parent rotates, the player box will be rotated around the parent’s position.
To add the anchor object, we can use a transformer object named “a”:
Step 17 - A Loop for Handling Key Presses
We will allow the player to press keys to rotate his box. Let’s define a new block named “handle keys”, and use a forever loop to check for key presses. We will start with the “d” key:
Note that we are always selecting the player’s box “p” as the sprite object first, since the sprite object might have changed.
Step 18 - Define a “Rotate Box” Block
When the player presses “d”, we need to make the player’s box rotate around its bottom right edge. To do that, we first need to move the anchor object to this point, and then rotate the anchor object around the Y-axis.
To implement this change, we will first define a new block named “Rotate Box”. It will accept 4 inputs, which allow us to specify the x and y position of the anchor object, and also how many degrees to rotate around the X axis and the Y axis:
Step 19 - Rotate to the Right
To rotate the player’s box to the right, let’s determine the 4 inputs we should use.
Suppose the player’s box’s center is at x = 1 and y = 1. Then the anchor point’s x position is 0.5 from the center, which is x + 0.5. The anchor point’s y position is the same as the center point’s y position. The anchor point’s z position should be the z position of the bottom of the box, which is 0.
We will rotate the box -90 degrees around the Y-axis. Since we are not rotating it around the X-axis, we can set it to 0.
Therefore, this is how we should use the new block:
Note that since the player box “p” is selected as the sprite object at the moment, the motion blocks "x position’ and “y position” represent the position of the center point of “p”.
Step 20 - Move the Anchor Object
Now it’s time to implement the definition of “Rotate Box”. First, we need to select the anchor object to move it to the given x and y position. Next, we will select the player box, and then set the anchor object as its parent.
Note that the 2 “select” blocks are very important. They tell the 3D engine which object you would like to work with.
Step 21 - Rotate the Anchor Object
Next, we’ll rotate the anchor point. We can check the values of “x degrees” to see if we are rotating around the X-Axis or the Y-Axis. If it is not 0, that means we are rotating around the X-Axis. Note that we need to select it before rotating it.
Step 22 - Unlink the Anchor Parent
After rotating the anchor object, the player box will be rotated to the new position. We need to unlink it from the parent anchor object, otherwise, its position information will not be accurate.
Now we can give it a try. When we press “d”, the player’s box will be rotated correctly to the right.
Step 23 - Rotate Right Again
When we try to rotate the box to the right by pressing “d” again, we get an incorrect result.
This is because when the box is lying down, the right edge is not 0.5 units away from the box’s center point, but 1 unit away.So how do we know if the box is lying down? We can check the z position of the player box. If it is standing up, its Z position should be 1; when it is lying down, its Z position is 0.5.
Now we can keep rotating the box to the right:
Step 24 - Rotate Forward on “w”
Next, let’s make the box rotate forward when the “w” key is pressed. We can duplicate the blocks for handling the “d” key, and modify it in a few places:
- When we rotate the box forward, the anchor point will be at the front bottom edge instead of the right bottom edge. That means we need to move the anchor object to the same x position as the box, but a large y position.
- We need to rotate the box around the X-Axis instead of the Y-Axis.
Now we can rotate forward as well:
Step 25 - Reset the Anchor Object’s Direction
When we rotate the box to the right 2 times, then forward, we have a problem:
This is a tricky problem. We can see that the anchor object’s position is correct, but it is rotating the box backward, not forward. The reason is that after we rotate the anchor object to the right 2 times, it is upside-down. So when we tell it to rotate forward, it rotates backward.The fix this issue, we simply need to reset the anchor object’s direction every time we use it:
And we can confirm this problem has been fixed:
Step 26 - Rotate Sideways
There is another edge case we have to fix. When we rotate right once, then rotate forward, the box ends up in the air:
This time, the issue is not in the rotation direction, but the position of the anchor point. When the box is lying down, it can be heading forward or sideways. We only handled the former case so far.When the box is lying sideways, to move it forward, the anchor point’s y position should only be 0.5 units away from the box’s center point, not 1 unit.
However, how do we know if the box is lying forward or sideways? We can check its y position. If the box is lying sideways, its y position is a whole number like 1, 2, etc; if it is lying forward, its y position is halfway in between 2 positions, like 1.5, 2.5, etc. So we can check if the y position rounds to itself: whether round (y ) is still equal to y.
And the problem is now fixed:
Step 27 - Rotate Forward Then Sideways
We need to apply the same logic for handling the “d” key: if the box is lying forward, and we roll it to the right, we need to adjust the x position of the anchor point.
And we can test it like this:
Step 28 - Handle the “a” Key
Now let’s copy the logic for “d” key to handle the “a” key. The anchor point’s x position will be to the left of the center of the box, and the rotation angle is 90 instead of -90:
Step 29 - Handle the “s” Key
Lastly, let’s duplicate the logic for “w” key to handle the “s” key. The anchor point will have a smaller y position than the box’s center, and the rotation angle is -90:
Make sure you test all 4 directions thoroughly:
Step 30 - Specify the Goal Position
Now let’s specify where is the goal position on the map. We can use a different letter “g” to represent the position of the goal, and there should be only one “g” in the entire map. For example, we can put it in column 4, row 2:
Step 31 - Add a Box at the Goal Position
In the Platform sprite, when we create the boxes for the platform, we will walk through every item on the table. If we find the item’s type is “g”, we should create a new box to represent the goal position. It will have the same size as the other boxes except for a different color (such as purple).
Step 32 - Make the Goal Box Glow
To make our goal box prettier, we can make it glow. We will need to update its emission color, then create a glow layer for it:
Here is the glow effect:
Step 33 - Check Player Box Position
Now our game is set up for play, and every time after we rotate the player’s box, we need to check its position, and determine if the box should fall or the level is completed.
Let’s start by creating a new block named “Check Position”, which will run at the end of the “Rotate Box” block.
Step 34 - Get Position Type When the Player’s Box is Standing Up
The player’s box is made of 2 cubes. We need to know whether there is a platform box below each cube, or the goal box is below these cubes. We can read this information from the “Map” table.
When the player’s box is standing up (its z position is 1), this is fairly simple. Both cubes of the player box share the same x and y positions as the player box itself. Let’s make 2 new variables “type 1” and “type 2” to represent the item type underlying each cube, and we can set their values this way:
For example, when the player box’s x position is 1 and y position is 2, then we will set “type 1” to the value of the item at row 2 column 1 of the table, which will be “b”. “type 2” will be the same, since the second cube of the player box is also at the same x and y positions.
Step 35 - When the Player’s Box is Lying Left to Right
When the player box’s z position is not 1, that means it is lying down. If it is lying left to right, its y position would be a whole number. In this case, the 2 cubes of the player box would have the same y position as the box itself, and their x positions would be 0.5 units away from the box’s center.
For example, if the box is lying at y of 2 and x of 2 to 3, we would find their position types will both be “b”:
Step 36 - When the Player’s Box is Lying Front to Back
In the last case, the player’s box is lying front to back. The 2 cubes would have the same x position as the box, and their y positions would be 0.5 units away from the y position of the box.
For example, in this picture, the 2 cubes are at x of 4, y of 2 and 3. So the types of bricks below them are “g” and “b”:
Step 37 - Enable Physics
So far we have not used the physics engine at all. So long as the player’s box is landing on the platform properly, we only need the rotation animations. However, when the player’s box should fall off the platform, we would need to use the physics engine to make the fall look real.
To use the physics engine, let’s make a few changes:
- Enable physics for the scene in the Main sprite:
- In the Platform sprite, attach a physics body to the first box we create. This way, all copies of it will have a physics body automatically. Note that the “mass” has to be 0 to ensure these bricks do not fall.
Step 38 - Make the Player’s Box Fall
When the player box is standing up, it has to be on top of a platform brick. If the player’s box is lying down, then both cubes of it have to be on top of some platform bricks.
Therefore, when we review “type 1” and “type 2”, if at least one of them is empty, then we know the box should fall. To make the box fall, we simply need to attach a physics body to it.
Now we are getting a good falling effect:
Step 39 - Checking for Level Completion
How do we know when the player has completed the challenge? The box should be standing over the goal area, which means both “type 1” and “type 2” should be “g”.
When that happens, we should also make the box fall by attaching a physics body to it.
Now the box will fall through the goal area:
Step 40 - The Level Complete Message
When the box falls through the goal, we should also show a message for “level complete”. We can use a label to do that:
It will pop out like this:
Creative Ideas
Although this game is very simple, you can extend it in many ways. Here are some ideas worth trying:
-
Change the Level Map: You can change the map of the platform very easily by changing the “Map” table. You can add more rows and columns if you need to.
-
Multiple levels: when the user completes a challenge, you can reset the platform to a more difficult map.
-
Buttons: You can add buttons on top of some bricks, and when the player’s box lands on those bricks, it triggers some bricks to be added or removed, such as a bridge between 2 parts of the platform. To implement this idea, you would need to dynamically change the content of the Map table.
-
Blockers: You can use a different color for some bricks of the platform, and when the player’s box lands on any of these bricks, it will bounce back to the previous position.
-
Leaderboard: You can keep track of the number of moves made by the player to complete the level, and show that in a leaderboard.
-
On-screen Buttons: You can add some buttons for rotating the player’s box to the stage so that the game can be played on touchscreen devices.
Below is a game that demonstrates some of the ideas above:
https://play.creaticode.com/projects/77083f9840c1f919563357ff
-
-
@info-creaticode said in 3D - Bloxorz Game (Difficulty 6):
Below is a game that demonstrates some of the ideas above:
https://play.creaticode.com/projects/77083f9840c1f919563357ff