【问题标题】:Tilemap collision detection C# XNATilemap 碰撞检测 C# XNA
【发布时间】:2014-03-30 11:59:08
【问题描述】:

我正在尝试用 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);
         }
     } }

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

【问题讨论】:

  • 不要通过将速度设置为0来停止玩家,您需要查看玩家进入瓷砖的距离,也称为交叉深度,并减去深度来设置玩家回到瓷砖上。
  • 除了最后一个图块外,您没有任何地方可以检查碰撞。您可能必须创建一个包含所有矩形的数组,然后是一个 foreach 循环,检查每个 tilerectangle 是否与玩家边界相交。请记住@Cyral 所说的。

标签: c# xna


【解决方案1】:

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

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

然后用 Tiles 创建一个数组。现在你必须检查玩家是否靠近可碰撞的瓷砖。您需要一个将世界空间转换为瓦片空间并将您的玩家坐标放入其中的函数,检查玩家周围的几个瓦片的每一帧。如果您检查完整的地图是否有碰撞,您的 FPS 将下降到 0.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 之前,您必须检查该位置是否有效。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-07-20
    • 1970-01-01
    • 2023-04-06
    • 1970-01-01
    • 2014-02-28
    • 2015-10-08
    • 2016-08-31
    相关资源
    最近更新 更多