3
\$\begingroup\$

In a tile-based 2D RPG, a character is supposed to walk into all eight directions.

However, if we blindly tell the player to move in the direction (1, 1), he will be around 41% (√2-fold) faster. Thus, my next idea was to normalize the direction vector before moving.

Unfortunately, since the vector (1, 1) normalizes to (√2 / 2, √2 / 2) ≈ (0.71, 0.71), but the game functions on a whole-pixel basis, this will make the player reach invalid 2D locations. My next idea was that I should just make diagonal movement slower by √2 somehow.

So next, I tried another approach: When I receive an input and the player isn't already walking, I set the player's destination point. Then, I compute how much of his way to the destination the player can actually walk in one frame, given the player's velocity in "pixels per frame". I will repeat the player position update every frame, until the destination is reached.

So for example, if the player needs to move from the origin (0, 0) in the direction (1, 1) at speed 1, his sprite will be displayed at (0.71, 0.71) after one frame, and in the next frame it snaps to his destination (1, 1). This is okay, because the player ends up at a valid coordinate.

While this last approach sounds okay, it has only created more problems, because now diagonal movement takes two frames, and orthogonal movement takes only one frame. In other words, the walking speeds are still not equal.

How do you usually solve this?

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Have you actually confirmed that this is a problem for you? Just asking I've never encountered this problem myself when using vector based movement. \$\endgroup\$
    – Charanor
    Jun 7, 2017 at 21:07
  • \$\begingroup\$ @Charanor I have, yes. \$\endgroup\$
    – Chiru
    Jun 7, 2017 at 21:10
  • \$\begingroup\$ represent the position and velocity internally with float and convert to integer pixel coordinates when you need to for display \$\endgroup\$
    – Jimmy
    Jun 7, 2017 at 21:50
  • \$\begingroup\$ A common workaround is a hex grid. \$\endgroup\$
    – Peter
    Jun 7, 2017 at 22:04

2 Answers 2

1
\$\begingroup\$

There are multiple workarounds.

  • Don't base movement on screen pixels. Base movement on a finer grid (e.g. use float), and only snap to pixels for display.
  • Declare faster diagonal movement a "feature" of the game.
  • Use a hex grid.
\$\endgroup\$
0
\$\begingroup\$

Sounds like it's working fine to me. The real issue here is that, for some moves, you arrive at the destination with "extra time" in the frame. In that, if you were moving farther, you could, for example, move 1.5 units in two frames. Essentially, it's a rounding issue. For the example you picked, it appears that the player would arrive at the same time, two frames, even if they moved left then up as compared to moving diagonally left+up. However, it only appears that way because you've reached the bottom of your time resolution. You can't have sub-frames, so you have no choice but to waste the "half a frame" you saved by going diagonal.

I think in practice, you're likely not going to be dealing with examples so close to your time resolution. This is what @Charanor is getting at when they suggest you determine if it's even a problem. It's not likely a problem because you're likely not going to moving at 1 unit per frame. You'll be moving something much slower than that, so the frame resolution is much less of an issue.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .