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\$
  • 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 '17 at 21:07
  • \$\begingroup\$ @Charanor I have, yes. \$\endgroup\$ – Chiru Jun 7 '17 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 '17 at 21:50
  • \$\begingroup\$ A common workaround is a hex grid. \$\endgroup\$ – Peter - Unban Robert Harvey Jun 7 '17 at 22:04
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\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.