Move sprite like in Pokémon

有些话、适合烂在心里 提交于 2019-12-11 12:08:45

问题


I have a game, where I want my characters to move in my field square by square, like in Pokémon.

With the code I have, it is moving square by square just it skips on every key hit about 4-5 squares. And just jumps around.

Can someone help me to get my code work in a similar manner like Pokémon?

The code I have is as follows.

public class Map {

    private Map() {
        Position = new Vector2(0, 0);
    }

    public string Data { get; set; }

    public string[][] MapData { get; set; }

    public ContentManager Content { get; set; }

    public SpriteBatch SpriteBatch { get; set; }

    public Vector2 Position { get; set; }

    private Vector2 ArrayPosition;

    private readonly Vector2 Speed = new Vector2(40, 32);

    public static Map Parse(string path) {
        var map = new Map();
        var stream = TitleContainer.OpenStream(Path.Combine("Content", path));
        using (var sr = new StreamReader(stream)) {
            map.Data = sr.ReadToEnd();
        }
        var lines = map.Data.Split(new string[1] { Environment.NewLine }, StringSplitOptions.None);
        var mapHeight = lines.Count();
        map.MapData = new string[mapHeight][];
        for (int i = 0; i < lines.Count(); i++) {
            var elements = lines[i].Split(';');
            map.MapData[i] = elements;
        }
        return map;
    }

    public void DrawMap(SpriteBatch spriteBatch, ContentManager content, GameTime gametime) {
        this.SpriteBatch = spriteBatch;
        this.Content = content;
        for (int y = 0; y < MapData.Count(); y++) {
            var current = MapData[y];
            for (int x = 0; x < current.Count(); x++) {
                switch (current[x]) {
                    case "e":
                        drawEnemy(x, y);
                        break;

                    case "P":
                    case ".":
                        drawTile(x, y);
                        break;

                    case "w":
                        drawWall(x, y);
                        break;
                }
            }
        }
        drawPlayer();
    }

    public void Move(Direction pdirection, GameTime gametime) {
        var direction = Vector2.Zero;
        var x = this.ArrayPosition.X;
        var y = this.ArrayPosition.Y;
        switch (pdirection) {
            case Direction.Up:
                if (y > 0 && y < 16) {
                    direction = new Vector2(0, -1);
                }
                break;

            case Direction.Down:
                if (y < 16 && y >= 0) {
                    direction = new Vector2(0, 1);
                }
                break;

            case Direction.Left:
                if (x > 0 && x < 16) {
                    direction = new Vector2(-1, 0);
                }
                break;

            case Direction.Right:
                if (x < 16 && x >= 0) {
                    direction = new Vector2(1, 0);
                }
                break;
        }
        Position += direction * Speed;
    }

    private void drawPlayer() {
        var tile = Position / Speed;
        var x = tile.X;
        var y = tile.Y;
        drawTile((int)x, (int)y);
        var texture = Content.Load<Texture2D>("Sprites/player");
        this.SpriteBatch.Draw(texture, Position, Color.White);
    }

    private void drawEnemy(int x, int y) {
        drawTile(x, y);
        drawTexture(Content.Load<Texture2D>("Sprites/enemy"), x, y);
    }

    private void drawTile(int x, int y) {
        drawTexture(Content.Load<Texture2D>("Tiles/grass"), x, y);
    }

    private void drawWall(int x, int y) {
        drawTexture(Content.Load<Texture2D>("Tiles/wall"), x, y);
    }

    private void drawTexture(Texture2D texture, int x, int y) {
        var rectangle = new Rectangle(x * 40, y * 32, 40, 32);
        this.SpriteBatch.Draw(texture, rectangle, Color.White);
    }
}

回答1:


It looks to me that you are using a mix of co-ordinate systems to represent things on your map in addition to possible cumulative movement delta error. Consider having one co-ordinate system. I'm not sure how big your map is so lets assume it's 10x10. Therefore tiles; enemys; and the player's co-ordinates should be within {0...9}x{0...9}.

e.g. In your DrawMap() I see your tiles use a co-ordinate system of 0 to the dimensions of your string[][] MapData. You leave scaling the co-ordinates until your drawTexture() as below which I think is a good idea:

private void drawTexture(Texture2D texture, int x, int y) {
    var rectangle = new Rectangle(x * 40, y * 32, 40, 32);
    this.SpriteBatch.Draw(texture, rectangle, Color.White);
}

Tip: Try to avoid having magic numbers in your code. Consider either defining 40 and 32 as constants or even better determine the tile size at runtime during LoadContent().


However, your method Move(), which moves the player about based on direction is scaled by Speed defined below as:

private readonly Vector2 Speed = new Vector2(40, 32);

...which I don't think is a good idea because you are scaling the size of tiles with the player's speed which results in the player's co-ordinates being in an entirely different co-ordinate system than enemy's, walls and other map data. Because it is scaled, you need to divide by the tile size all the time to normalise the player's co-ordinates whenever you wish to interact with the map.

Later when you draw the player you have this unusual line:

private void drawPlayer() {
    var tile = Position / Speed;

If p is position, v is velocity; t is time; then p = vt which follows that t = p / v so just reading the above line on its own is a little odd. But I know what you are trying to do - determine the co-ordinates of the tile based on tile size.

However if you just normalise the player's position to always be with the range {0...MapData dimensions} without scaling by (40, 32) it would make things simpler.

Changes

In your Move() method change this line:

    Position += direction * Speed;

...to:

    Position += direction;

Then change drawPlayer() from:

private void drawPlayer() {
    var tile = Position / Speed;
    var x = tile.X;
    var y = tile.Y;
    drawTile((int)x, (int)y);
    var texture = Content.Load<Texture2D>("Sprites/player");
    this.SpriteBatch.Draw(texture, Position, Color.White);
}

...to:

private void drawPlayer() {
    drawTile((int)Position.x, (int)Position.y);
    var texture = Content.Load<Texture2D>("Sprites/player");

    var p = Position * new Vector2 (40,32);
    this.SpriteBatch.Draw(texture, p, Color.White);
}

Performance tip

  • Move all the Content.Load<> from your Drawxxx(...) to LoadContent(...). Generally you want to minimize the loading of resources (particularly the same resources) during your game loop unless your game is streaming (which you are not in this case).


来源:https://stackoverflow.com/questions/29808334/move-sprite-like-in-pok%c3%a9mon

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!