I made a clone of Mekorama, a tower-based puzzle game.
The player solves puzzles by leading a robot to the finish-block. The player can drag movable blocks on pipes to complete a path, and click on a block to move the robot. The gameplay is showcased in the video below.
( Mekorama Clone's gameplay video )
Pick Buffer &
Three-dimensional Heat Map
Data driven using XML definitions
The original game is made for touchscreen devices; thus it meant to use touch and swipes as a primary input. Which gave me an opportunity to work with similar mouse-based inputs: click and drag. To make it work, I used these techniques:
Use a Pick Buffer for detecting which block is clicked.
Do vector calculation in Screen Space when the player drags a block, to move it.
1. Pick Buffer
It is a powerful tool to get the game object directly based on its screen-space position. On a mouse click, I generate a pick buffer which provides Pick ID of the game object at cursor's position. Now I can easily get a pointer of selected block from a dictionary, where I keep a record of each game objects and its Pick ID. Take a look at the code given below.
( Code for getting the clicked block from Pick Buffer )
Pick ID being an unsigned integer, its size is 4 bytes, which is the same as the size of an RGBA color. So, the Pick ID number can be used as a color code, unique for each game object. When I generate a pick buffer, a special material is used to render every game objects of the scene just using its Pick ID color. In doing so, I need to make sure that due to the alpha value, two colors are not blended together. Otherwise, it'll produce the wrong results. Following screenshot shows a render pass of the pick buffer, where each block is rendered in a slightly different shade of red color.
( Showcasing the render pass when a Pick Buffer is generated )
To get which object is selected, the pick buffer needs to fetch color at the given screen position and return it as an unsigned integer (Pick ID).
2. Vector calculation in Screen Space
When the player is performing a drag gesture, calculations of moving a block on its pipe happens in Screen Space. The block is moved based on a dot product between the pipe's direction and the displacement in the cursor's position. I call it the drag distance, which is calculated by the following method.
( Method for getting clicked block's drag distance )
The robot does path-finding using a three-dimensional heat map. The clicked block is considered as a target. When generating a heat map, the target gets the lowest heat-value: zero. In screenshots given below, heat-values for all blocks, which can lead to the target, are rendered in white text. As long as the robot keeps moving to a neighboring block which has lower heat-value, it will reach to the target.
( Numbers indicates how many steps it would take to reach at specific block )
A level is constructed using its XML definition. It includes the information about which puzzle-tower to construct, where to spawn the robot and where the finish block should be.
( XML definition of a level )
( A part of tower's XML definition )
Similarly, a tower is constructed using its definition which contains the layout of blocks for each layer, and the information about pipes on which draggable blocks can be moved.
On the construction of a tower, all the blocks are constructed using their respective definitions. Block definition contains rendering information, gameplay properties, as well as its name.
( XML definition of water block )
( XML definition of red brick block )
( XML definition of draggable metal block )
As you can see in definition, the player can not select a water block because of the value of isSelectable. A robot can't stand on a water block because of the value of its isSolid property. Both of these values being true for red-brick block means that the player can select it as well as the robot can stand on it! Similarly, a metal block can be moved on a pipe because the value of isDraggable boolean is true, in its definition.