繁体   English   中英

瓷砖矩形碰撞

[英]Tile Rectangle Collisions

我有一张1280 x 1280像素的地图。 我正在屏幕上绘制32 x 32像素的图块。 我还给每个图块一个32 x 32像素的矩形。 每个磁贴都有一个布尔值,告诉我是否被阻塞。 我的精灵有一个32 x 32像素的矩形。

当精灵和图块相交时,图块的最左上像素是唯一与精灵矩形接触的像素。

我尝试不加修饰地扩大矩形。

Core.playerOneSpriteRectangle = new Rectangle((int)Core.playerOneSprite.Position.X, (int)Core.playerOneSprite.Position.Y, Engine.TileWidth, Engine.TileHeight);

        #region Player One Controls
        // Player One Controls
        Tile tile;
        Rectangle destination = new Rectangle(0, 0, Engine.TileWidth, Engine.TileHeight);
        if (keyState.IsKeyDown(Keys.W) || (gamePadOneState.DPad.Up == ButtonState.Pressed))
        {
            Core.playerOneSprite.CurrentAnimation = AnimationKey.Up;
            foreach (var layer in tileMapLayers)
            {
                for (var y = 0; y < layer.Height; y++)
                {
                    destination.Y = y * Engine.TileHeight;
                    for (var x = 0; x < layer.Width; x++)
                    {
                        tile = layer.GetTile(x, y);

                        destination.X = x * Engine.TileWidth;

                        // Check Collision With Tiles
                        if (Core.playerOneSpriteRectangle.Intersects(destination) && tile.TileBlocked)
                        {
                            playerOneMotion.Y = destination.Bottom;
                            //Console.WriteLine("Intersected with" + destination + tile.TileBlocked);
                        }
                        else if (Core.playerOneSpriteRectangle.Intersects(destination) && tile.TileBlocked == false)
                        {
                            playerOneMotion.Y = -1f;
                        }  
                    }
                }
            }
        }

我正在尝试为每个图块创建矩形,以使我的子画面不会遍历它们。

更新

这是我在修改建议后当前拥有的代码。

Tile tile;
        Point playertile = new Point((int)Core.playerOneSprite.Position.X / Engine.TileWidth, (int)Core.playerOneSprite.Position.Y / Engine.TileHeight);

        if (keyState.IsKeyDown(Keys.W) || (gamePadOneState.DPad.Up == ButtonState.Pressed))
        {
            Core.playerOneSprite.CurrentAnimation = AnimationKey.Up;
            foreach (var layer in GraelenAreaOne.graelenAreaOneSplatterTileMapLayers)
            {
                tile = layer.GetTile(playertile.X, playertile.Y - 1);

                // Check Collision With Tiles
                if (tile.TileBlocked)
                {
                    playerOneMotion.Y = 0;

                    //Console.WriteLine("Intersected with" + destination + tile.TileBlocked);
                }
                else
                {
                    playerOneMotion.Y = -1;
                }  
            }
        }

我现在可以与图块碰撞,但是我的精灵矩形未正确相交。 Sprite纹理的0,0位置在最左上角,并且只有1x1像素。 设置为32x32时,为什么矩形不包含整个纹理?

您只需要检查要转到的图块是否可行走 ,而不必麻烦自己使用矩形。

一些伪代码:

// Convert pixel coordinates to tile coords
Point playerTile = new Point(player.X / tileWidth, player.Y / tileHeight);
Point targetTile = new Point(target.X / tileWidth, target.Y / tileHeight);

// Take a decision 
if(Direction == Up)
    var tile = layer.GetTile(playerTile.X, playerTile.Y - 1);
    if(tile == walkable)
        // Move to your tile
    else
        ...

另外,这是我前一段时间编写的一些代码,可能仅通过绘制可见的内容来使您感兴趣,以优化关卡的绘制。

https://gamedev.stackexchange.com/questions/29121/organize-a-game-set/29930#29930

在此处输入图片说明

注意: https : //gamedev.stackexchange.com/绝对是解决此类问题的好地方。

编辑

这是一个对我有用的简单示例:

请注意,当玩家无法移动到图块时,我会返回

瓷砖:0是可步行的,1是墙壁,2是玩家

using System;
using System.Linq;
using System.Windows;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input.Touch;
using Point = Microsoft.Xna.Framework.Point;

namespace SlXnaApp1
{
    public partial class GamePage : PhoneApplicationPage
    {
        private readonly GameTimer _timer;
        private int[] _levels;
        private Point _player;
        private Texture2D _t1;
        private Texture2D _t2;
        private Texture2D _t3;
        private Texture2D[] _textures;
        private ContentManager _contentManager;
        private SpriteBatch _spriteBatch;

