Workinging with positions on 2D tile-based game

I paste my stackoverflow question here, since I think It fits more this community:

Lately, I have started working on a simple MMORPG 2D tile based world (for learning purpose only) written in C# for both server and client.

I started working on the server (networking, messages encoding/decoding and ect’), and assumed 2 integer will be sufficient for sprite positions.

My pros for using integers:

  • Easy mapping sprite <-> tile.
  • Reduce used memory for client updates (bandwidth): on neighbor sprite move, I can send only the delta offset from the previous location - one byte for each offset (X & Y).

On the other hand, when I reached the client implementation, I couldn’t figure out how to implement smooth scrolling and move speed, since the position on every update are two integers, which are bound to specific location inside a tile (using Camera2D transformation).

I want to be able to see sprite movements between tiles, based on the sprite speed (and tile type).

My camera code:

public class Camera2D
{
    private Vector2 _pos;
    private int _viewportWidth;
    private int _viewportHeight;
    private float _textureWidth;
    private float _textureHeight;

    public Matrix Transformation
    {
        get
        {
            return Matrix.CreateTranslation(new Vector3(-this._pos.X-this._textureWidth/2, 
                                                        -this._pos.Y-this._textureHeight/2, 0)) *
                   Matrix.CreateTranslation(new Vector3(this._viewportWidth * 0.5f, 
                   this._viewportHeight * 0.5f, 0));
        }
    }

    public Camera2D(int viewportWidth, int viewportHeight, float tlieWidth, float tileHeight)
    {
        this._viewportHeight = viewportHeight;
        this._viewportWidth = viewportWidth;
        this._tileHeight = tileHeight;
        this._tileWidth = tlieWidth;
        this._pos = new Vector2(0, 0);
    }

    public void Follow(Sprite sprite)
    {
        this._pos.X = sprite.Position.X;
        this._pos.Y = sprite.Position.Y;
        this._textureWidth = sprite.Texture.Width;
        this._textureHeight = sprite.Texture.Height;
    }
}

My tiles data structure looks like:

Tile[,] _mapTiles;

Where:

class Tile
{
    private int _id;
    private List<Character> _standingCharacters;
    private ViewPoint _viewPoint;
}

I thougt about sending clients the sprites’ speed and make all the simulation in the client, but I don’t think it’s feasible due to the difference of clients’ network, which will cause to massive synchronization problems.

My moto so far: the server should relies only on itself and be responsible for the simulation, while the client will get updates and render based on them (and internal client prediction).

How do you think I should tackle the described problem?

Thanks!

Edit:

I had another idea and I would like to see your feedback:

I can manage in addition to the 2 integers (X,Y), additional in-tile offset in size of two bytes (for X and Y axis):

Position(X,Y,inTileOffsetX,inTileOffsetY) = (X + inTileOffsetX / 128,Y + inTileOffsetY / 128).

The speed can be controlled via the inTileOffset updated value, meaning I will have maximum 128 possible speed rates.

Skim read your post, sorry.

Can’t you just lerp over time with floats between starting position and final position?

If you are networking motion, then send the velocity, as if you have missing packets, at least you have the last known velocity, and if the drop is small the lag may be less noticable.

Thanks for your answer.

If I understood correctly, you suggest making the tile movement simulation in the clients as well as in the server, while sending start and end location as integers.
If the speed is changed during a movement, the clients will be updated as well.

Don’t you think it will make the client rendering more error pruned and sensitive to network latency?
Another point: floating points has some problems like being undeterministct on some platforms, or precise in large numbers, don’t you think my offsetInTile solution should be better?

Thanks again :slight_smile:

1 Like

I think stick to your integers, for final position, but you can lerp from the starting position to the end position with floats during movement is all. I imagined your server is sending current position, the clients get that then move from it’s last known current position to new server position. Floating point accuracy would be an issue at v large or small values yes, so I guess you could get motion artifacts this way…

If you have network latency, you are screwed anyway, if you have current velocity you can at least have a decent bet of where the sprite is going rather than just stopping the sprite where the lag occured :slight_smile: Sending position as well as velocity might help with hiding lag or missed packets.

Thank you very much!

I decided to take both solutions:
I will simulate at the client, and in the server I will also keep one byte for offsetInTile, so if new player will spawn, he will be able to see immediately his neighbor movement.

The movement can be very slow, since I want to be abled to support paralyzed effect of players (which will take movement couple of seconds).

1 Like