Build an isometric 3D game in 2D — #3 Make blocks move

This is part 3 of the 2d/3d(game/engine) conversion used in my puzzle game: Ladder Box, which is available on Steam:

You can find all the textures, scripts in this GitHub repo: https://github.com/fengjiongmax/3D_iso_in_2D

Godot 3.2.x is used in this project, you can check the commits for what’s new in each part of this series.

===

Before we make more changes to movable and unmovable scripts:

name movable Movable and add every movable to group “movable”:

name unmovable Unmovable:

Store the grid content

We need to know what’s on our board and their position, and a place that stores this information, I’m putting this in the global Grid(grid.gd).

To make things more organized, let’s move something that can be calculated statically into another script.

Create a script call grid_utils.gd:

then grid.gd after clean up and adding some function related to the grid content( which can not be accessed by static function):

  • ‘game_arr’ is the variable that stores our grid content.
  • the board size is V3(8,8,8)

Change ‘set_game_pos’ in block_base.gd :

Finite State Machine

We will be using a finite state machine to make those blocks move the way we want. You can learn about the concept of FSM here.

First, we need to define the states for those movable blocks.

1. Idle

This is the initial state for our movables, and when they end their movement standing still.

2. Move

When we issue commands to make them move in four directions.

3. Jump

When blocks meet one block higher than their current game_pos.y, they will enter this state, and then they will continue moving in their direction, or fall to their previous position.

4. Fall

Fall to game-pos.y - 1.

======

That’s all the states for movable. In this part, we’ll get idle and move states work.

Code for FSM

Let’s first create scripts for state machine and state base class.

state_base.gd:

state_machine.gd:

create nodes for states in the movable scene:

In the inspector, assign the initial state to ‘idle’.

and attach scripts to all those states that extend our StateBase class:

Send command to movable

We’re gonna use ‘a,s,z,x’ to navigate our movable:

Let’s handle input in our main scene, then send command to movable to make them from idle to other states.

And add the function to handle input to send the command, in main.gd:

  • also add ‘set_process_input(true)’ at _ready

In idle.gd:

Now we switch to the move state once we send the command in idle state, if we add something in _enter function of move.gd:

And run the scene, you should see the output :)

At the _enter function of the move.gd, we will calculate how the movable move in the engine by the given direction, also the “next position” when the movable moved one block along that direction, I choose to make the calculation in a separate function called set_next_target, the “next” related variables will have a prefix “target”.

Now edit the move.gd:

Run the scene and hit z:

it moved.

But we don’t want them to move to the next block at once, we want them to move to their target gradually.

Edit block_base.gd:

  • separate the original set_game_pos into two functions

and change new_movable and new_unmovable in main.gd:

change set_game_pos to initial_game_pos.

Then we need to make movable moves in _update function in the move.gd, but before we do that, we know the blocks move in a Vector 2 direction, and they are moving in a grid, but the distance of each update may vary, so after an update, the result of the movement may be:

  • haven’t reached target_engine_pos yet.
  • movable.position = target_engine_pos
  • movable has moved over the target_engine_pos.

So in the last two situations, both should be labeled movable has reached the target position, let’s create a script to help us do this:

In math.gd:

Before we edit move.gd, we can define a constant in movable.gd to define the move speed, I’m setting this to 2( this is slow but you can see the movement):

Then we can add the _update function in the move.gd:

Run the scene:

The gif is slower than the running scene, but it works as expected.

That's it for this part, you can check out the Github repo for the code committed, to make it work as in Ladder Box, we still have a long way to go.

Stay tuned!