2014-03-30 137 views
0

我想在C#XNA中为一个学校项目制作一个非常简单的类terraria游戏。我的时间非常有限,否则我可能会花更多的时间来自己弄清楚。我创建了一个瓷砖地图,但我无法弄清楚如何使瓷砖“坚实”,而不是通过。Tilemap碰撞检测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,那么它将仍然缓慢地“落入”块中,因为存在默认的垂直加速度。

+2

您不必通过将速度设置为“0”来停止玩家,您需要查看玩家进入瓦片的距离(也称为交叉点深度),然后减去深度以将玩家重新放回瓦片。 – Cyral

+0

除了最后一个瓷砖,您没有任何碰撞检查的地方。您可能必须对所有矩形创建一个数组,然后创建一个foreach循环,如果它与玩家边界相交,请检查每个tilerectangle。请记住@Cyral也说了什么。 – joppiesaus

回答

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

然后创建与瓷砖的数组。现在你必须检查玩家是否接近可碰撞的瓦片。你需要一个将世界空间转换为平铺空间并将你的球员坐标放入其中的功能,检查每个球员周围的几个方格。如果您检查完整的地图碰撞,您的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游戏也会很耗时。既然你不知道碰撞的基础知识,我建议做一个乒乓球或打砖块克隆,这几乎是我们所有人开始的。