平铺矩形碰撞

时间:2013-07-01 20:43:27

标签: c# .net xna

我有一张1280 x 1280像素的地图。 我在屏幕上绘制了32 x 32像素的图块。 我还给每个图块一个32乘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;
                }  
            }
        }

我现在能够与瓷砖碰撞但是我的精灵矩形没有正确交叉。精灵纹理的位置0,0位于左上角,只有1x1像素。 为什么矩形不包含整个纹理,因为它设置为32x32?

1 个答案:

答案 0 :(得分:3)

你应该检查你想要去的瓷砖是否是 walkable ,而不必费心自己使用矩形。

一些伪代码:

// 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

enter image description here

注意:对于这类问题,https://gamedev.stackexchange.com/绝对是一个更好的地方。

修改

这是一个适合我的简单示例:

请注意,当玩家无法移动到平铺时,我返回

Tiles: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并向右移动时,向下移动;这是无意的,但是正常,因为我没有检查边界。为简单起见,您需要将您的关卡保持为二维数组。