Build an isometric 3D game in 2D — #5 More order and move sync

This is part 5 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:

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

In the last 4 tutorials, we’ve built a working mechanic that lets a movable move freely on an empty board, even the board has some unmovable here and there.

The problem

If you set the board like this:

run the game and hit ‘Z’, you’ll see:

the one V3(0,0,0) will stay still, but this is not what we want, so let’s figure out how this happened and how to solve this.

When we creating movables, we will add them to the group “movables”, and when we issue a command to make them move, we call the command function in their states one by one, the order of calling the command function is the order we create them, that’s :

This means when the V3(0,0,0) receives the command, both V3(0,0,1) and V3(1,0,0) have not run their set_next_target function in move state yet, which means they haven’t set their game_pos to their correspond target_game_pos, which makes the V3(0,0,0) think there’s a block in front of it and a block right above it, so it stays.

Then this is a similar problem that we solved in the second part of this series, but this will be a bit tricky to solve.


We need to call the command in a custom order so that we can issue commands and update them correctly, to do that, let’s create a custom script to write codes for that:

We can call the corresponding function according to the key pressed, and we can calculate the correct order by using the sort_custom function in Array:

Sorts the array using a custom method. The arguments are an object that holds the method and the name of such method. The custom method receives two arguments (a pair of elements from the array) and must return either true or false.

Note: you cannot randomize the return value as the heapsort algorithm expects a deterministic result. Doing so will result in unexpected behavior.

Add a function in

And in :

also in the update function:

Run the scene:

The V3(0,0,0) moves at the beginning. But the V(0,1,0) will fall in the middle of the road, let’s see if we can fix that.

Move sync

As we discussed in the 3rd part of this series, we know that the movable moves in a vector 2 direction but they are in a grid-based board, so after each update, they may not end up in the exact engine location, so they may not reach the target_engine_pos the same time, that causes the fall.

Then we need to sync the movements of the movable, we’re gonna use signal to do that, add these to

and in the, we will call the send command to tell the movable when one of them reaches the target:

  • and connect the movable.block_rach_target signal to movable_into_idle function when creating it.

And call reach_target function every time the block reaches the target, we need to modify move, jump, fall states., replace _update, add _command:

and same for also:

And run the scene, you will see:

they move as expected, but you may see some of them wobble a little bit, that’s because when a movable emits signal “block_reach_target” all the movable get set to their target_engine_pos, but in the _physics_process function of, it may be in the middle of an update, so some movables will move one update cycle faster than others.

this can be fixed by this, use a block_reached_target variable, and set it to true when block_reach_target gets called, and _physics_update will update movables accordingly:

and no more shaky movables.

That’s it for this article, next article will be the finale of this series, we will be testing a lot and adjusting the behaviors of the movable to make the movement feels natural.

You can find all the textures, scripts in this GitHub repo: