在平铺地图中移动平台 [英] Moving Platforms in a Tile Map

查看:34
本文介绍了在平铺地图中移动平台的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用瓷砖地图,如果移动平台碰到瓷砖,它应该去另一个方向.我正在为 tilemap 和平台使用一个列表,这有助于保持整洁.

I am using a tile map where if a moving platform hits a tile it should go another direction. I am using a list for both the tilemap and platform, this helps keep things neat.

下图显示了平台,它一直在运动,当它与一个黑色圆圈相撞时,它应该改变方向并朝相反的方向行驶.

The image below shows the platform, it is constantly in motion and when it collides with one of the black circles it should change directions and head the opposite way it was going.

不幸的是,我遇到了一个问题,我需要找到正确的平台,以便它会走向另一个方向.我在主类中创建了列表,但不知道如何在主类之外的另一个类中调用列表.

Unfortunately I am having a problem where I need to find the correct platform so it will go the other direction. I created the list in the main class and do not know how to call upon the list inside a another class besides the main.

问题:

我如何调用一个列表,该列表包含多个朝不同方向、不同位置移动的对象,并在主类中创建,以便我可以知道平台是否与瓷砖碰撞?

How would I call upon a list that is holding multiple objects going in different directions, in different position, and is created in the main class, so that I can know if the platform is colliding with a tile?

简单来说,如何让平台与瓷砖发生碰撞?

这是瓦片地图必须经过使用和调用的过程:

Here is the process that the tile map must go through to be used and called:

为了制作瓦片地图,使用了两个类,Block 类和 Game1 类(主类).

To make the tile map two classes are used, Block class and Game1 class (the main class).

在 Block 类中,Texture、Position 和 BlockState(决定它将做什么)

Inside the Block class the Texture, Position, and BlockState (which decides what thing it will do)

    public Block(Texture2D Texture, Vector2 Position, int BlockState)
    {
        this.Texture = Texture;
        this.Position = Position;
        this.BlockState = BlockState;
    }

然后 Block 类将使用一个使用 Player 类的方法.

Then the Block class will use a method that uses the Player class.

    public Player BlockCollision(Player player)
    { 
        Rectangle top = new Rectangle((int)Position.X + 5, (int)Position.Y - 10, Texture.Width - 10, 10);
        Rectangle bottom = new Rectangle((int)Position.X + 5, (int)Position.Y + Texture.Height, Texture.Width - 10, 10);
        Rectangle left = new Rectangle((int)Position.X - 10, (int)Position.Y + 5, 10, Texture.Height - 10);
        Rectangle right = new Rectangle((int)Position.X + Texture.Width, (int)Position.Y + 5, 10, Texture.Height - 10);

        if (BlockState == 1 || (BlockState == 2 && !player.goingUp))
        {
            if (top.Intersects(new Rectangle((int)player.Position.X, (int)player.Position.Y, player.Texture.Width, player.Texture.Height)))
            {
                if (player.Position.Y + player.Texture.Height > Position.Y && player.Position.Y + player.Texture.Height < Position.Y + Texture.Height / 2)
                {
                    player.Position.Y = player.ground = Position.Y - player.Texture.Height;
                    player.Velocity.Y = 0;
                    player.isJumping = false;
                    player.Time = 0;
                    player.botCollision = true;
                }
            }
        }

        return player;
    }

然后是 Draw 方法.

Then the Draw method.

    public void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(Texture, new Rectangle((int)Position.X, (int)Position.Y, Texture.Width, Texture.Height), Color.White);
    }

然后我们转到主类 Game1.

We then move over to the main class Game1.

我为块和平台创建了列表.

I create the Lists for both Blocks and the Platforms.

    List<Block> Blocks;
    List<MovingPlatform> Platforms;

我使用字符系统创建地图.

Using a char system I create the map.

    List<char[,]> Levels = new List<char[,]>();
    public int tileWidth, tileHeight;

然后在 Initialize 方法中调用 Lists 并创建地图.

