Diagonal Movement and Movement Speed
This is the third part of my dev log on implementing diagonal movement in your RPG Maker VX Ace project.
In the first part, we modified the movement scripts to allow diagonal movement and to use diagonal sprites as needed.
In the second part, we implemented interactions between characters such as diagonal event triggering and facing towards or away from characters diagonally.
At this point, you should have fully-functional eight directional movement. One thing that you may notice while you are moving around the map is that if you are moving diagonally, you appear to be moving twice as fast compared to moving orthogonally. This may or may not be a bug, but we will look at why that happens and how we can address it.
Diagonal Distance
Suppose you were standing on one tile and you wanted to move to another tile. You might choose to move to the right, or move to the upper-right.
Each tile is one unit in width and height. The amount of distance required to travel from the centre of the current tile to the centre of the tile on the right is basically one unit.
What is the distance between the centre of the current tile, and the centre of the tile on the upper-right? Is it one tile?
Triangular Geometry
This is the same question shown above, except modeled after a triangle.
If you were to claim that the distance between A and C is equal to the distance between A and B, you would be wrong. Here’s why. Using the Pythagorean equation, the distance between A and C is square root of 2. Which is not 1, but closer to 1.4142.
Adjusting Diagonal Movement
There are two rules that you should follow when you make a move:
- You are moving at a constant speed. Your speed doesn’t change just because you move in a certain direction.
- You will move to another tile. Doesn’t matter whether you’re moving orthogonally or diagonally, you will always successfully move to another tile. You will never stop between two tiles.
So how do we account for this extra distance between two diagonal tiles?
In Game_CharacterBase
, there are two methods related to movement:
def real_move_speed @move_speed + (dash? ? 1 : 0) end def distance_per_frame 2 ** real_move_speed / 256.0 end
One method determines your current move speed based on a number of factors, such as whether you’re dashing or not. The other method determines how much distance you cover per frame.
So basically you can change how fast you move to another tile, or you can change how long it takes to move to another tile.
If you think about how you move in real-life, do you suddenly move slower or faster if you were walking diagonally? Not really. So the amount of distance you cover in a constant amount of time at a constant speed is always equal. This statement should be obviously true in our 2D world.
Therefore, in order to cover more distance at the same speed, you would need more time.
From the math that I showed above, the amount of distance that you need to cover is approximately 1.4142 times more to reach a diagonal tile compared to an orthogonal tile. Thus, the amount of distance you cover per frame should be 1.4142 times less when you are moving diagonally.
This leads to the following solution:
class Game_CharacterBase def distance_per_frame s = 2 ** real_move_speed / 256.0 return @direction % 2 == 0 ? s : s / 1.41421356237 end end
A little note on the choice of numbers. First, square root is an expensive operation. The square root of 2 has no finite expansion (I think), so you will never be perfectly accurate anyways due to how computers work. Also, because the distance covered per frame typically only goes to the 6th decimal place, any precision beyond that is not too useful. You could probably just stick with 1.4142 and it would be “good enough” for our purposes, but there is no harm in being more precise in your calculations, so I left some more decimal places in.
Add this to your script, and when you test it in game, you should feel the diagonal movement and orthogonal movement are equal in speed.
Summary
Intuitively, it should take more time to move to a diagonal tile than it does to move to an orthogonal tile. And indeed, you will see that without accounting for difference in distance, you would essentially move faster if you moved diagonally, which some players may notice as a bug when they can easily out-runs by running diagonally all the time.
With just one line of code, we have cleanly addressed this issue.
The eight-directional movement script can be found here.
Credits
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.
Yes, I haven’t figured out how to deal with it.
Did you notice that followers look a bit skippy when following with diagonal movement?