像《神奇宝贝》中那样移动精灵 [英] Move sprite like in Pokémon

查看:56
本文介绍了像《神奇宝贝》中那样移动精灵的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个游戏,希望我的角色像《神奇宝贝》一样在我的战场上逐格移动.

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

使用我的代码,它会逐格移动,只是每次击键时都会跳过约4-5平方.然后跳来跳去.

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?

我的代码如下.

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);
    }
}

推荐答案

在我看来,除了可能的累积运动增量误差之外,您还使用多种坐标系来表示地图上的事物.考虑使用一个坐标系.我不确定您的地图有多大,所以假设它是10x10.因此瓷砖;敌人并且玩家的坐标应在{0 ... 9} x {0 ... 9}之内.

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}.

例如在您的DrawMap()中,我看到您的图块对您的string[][] MapData的尺寸使用了0坐标系.您可以按比例缩放坐标,直到您的drawTexture()如下所示,我认为这是一个好主意:

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);
}


提示:请尝试避免在代码中包含魔术数字.考虑将40和32定义为常量,或者甚至更好地在运行时确定LoadContent()期间的切片大小.


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().

但是,根据direction移动播放器的方法Move()Speed缩放,定义如下:

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;

如果p是位置,则v是速度; t是时间;然后是p = vt,紧随其后的是t = p / v,因此仅阅读上面的行有点奇怪.但是我知道您要做什么-根据图块大小确定图块的坐标.

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.

但是,如果仅将玩家的位置标准化为始终在{0 ... MapData维数}范围内,而不用(40,32)进行缩放,则会使事情变得简单.

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.

在您的Move()方法中,更改以下行:

In your Move() method change this line:

    Position += direction * Speed;

...发送至:

    Position += direction;

然后从以下位置更改drawPlayer():

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 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);
}

性能提示

  • 将所有Content.Load<>从您的Drawxxx(...)移动到LoadContent(...).通常,除非您的游戏不是流媒体(在这种情况下不是),否则您通常希望在游戏循环中最小化资源(尤其是相同资源)的负载.
  • 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).
    • 这篇关于像《神奇宝贝》中那样移动精灵的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