图块映射冲突检测 C# XNA

本文关键字:XNA 冲突检测 映射 | 更新日期: 2023-09-27 17:55:13

我正在尝试用C# XNA为学校项目制作一个非常简单的类似泰拉瑞亚的游戏。我的时间非常有限,否则我可能会花更多的时间试图自己解决这个问题。我创建了一个瓦片地图,但我只是不知道如何使瓷砖"坚固"且无法通过。

using System; 
using System.Collections.Generic; 
using System.Linq; 
using Microsoft.Xna.Framework; 
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content; 
using Microsoft.Xna.Framework.GamerServices; 
using Microsoft.Xna.Framework.Graphics; 
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
namespace TileEngine {
     public class Game1 : Microsoft.Xna.Framework.Game
     {
         GraphicsDeviceManager graphics;
         SpriteBatch spriteBatch;
         Texture2D character;
         Vector2 cPosition;
         Rectangle cBounds, t1Bounds;
         List<Texture2D> tileTextures = new List<Texture2D>();
         int[,] tileMap = new int[,]
         {
             { 0, 1, 1, 0, 2, 1, 1, 1, 0, 1, },
             { 0, 1, 1, 0, 2, 1, 1, 1, 0, 1, },
             { 0, 1, 1, 0, 2, 1, 1, 1, 0, 1, },
             { 0, 1, 1, 0, 2, 1, 1, 1, 0, 1, },
         };
         int tileWidth = 64;
         int tileHeight = 36;
         int cameraPositionX = 0;
         int cameraPositionY = 0;
         int vSpeed = 0;
         public Game1()
         {
             graphics = new GraphicsDeviceManager(this);
             Content.RootDirectory = "Content";
         }
         protected override void Initialize()
         {
             IsMouseVisible = true;
             graphics.IsFullScreen = false;
             graphics.PreferredBackBufferWidth = 1280;
             graphics.PreferredBackBufferHeight = 720;
             graphics.ApplyChanges();
             cPosition = new Vector2(graphics.GraphicsDevice.Viewport.Width / 2 - 15, graphics.GraphicsDevice.Viewport.Height / 2 - 20);
             cBounds = new Rectangle((int)(cPosition.X), (int)(cPosition.Y), character.Width, character.Height);
             base.Initialize();
         }
         protected override void LoadContent()
         {
             // Create a new SpriteBatch, which can be used to draw textures.
             spriteBatch = new SpriteBatch(GraphicsDevice);
             Texture2D texture;
             character = Content.Load<Texture2D>("Tiles/character");
             texture = Content.Load<Texture2D>("Tiles/green");
             tileTextures.Add(texture);
             texture = Content.Load<Texture2D>("Tiles/red");
             tileTextures.Add(texture);
             texture = Content.Load<Texture2D>("Tiles/blue");
             tileTextures.Add(texture);
             cBounds = new Rectangle((int)(cPosition.X), (int)(cPosition.Y),  
 character.Width, character.Height);
             // TODO: use this.Content to load your game content here
         }
         protected override void UnloadContent()
         {
             // TODO: Unload any non ContentManager content here
         }

         protected override void Update(GameTime gameTime)
         {
             if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                 this.Exit();
             KeyboardState keyState = Keyboard.GetState();
             vSpeed += 1;
             cameraPositionY += vSpeed;
             if (keyState.IsKeyDown(Keys.Right))
                 cameraPositionX += 5;
             if (keyState.IsKeyDown(Keys.Left))
                cameraPositionX -= 5;
             if (keyState.IsKeyDown(Keys.Space))
                 vSpeed = -15;
             if (cBounds.Intersects(t1Bounds))
             {
                 cameraPositionY = 0;
                 vSpeed = 0;
             }    
             base.Update(gameTime);
         }

         protected override void Draw(GameTime gameTime)
         {
             GraphicsDevice.Clear(Color.CornflowerBlue);
             spriteBatch.Begin();
             int tileMapWidth = tileMap.GetLength(1);
              int tileMapHeight = tileMap.GetLength(0);
             spriteBatch.Draw(character, cPosition, Color.White);
             for (int x = 0; x < tileMapWidth; x++)
             {
                 for (int y = 0; y < tileMapHeight; y++)
                 {
                     int textureIndex = tileMap[y, x];
                     Texture2D texture = tileTextures[textureIndex];
                     spriteBatch.Draw(
                         texture, t1Bounds =
                         new Rectangle(
                             320 + x * tileWidth - cameraPositionX,
                             540 + y * tileHeight - cameraPositionY,
                             tileWidth,
                             tileHeight),
                         Color.White);
                 }
             }
             spriteBatch.End();
             base.Draw(gameTime);
         }
     } }

如您所见,我试图在所有精灵周围制作矩形并检测它们何时相交,但它似乎不起作用。即使我让矩形的东西工作,我也不知道如果它们相交该怎么办。如果我将速度设置为 0,那么它仍然会慢慢"下降"通过块,因为存在默认的垂直加速度。

图块映射冲突检测 C# XNA

首先,您需要为磁贴创建一个简单的类,如下所示:

Class Tile
{
public int type; //Holds the ID to the specific texture.
public bool collision; //If true you should check for collision if the player is close.
public int health; //You probably need this since rock is harder to break then dirt.
}

然后创建一个包含磁贴的数组。现在,您必须检查播放器是否靠近可碰撞的瓷砖。您需要一个将世界空间转换为图块空间并将玩家坐标放入其中的功能,检查每个帧是否有玩家周围的几个图块。如果您检查完整的地图是否有碰撞,您的 FPS 将下降到 .001,绘制所有瓷砖也是如此。一些伪代码(已经在磁贴级别):

for (int y = player.y-4;y <= player.y+4;y++) 
{ //If your player is just the size of a single tile then just -2/+2 will do. 9*9 is already an expensive 81 rectangles to check.
    for (int x = player.x-4;x <= player.x+4;x++)
    {
        if (map[x,y].collision){
        if (new Rectangle(x*tilewidth,y*tileheight,tilewidth,tileheight).intersects(player.rectangle)){
        //Check farthest valid position and put player there
        }}
    }
}

最好的办法是添加一个 newPosition 属性,在将玩家移动到这个 newPosition 之前,您必须检查该位置是否有效。

除此之外,如果您没有时间,那么最好的建议是不要创建类似泰拉瑞亚的游戏。即使是最简单的泰拉瑞亚游戏也会很耗时。由于你不了解碰撞的基础知识,我建议制作一个乒乓球或类人克隆,这几乎就是我们所有人的开始方式。