        public GamePage()
        {
            InitializeComponent();

            // Get the content manager from the application
            _contentManager = (Application.Current as App).Content;

            // Create a timer for this page
            _timer = new GameTimer();
            _timer.UpdateInterval = TimeSpan.FromTicks(333333);
            _timer.Update += OnUpdate;
            _timer.Draw += OnDraw;
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            // Set the sharing mode of the graphics device to turn on XNA rendering
            var graphicsDevice = SharedGraphicsDeviceManager.Current.GraphicsDevice;
            graphicsDevice.SetSharingMode(true);

            // Create a new SpriteBatch, which can be used to draw textures.
            _spriteBatch = new SpriteBatch(graphicsDevice);

            // TODO: use this.content to load your game content here
            _t1 = new Texture2D(graphicsDevice, 32, 32);
            _t1.SetData(Enumerable.Repeat(Color.Red, 32*32).ToArray());
            _t2 = new Texture2D(graphicsDevice, 32, 32);
            _t2.SetData(Enumerable.Repeat(Color.Green, 32*32).ToArray());
            _t3 = new Texture2D(graphicsDevice, 32, 32);
            _t3.SetData(Enumerable.Repeat(Color.Blue, 32*32).ToArray());
            _textures = new[] {_t1, _t2, _t3};
            _levels = new int[4*4]
                {
                    2, 0, 0, 0,
                    0, 0, 1, 0,
                    1, 1, 1, 0,
                    0, 0, 0, 1,
                };
            _player = new Point();

            TouchPanel.EnabledGestures = GestureType.Flick;
            // Start the timer
            _timer.Start();

            base.OnNavigatedTo(e);
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // Stop the timer
            _timer.Stop();

            // Set the sharing mode of the graphics device to turn off XNA rendering
            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false);

            base.OnNavigatedFrom(e);
        }

        /// <summary>
        ///     Allows the page to run logic such as updating the world,
        ///     checking for collisions, gathering input, and playing audio.
        /// </summary>
        private void OnUpdate(object sender, GameTimerEventArgs e)
        {
            Vector2 vector = new Vector2();
            while (TouchPanel.IsGestureAvailable)
            {
                var gestureSample = TouchPanel.ReadGesture();
                var vector2 = gestureSample.Delta;
                vector2.Normalize();
                vector = new Vector2((float) Math.Round(vector2.X), (float) Math.Round(vector2.Y));
            }

            Direction direction = new Direction();
            if (vector.X > 0) direction = Direction.Right;
            else if (vector.X < 0) direction = Direction.Left;
            else if (vector.Y < 0) direction = Direction.Up;
            else if (vector.Y > 0) direction = Direction.Down;

            Point newPos = new Point();
            switch (direction)
            {
                case Direction.None:
                    return;
                case Direction.Up:
                    if (GetTile(_player.X, _player.Y - 1) == 0)
                        newPos = new Point(_player.X, _player.Y - 1);
                    else return;
                    break;
                case Direction.Down:
                    if (GetTile(_player.X, _player.Y + 1) == 0)
                        newPos = new Point(_player.X, _player.Y + 1);
                    else return;
                    break;
                case Direction.Left:
                    if (GetTile(_player.X - 1, _player.Y) == 0)
                        newPos = new Point(_player.X - 1, _player.Y);
                    else return;
                    break;
                case Direction.Right:
                    if (GetTile(_player.X + 1, _player.Y) == 0)
                        newPos = new Point(_player.X + 1, _player.Y);
                    else return;
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }

            SetTile(_player.X, _player.Y, 0);
            SetTile(newPos.X, newPos.Y, 2);
            _player = newPos;
        }

        private int GetTile(int x, int y)
        {
            return _levels[y*4 + x];
        }

        private void SetTile(int x, int y, int value)
        {
            _levels[y*4 + x] = value;
        }

        /// <summary>
        ///     Allows the page to draw itself.
        /// </summary>
        private void OnDraw(object sender, GameTimerEventArgs e)
        {
            SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.CornflowerBlue);
            _spriteBatch.Begin();
            for (int i = 0; i < _levels.Length; i++)
            {
                var tile = _levels[i];
                Point point = new Point(i%4, i/4);
                var texture2D = _textures[tile];
                _spriteBatch.Draw(texture2D, Vector2.Multiply(new Vector2(point.X, point.Y), 32), Color.White);
            }
            _spriteBatch.End();
        }

        private enum Direction
        {
            None,
            Up,
            Down,
            Left,
            Right
        }
    }
}

同样,由于我将级别构建为一维数组的方式,因此,例如在x = 3,y = 0时,图块会向下移动并向右移动; 这完全是意料之外的,但是很正常,因为我不检查范围。 为了简单起见,您希望将级别保持为二维数组。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM