2014-03-30 138 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遊戲也會很耗時。既然你不知道碰撞的基礎知識,我建議做一個乒乓球或打磚塊克隆,這幾乎是我們所有人開始的。