This article explains how to introduce diagonal movement into RPG Maker. By default, RPG Maker assumes characters can only face four directions. Although there is support for eight directions, it is not implemented.
We start by seeing how we can turn our four-directional movement into eight-directional movement.
RPG Maker uses numbers to represent each direction.
1 - down-left 2 - down 3 - down-right 4 - left 6 - right 7 - up left 8 - up 9 - up right
If you have a keyboard with a numpad, you might notice the directions correspond to the layout, with 5 in the center.
Handling Direction Input
RPG Maker provides two ways to check your direction.
- Input.dir4. This returns the number corresponding to 4-directional movement.
- Input.dir8. This returns the number corresponding to 8-directional movement.
When you press one key, it will be a 4-dir move. When you hold down two keys, the game will automatically find which two keys you’re pressing and calculate the appropriate direction value.
Note that if you hold two keys and use dir4, the game will simply round it off to one of the 4-dir directions.
Performing Diagonal Movement
RPG Maker already supports diagonal movement. They come with the move route editor. This means that most of the work is done for you: all we need to do is call it.
Here is the signature for diagonal movement, defined in
#-------------------------------------------------------------------------- # * Move Diagonally # horz: Horizontal (4 or 6) # vert: Vertical (2 or 8) #-------------------------------------------------------------------------- def move_diagonal(horz, vert)
One of the easiest places to start is converting the player’s 4-dir movement into 8-dir movement. Going through the scripts, we see that movement input is handled like this
def move_by_input return if !movable? || $game_map.interpreter.running? move_straight(Input.dir4) if Input.dir4 > 0 end
There are some conditions that prevent you from moving, but other than that, if you press any of the direction keys, you will move straight in that direction.
Instead of working with 8 directions directly, you instead pass in the orthogonal movement for each axis. So let’s rewrite the
move_by_input method as follows
def move_by_input return if !movable? || $game_map.interpreter.running? return if Input.dir4 == 0 return move_straight(Input.dir4) if Input.dir8 % 2 == 0 case Input.dir8 when 1 return move_diagonal(4, 2) when 3 return move_diagonal(6, 2) when 7 return move_diagonal(4, 8) when 9 return move_diagonal(6, 8) end end
Instead of using 8 different cases, I simply checked if it was even or not. If it’s even, then it’s one of the orthogonal movements. If it’s odd, then it’s diagonal movement.
At this point, you can test your game and see that you do move diagonally.
Updating Character Direction
When the character is moving diagonally, you want to properly update the character’s direction. This is how the method is defined by default
def move_diagonal(horz, vert) @move_succeed = diagonal_passable?(x, y, horz, vert) if @move_succeed @x = $game_map.round_x_with_direction(@x, horz) @y = $game_map.round_y_with_direction(@y, vert) @real_x = $game_map.x_with_direction(@x, reverse_dir(horz)) @real_y = $game_map.y_with_direction(@y, reverse_dir(vert)) increase_steps end set_direction(horz) if @direction == reverse_dir(horz) set_direction(vert) if @direction == reverse_dir(vert) end
Because the default engine uses 4-dir movement, all directions are stored in four directions. You can see that it simply picks one of the orthogonal directions. If we are changing to 8-dir movement, we can now store our actual diagonal value in the direction. For compatibility purposes, I decide to take the long way around:
class Game_CharacterBase alias :th_8dir_movement_move_diagonal :move_diagonal def move_diagonal(horz, vert) th_8dir_movement_move_diagonal(horz, vert) if horz == 4 if vert == 2 set_direction(1) elsif vert == 8 set_direction(7) end elsif horz == 6 if vert == 2 set_direction(3) elsif vert == 8 set_direction(9) end end end end
Inserting Diagonal Sprites
Your diagonal movement works, but it doesn’t look very good. Let’s use some diagonal sprites. I grab some Kaduki Sprites and put them together like this
For convenience, I stick with Ace’s 8 groups per sheet format and place the diagonal sprites right beside the orthogonal sprites.
Now if you just stick this in your project and assign it to your actor, it won’t work, because the engine doesn’t know how to use it.
How Movement Sprites Work
We need to understand how the engine figures out which sprite to draw. The answer lies in
def update_src_rect if @tile_id == 0 index = @character.character_index pattern = @character.pattern < 3 ? @character.pattern : 1 sx = (index % 4 * 3 + pattern) * @cw sy = (index / 4 * 4 + (@character.direction - 2) / 2) * @ch self.src_rect.set(sx, sy, @cw, @ch) end end
There are a lot of different properties being used. See this diagram:
- Index – Which block of sprites to use
- Pattern – frame in the animation
- Direction – character’s current direction
Recall that in Ace, you can have 8 blocks of character sprites per sheet. This is what the index is for. The math is used to take all of those values and figure out which region on the spritesheet should the sprite be copied from.
We need to decide on a format to use for our spritesheets. Once we have chosen a format, every movement spritesheet must follow that format. For simplicity, let’s just place them side-by-side, since that’s what the sheet I found comes with.
We have something like this
So basically, we have our orthogonal movement as index 0, and our diagonal movement as index 1. Now the question is how all of the calculations from above can be used to figure out whether we want to use orthogonal or diagonal, and which is direction to use.
We notice a relationship between the orthogonal movement and diagonal movement.
For directions 1 and 2, we use the top row.
For directions 4 and 7, we use the second row.
For directions 6 and 3, we use the third row.
For directions 8 and 9, we use the fourth row.
Now, there is an easy way to calculate this. We use the follow formula
for even dir, use dir for odd dir, use dir * 2 % 10
So when we are moving in direction 7, the row to use is equal to
7 * 2 % 10 = 4, and so when the engine sees 4, it will know to pick the second row.
This math isn’t really necessary. You could just as easily use a set of conditional branches.
Updating the Sprite or the Character?
At this point, you as the scripter have to make some more decisions. We know that we need to update the index and the direction, but there are two places where this can be done.
- `Game_Character` – these objects stores all of the properties
- `Sprite_Character` – these objects take the characters and draw them
Game_Character, the direction is set whenever you move. This value should accurately reflect the character’s direction, in case you need to use the direction for other purposes (and there are quite a few cases where we actually need a character’s direction)
I would prefer to modify the sprite method. As mentioned above, we need to handle the orthogonal and diagonal cases separately, so I simply overwrote the method completely:
class Sprite_Character < Sprite_Base def update_src_rect if @tile_id == 0 if @character.direction % 2 == 0 index = @character.character_index pattern = @character.pattern < 3 ? @character.pattern : 1 sx = (index % 4 * 3 + pattern) * @cw sy = (index / 4 * 4 + (@character.direction - 2) / 2) * @ch self.src_rect.set(sx, sy, @cw, @ch) else index = @character.character_index + 1 # add one, as per the specs pattern = @character.pattern < 3 ? @character.pattern : 1 sx = (index % 4 * 3 + pattern) * @cw sy = (index / 4 * 4 + (((@character.direction * 2) % 10) - 1) / 2) * @ch # our new formula self.src_rect.set(sx, sy, @cw, @ch) end end end end
Now that we have updated the character’s direction to reflect 8-dir, and the sprite knows how to render the character, we should have a pretty good 8-dir movement behavior.
Other Character Objects
The player is only one type of character. We also have events, followers and vehicles. However, because they all use the same methods that we have customized, they will automatically support proper 8-dir movement as well!
One thing you will immediately notice is that you can’t trigger events diagonally. I will cover this topic in a later tutorial, where we look at how a simple direction affects whether an event is triggered or not.
The purpose of this tutorial was to demonstrate how you can implement 8-dir movement in your game. Basically
- Modify the player input to support 8 directional input
- Store the player’s direction
- Update the sprite to use the new format
This can be done in any number of ways. I have shown one way, but it may not be the most optimal or compatible way. A copy of the script can be found here.
While we have successfully introduced diagonal sprites, we have revealed issues with other aspects of the engine. Because the engine assumed everything was 4-dir, all of the logic involving character direction is based on this assumption. There are still several other things to cover before we have a fully functioning 8-dir movement script.
All of the sprites shown in the screenshots are taken from this website: http://usui.moo.jp/rpg_chadot.html
Spread the Word
If you liked the post and feel that others could benefit from it, consider tweeting it or sharing it on whichever social media channels that you use. You can also follow @HimeWorks on Twitter or like my Facebook page to get the latest updates or suggest topics that you would like to read about.