Then in the Initialize method I call on Lists and create the map.

    protected override void Initialize()
    {
        Blocks = new List<Block>();
        Platforms = new List<MovingPlatform>();

        char[,] Level1 = {{'.','.','#'},
                          {'.','.','#'},
                          {'.','.','#'}};

        Levels.Add(Level1);

        base.Initialize();
    }

然后调用 void LoadLevel.

Then a void LoadLevel is called on.

    void LoadLevel(int level)
    {
        Blocks.Clear();
        Platforms.Clear();

        player.Position = Vector2.Zero;

        tileWidth = Levels[level].GetLength(1);
        tileHeight = Levels[level].GetLength(0);

        Texture2D blockSpriteA = Content.Load<Texture2D>("blockA2");

        for (int x = 0; x < tileWidth; x++)
        {
            for (int y = 0; y < tileHeight; y++)
            {

                //Background
                Blocks.Add(new Block(background, new Vector2(x * 50, y * 50), 0));

                //Impassable Blocks
                if (Levels[level][y, x] == '#')
                {
                    Blocks.Add(new Block(blockSpriteA, new Vector2(x * 50, y * 50), 1));
                }

                //Vertical Moving Platform
                if (Levels[level][y, x] == '=')
                {
                    Platforms.Add(new MovingPlatform(platform, new Vector2(x * 50, y * 50), 3.0f, true));
                }

然后在更新中我调用列表.

Then In the Update I call on the lists.

        foreach (Block b in Blocks)
        {
            player = b.BlockCollision(player);
        }

        foreach (MovingPlatform m in Platforms)
        {
            player = m.BlockCollision(player);
            m.Update(gameTime);
        }

最后 Draw 方法调用了它们.

Finally the Draw method calls on them.

        foreach (Block b in Blocks)
        {
            b.Draw(spriteBatch);
        }

        foreach (MovingPlatform m in Platforms)
        {
            m.Draw(spriteBatch);
        }

推荐答案

我想我明白你的问题,我不确定,但我还是要冒险回答.

I think I understand your question, I am not sure, but I am going to hazard an answer anyway.

我认为您需要做的是将内容移出主 Game 类.你有一个地图的概念和一堆属于地图的东西(平台、块),所以最好把它封装在它自己的类中,例如:

I think what you need to do is to move stuff out of the main Game class. You have a concept of a map and a bunch of stuff that belongs to a map (platforms, blocks) so it's a good idea to encapsulate this in its own class, eg:

class Map
{
    public List<Block> Blocks;
    public List<MovingPlatform> Platforms;

    void LoadLevel(int level)
    {
        ///
    }
}

现在它使代码更清晰,而且您现在还拥有一个可以传递的 Map 对象.

Now it makes the code cleaner, but also you now have a Map object you can pass around.

例如,要使移动平台能够访问地图上的所有内容,您只需要将地图的引用作为参数传递给移动平台构造函数,该构造函数将其保存到私有字段中.例如:

So for example to enable a MovingPlatform to have access to everything on a map, you just need to pass a reference to a map as a parameter to the MovingPlatform constructor which saves it away to a private field. Eg:

class MovingPlatform
{
    Map _map;
    public MovingPlatform(Map map, Vector2 position, ...)
    {
        _map = map;
    }

    public void Update(GameTime gameTime)
    {
        //move platform
        //detect collision
        //have access to all the blocks and other platforms on map
        //_map.Blocks;
        //_map.Platforms;
    }
}

因此,在地图类 LoadLevel() 方法中,您将传入this"作为移动平台构造函数的第一个参数:

So in the map class LoadLevel() method you'd pass in 'this' as the first parameter of the MovingPlatform constructor:

class Map
{
    void LoadLevel(int level)
    {
        //Vertical Moving Platform
        if (Levels[level][y, x] == '=')
        {
            Platforms.Add(new MovingPlatform(this, ...));
        }
    }
}

您可以向 Map 类添加其他特定于地图的内容(甚至是对玩家的引用?),MovingPlatforms 将自动访问它们.

You can add other map specific things (even a reference to the player?) to the Map class and the MovingPlatforms will automatically have access to them.

这称为依赖注入.您的 MovingPlatform 类依赖于地图,并且您正在通过构造函数注入该依赖项.

This is called Dependency Injection. Your MovingPlatform class has a dependency on the map and you are injecting that dependency in through the constructor.

对于碰撞,您可以向 Tile 和 MovingPlatform 类添加 Bounds 属性.这使得获取它们的当前矩形边界变得更容易.也是MovingPlatform 中的IntersectsTile 方法,如果平台与指定的图块相交,它将返回true.

For collision you could add a Bounds property to Tile and MovingPlatform class. That makes it easier to get the current rectangle bounds of them. Also an IntersectsTile method in MovingPlatform that will return true if the platform intersects a specified tile.

class Tile
{
    Rectangle Bounds
    {
        get
        {
            return new Rectangle((int)Position.X, (int)Position.Y, tileWidth, tileHeight);
        }
    }
}

class MovingPlatform
{
    Rectangle Bounds
    {
        get
        {
            return new Rectangle((int)Position.X, (int)Position.Y, platformWidth, platformHeight);
        }
    }

    //returns true if this platform intersects the specified tile
    bool IntersectsTile(Tile tile)
    {
        return Bounds.Intersects(tile.Bounds);
    }
}

然后在MovingPlatfom类中平台每帧移动的Update方法中,检查移动后是否有碰撞.如果发生碰撞,则退出运动并反转平台方向,因此下一帧它将以相反的方式移动.

Then in the MovingPlatfom class in the Update method where the platform is moved each frame, check if there is a collision after the movement. If there is a collision then back out the movement and reverse the platform direction, so next frame it will move the opposite way.

class MovingPlatform
{
    void Update(Tile[] collidableTiles)
    {
        Position += direction;

        //test collision
        bool isCollision = CollisionTest(collidableTiles);
        if (isCollision)
        {
            //undo the movement and change direction
            Position -= direction;
            direction = newDirection;
        }
    }

    //returns true if this platform intersects with any of the specified tiles
    bool CollisionTest(Tile[] tiles)
    {
        foreach (Tile tile in tiles)
            if (IntersectsTile(tile))
                return true;
        return false;
    }
}

要使上述工作正常运行,您需要将地图上的可碰撞图块列表传递给移动平台更新.调用地图类中的每个移动平台,将可碰撞图块列表传递给它.

For the above to work you need to pass in a list of collidable tiles on the map to the MovingPlatform update. Call each MovingPlatform in the map class, passing it the list of collidable tiles.

class Map
{
    List<Tile> _collidableTiles;

    void Update(GameTime gameTime)
    {
        foreach (MovingPlatform platform in MovingPlatforms)
        {
            platform.Update(_collidableTiles);
        }
    }
}

这是一种方法.不过,更好的方法是不要传入可碰撞的瓷砖,而是让移动平台抓取它周围的瓷砖并测试它们.

That's one way of doing it. A better way though would be instead of passing in collidable tiles, get the MovingPlatform to grab tiles around it and test those.

class MovingPlatform
{
    void Update()
    {
        Position += direction;

        //test collision
        Tile[] tiles = _map.GetNearbyTiles(Position);
        foreach (Tile tile in tiles)
            if (tile.IsSolid)
                if (IntersectsTile(tile))
                {
                    //undo the movement and change direction
                    Position -= direction;
                    direction = newDirection;
                    break;
                }
    }
}

这样所有的瓷砖都有一个 IsSolid 属性,任何设置为 true 的都会导致移动平台与它们碰撞.

So that way all tiles have an IsSolid property and any that are set to true will cause moving platforms to collide with them.

class Tile
{
    bool IsSolid;
}

这篇关于在平铺地图中移动平台的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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