1
\$\begingroup\$

I'm having a problem with mapping logical coordinates to graphical ones when my character is walking. I've been able to map them without the graphical walking in between, i.e it just "jumps" from one tile to the other.

The logical coordinates are represented such as [0,0], [0,1] etc. and a character can only be in one of these tiles at a time. I want my character to graphically move from one tile to the next at a given speed/pixels per rendering update until it hits the logical tile's graphical position.

If I didn't phrase myself good, please don't be afraid to tell me.

\$\endgroup\$
4
  • 1
    \$\begingroup\$ Most tutorials use something like OffsetX, OffsetY in addition to your PoisitonX and PositionY. When you walk you increase your Offset until its equal to tilesize and then you increase position and reset offset. And you draw to Position * TileSize + Offset \$\endgroup\$
    – Kikaimaru
    Commented Aug 8, 2013 at 11:44
  • \$\begingroup\$ Thank you. I implemented a solution with offsets but I don't like that it mixes graphics and logic too much. Maybe you could give me a hint on how to do it better? \$\endgroup\$
    – Oakin
    Commented Aug 8, 2013 at 13:01
  • \$\begingroup\$ Personaly I use absolute position as logical position even if game is tile based. And then I have getter that will recompute absolute position to tile position (for collisions etc). \$\endgroup\$
    – Kikaimaru
    Commented Aug 8, 2013 at 14:45
  • \$\begingroup\$ It's best to separate questions and answers. Why not put your solution as an answer? \$\endgroup\$
    – House
    Commented Aug 8, 2013 at 16:42

2 Answers 2

2
\$\begingroup\$

Probably I should ask this as a comment, but I'm not yet allowed to. So I'll blatantly formulate this as a semi-answer.

It sounds like entity.getX() is returning an integer between [0, maxTileNumberX] representing the tile position. In the end you're trying to interpolate the movement between getX() and getX()+1 using integers only. Why not make xOffset a float between [0,1]? Then do the calculation

Math.round((entity.getX() + entity.getXOffset()) * tileSize)

Of course this means speed must also be a float and scaled appropriately. Is there a reason not to use float? If you want to decouple the logic and graphic, that would be the first natural step. Only the graphic layer needs integers, the logic should be allowed to operate with its own data types suitable for the problem.

\$\endgroup\$
1
  • \$\begingroup\$ My solution is similar to that, check my own answer for how I did it. Cheers for your answer by the way. \$\endgroup\$
    – Oakin
    Commented Aug 9, 2013 at 7:23
0
\$\begingroup\$

Alright, I think it's time I posted my solution as an answer(thanks Byte56). It's not the prettiest but it works well enough for me.

I basically have a method for moving in the different directions. The goal variables are the tile we want to move to. In the next iteration of the game loop the entity's update method will take care of the goal variable.

/**
 * Move the entity right.
 */
public void moveRight() {
    if(goalY == y) {
        goalX = x+1;
        horizontalSpeed = speed;
        //  resetGoalY();
    }
}

I got a bug with this method that I will fix later on but I think it's good if you get the bigger picture of how my movement works. As long as goalX != x we will update the offset on each axis with the given speed. Note that the two different speeds can either be negative or positive depending on what direction we want to go. I then check if the offset equals the maximum offset (in my case, this is the tile size) and seeing as it can be either tilesize or -tilesize I will check with Math.abs which gives the absolute value of the values. If the values are equal it's time for the logic to move to that tile and I then reset the offsets.

/**
 * Update the entity's movement.
 */
private void updateMovement() {
    if(map.isTileWalkable(goalX, goalY)) {
        if(goalX != x) {
            xOffset += horizontalSpeed;
        }
        else if(goalY != y) {
            yOffset += verticalSpeed;
        }

        if(Math.abs(xOffset) == maxXOffset) {
            resetXOffset();
            x = goalX;
        }
        else if(Math.abs(yOffset) == maxYOffset) {
            resetYOffset();
            y = goalY;
        }
    }
}
\$\endgroup\$

You must log in to answer this question.

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