Tilemap碰撞检测C#XNA

时间:2014-03-30 11:59:09

标签: c# xna

我正在尝试在C#XNA中为学校项目制作一个非常简单的类似terraria的游戏。我的时间非常有限,否则我可能会花更多的时间来自己解决这个问题。我创建了一个瓷砖地图,但我无法弄清楚如何使瓷砖“坚固”而不能通过。

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,那么它仍将缓慢地“下降”通过块,因为存在默认的垂直加速度。

1 个答案:

答案 0 :(得分:0)

首先,你需要为你的瓷砖创建一个简单的类:

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将降至.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之前,你必须检查这个位置是否有效。

除此之外,如果你没有时间,那么最好的建议是不要创造像游戏一样的terraria。即使是像游戏这样最简单的terraria也会非常耗时。既然你不知道碰撞的基本知识,我建议制作一个乒乓球或者arkanoid克隆,这几乎就是我们所有人的开始。