1
\$\begingroup\$

I have this tilemap and a player in my game, and I got the player to move by adding the velocity to the position. However, it is very hard to control the player exact this way of the tilemap. So, I began trying to do something like the old final fantasy games did (and a heap of other games too): moving tile by tile, but making it look smooth.

However, I failed. So, if anyone have any idea of what the best way to make the player move tile by tile is, then shout out. If you have played final fantasy V for example, then that's the kind of movement I want to try to implement in my game.

To explain it a bit further; each tile in my game is 16x16, so is the player. I don't want the player to "jump" between the tiles, but I want it so that say, if you press "A", then move the player to the tile to the left in a smooth way.

I tried something like this:

    private Vector posA;
private Vector posB;
private double time = 0.6 / 60;
private void move(Direction dir) {
    if (!moving) {
        //Initialize Movement
        posA = new Vector(position);
        posB = new Vector(position);

        switch (dir) {
        case UP:
            posB.subtract(0, 16);
            break;
        case DOWN:
            posB.add(0, 16);
            break;
        case LEFT:
            posB.subtract(16, 0);
            break;
        case RIGHT:
            posB.add(16, 0);
            break;
        }

        moving = true;
    }

    //Update Position
    if (moving) {
        Vector v = new Vector();
        v.set((posA.x + (posB.x - posA.x) * time), (posA.y + (posB.y - posA.y) * time));

        //Set  Position
        position.add(v);

        if (position.x >= posB.x && position.y >= posB.y) {
            position.set(posB);
            moving = false;
            System.out.println("DONE MOVING!!!");
            posB = null;
            posA = null;
        }
    }

}
\$\endgroup\$
0

1 Answer 1

0
\$\begingroup\$

The problem is here:

if (position.x >= posB.x && position.y >= posB.y) {

This will only work if moving in positive X and/or positive Y. When moving the other way posB will be smaller than position and the character will stop right away.

Also, you keep adding the new position to position when you should be adding the delta

v.set((posA.x + (posB.x - posA.x) * time), (posA.y + (posB.y - posA.y) * time))

Try changing it to something like

int time;
int steps;

...

if (!moving) {

  ...

  time = 0;
  steps = 16;
}

...

if (moving) {

  ++time;

  position.set((posA.x + (posB.x - posA.x) * ((float)time / (float)steps))), (posA.y + (posB.y - posA.y) * ((float)time / (float)steps)));

  if(time >= steps){
   // stop 
   moving = false;
  }
}

Using an integer variable for N number of steps is the correct way to interpolate as floats accumulate errors, especially when you want to hit an exact target like the next 2D tile. Otherwise your characters can become more and more misaligned.

I'm incrementing time before calculating the positions so that we hit 16/16 and don't need to force the position to posB at the end.

\$\endgroup\$
0

You must log in to answer this question.

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