【问题标题】:Moving Platforms in a Tile Map在平铺地图中移动平台
【发布时间】:2014-05-21 23:59:54
【问题描述】:

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

下图显示了平台,它一直在运动,当它与其中一个黑色圆圈相撞时,它应该改变方向并朝着相反的方向前进。

不幸的是,我遇到了一个问题,我需要找到正确的平台,这样它就会朝着另一个方向发展。我在主类中创建了列表,但不知道如何在主类之外的另一个类中调用列表。

问题:

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

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

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

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

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

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

那么 Block 类将使用一个使用 Player 类的方法。

    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 方法。

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

然后我们转到主类 Game1。

我为块和平台创建列表。

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

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

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

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

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

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

        Levels.Add(Level1);

        base.Initialize();
    }

然后调用一个 void LoadLevel。

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

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

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

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

Draw 方法终于调用了它们。

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

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

【问题讨论】:

    标签: c# object xna tile


    【解决方案1】:

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

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

    class Map
    {
        public List<Block> Blocks;
        public List<MovingPlatform> Platforms;
    
        void LoadLevel(int level)
        {
            ///
        }
    }
    

    现在它使代码更简洁,而且您现在有了一个可以传递的 Map 对象。

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

    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”作为 MovingPlatform 构造函数的第一个参数:

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

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

    这称为依赖注入。您的 MovingPlatform 类对地图具有依赖关系,并且您正在通过构造函数注入该依赖关系。

    编辑:

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

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

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

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

    要使上述操作生效,您需要将地图上的可碰撞图块列表传递给 MovingPlatform 更新。调用地图类中的每个 MovingPlatform,将可碰撞瓦片列表传递给它。

    class Map
    {
        List<Tile> _collidableTiles;
    
        void Update(GameTime gameTime)
        {
            foreach (MovingPlatform platform in MovingPlatforms)
            {
                platform.Update(_collidableTiles);
            }
        }
    }
    

    这是一种方法。更好的方法是不要传入可碰撞的瓷砖,而是让 MovingPlatform 抓取它周围的瓷砖并对其进行测试。

    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 的瓦片都会导致移动平台与它们发生碰撞。

    class Tile
    {
        bool IsSolid;
    }
    

    【讨论】:

    • 感谢您尝试帮助我处理我凌乱的代码。我会尝试解决这个问题,很抱歉我的问题不清楚。我真的不知道我可能让你有点困惑,我想从类中添加单独数量的代码并不是最好的主意。我没有看到更简单的方法来显示我的代码,因为它是一个很大的块,任何人都无法筛选。
    • 不,我理解你的帖子,好吧,我只是不确定我是否应该在答案中发布代码来进行实际的碰撞检测(我不知道如何用块来做到这一点)
    • 好吧,这个怎么样,我们只看包含平台对象的列表。现在我将如何创建一个 for 循环并找到它们的位置以查看它们是否与图块的位置重叠。告诉我如何找到我可以做瓷砖的平台。
    • 这看起来不错,我认为这会很好,感谢 Weyland 的帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-12-03
    • 1970-01-01
    • 1970-01-01
    • 2014-10-23
    • 1970-01-01
    • 1970-01-01
    • 2013-05-21
    相关资源
    最近更新 更多