2012-11-06 173 views
2

我們目前正在爲大學制作一款Xna遊戲。 我們正在測試東西之前,我們把我們自己的紋理等Xna像素碰撞和多層。早期碰撞,錯誤檢測?

所以我們看了很多教程,並通過了大量的代碼。 現在,我們有這個小程序運行: http://www.konter.at/Konter_Game.rar

所以這個GameScreen,我們載入播放器和背景,我們想用一切。

namespace Casual_Game 
{ 
    public class GameplayScreen : GameScreen 
    { 
     Player player; 
     Camera camera; 
     SpriteFont font; 
     private List<Layer> layers; 
     private SpriteBatch _spriteBatch; 

    Rectangle recPlayer, recGround; 
    bool colis = false; 
    Collision collision; 

    public override void LoadContent(ContentManager content, InputManager input) 
    { 
     camera = new Camera(Game1.reference.GraphicsDevice.Viewport) { Limits = new Rectangle(0, 0, 4800, 720) }; 

     collision = new Collision(); 
     _spriteBatch = new SpriteBatch(Game1.reference.GraphicsDevice); 
     base.LoadContent(content, input); 
     player = new Player(); 
     player.LoadContent(content, input); 
     font = content.Load<SpriteFont>("Font1"); 

     layers = new List<Layer> 
     { 
      new Layer(camera) { Parallax = new Vector2(0.0f, 1.0f) }, 
      new Layer(camera) { Parallax = new Vector2(0.1f, 1.0f) }, 
      new Layer(camera) { Parallax = new Vector2(0.2f, 1.0f) }, 
      new Layer(camera) { Parallax = new Vector2(0.3f, 1.0f) }, 
      new Layer(camera) { Parallax = new Vector2(0.4f, 1.0f) }, 
      new Layer(camera) { Parallax = new Vector2(0.5f, 1.0f) }, 
      new Layer(camera) { Parallax = new Vector2(0.6f, 1.0f) }, 
      new Layer(camera) { Parallax = new Vector2(0.8f, 1.0f) }, 
      new Layer(camera) { Parallax = new Vector2(1.0f, 1.0f) } 
     }; 

     // Add one sprite to each layer }); 
     layers[1].Sprites.Add(new Sprite { texture = content.Load<Texture2D>("Textures/Layer2") }); 
     layers[2].Sprites.Add(new Sprite { texture = content.Load<Texture2D>("Textures/Layer3") }); 
     layers[3].Sprites.Add(new Sprite { texture = content.Load<Texture2D>("Textures/Layer4") }); 
     layers[4].Sprites.Add(new Sprite { texture = content.Load<Texture2D>("Textures/Layer5") }); 
     layers[7].Sprites.Add(new Sprite { texture = content.Load<Texture2D>("Textures/Layer8") }); 
     layers[8].Sprites.Add(new Sprite { texture = content.Load<Texture2D>("Textures/Layer9") }); 

     // Add a few duplicates in different positions 
     layers[7].Sprites.Add(new Sprite { texture = content.Load<Texture2D>("Textures/Layer8"), position = new Vector2(900, 0) }); 
     layers[7].Sprites.Add(new Sprite { texture = content.Load<Texture2D>("Textures/Layer8"), position = new Vector2(1400, 0) }); 
     layers[7].Sprites.Add(new Sprite { texture = content.Load<Texture2D>("Textures/Layer8"), position = new Vector2(2700, 0) }); 
     layers[8].Sprites.Add(new Sprite { texture = content.Load<Texture2D>("Textures/Layer9"), position = new Vector2(1600, 0) }); 
     layers[8].Sprites.Add(new Sprite { texture = content.Load<Texture2D>("Textures/Layer9"), position = new Vector2(3200, 0) }); 
     layers[8].Sprites.Add(new Sprite { texture = content.Load<Texture2D>("Textures/Layer9"), position = new Vector2(4800, 0) }); 

    } 
    public override void UnloadContent() 
    { 
     base.UnloadContent(); 
    } 
    public override void Update(GameTime gameTime) 
    { 
     player.Update(gameTime); 


     recGround = new Rectangle((int)layers[8].Sprites[0].Position.X, (int)layers[8].Sprites[0].Position.Y, layers[8].Sprites[0].Texture.Width, layers[8].Sprites[0].Texture.Height); 
     recPlayer = new Rectangle((int)player.Position.X, (int)player.Position.Y, player.Image.Width, player.Image.Height); 
     float elapsedTime = (float)gameTime.ElapsedGameTime.TotalSeconds; 
     KeyboardState keyboardState = Keyboard.GetState(); 

     if (keyboardState.IsKeyDown(Keys.Right)) 
      camera.Move(new Vector2(200.0f * (float)gameTime.ElapsedGameTime.TotalSeconds, 0.0f), true); 

     if (keyboardState.IsKeyDown(Keys.Left)) 
      camera.Move(new Vector2(-200.0f * (float)gameTime.ElapsedGameTime.TotalSeconds, 0.0f), true); 

     if (keyboardState.IsKeyDown(Keys.Down)) 
      camera.Move(new Vector2(0.0f, 400.0f * elapsedTime), true); 

     if (keyboardState.IsKeyDown(Keys.Up)) 
      camera.Move(new Vector2(0.0f, -400.0f * elapsedTime), true); 
     if (recPlayer.Intersects(recGround)) 
     { 
      if (collision.PixelCollision(player.Image, layers[8].Sprites[0].Texture, recPlayer, recGround)) 
      { 
       player.Collision = true; 
       colis = true; 
      } 
      else 
      { 
       player.Collision = false; 
       colis = false; 
      } 
     } 
     else 
     { 
      player.Collision = false; 
      colis = false; 
     } 

     camera.LookAt(player.Position); 

     base.Update(gameTime); 
    } 
    public override void Draw(SpriteBatch spriteBatch) 
    { 
     Vector2 parallax = new Vector2(1.0f); 
     _spriteBatch.Begin(SpriteSortMode.Deferred,null , null, null, null, null, camera.GetViewMatrix(parallax)); 
     foreach (Layer layer in layers) 
      layer.Draw(_spriteBatch); 
     player.Draw(_spriteBatch); 
     spriteBatch.DrawString(font, "Player X : " + player.Position.X.ToString(),new Vector2(10, 10), Color.Black); 
     spriteBatch.DrawString(font, "CameraX :" + camera._position.X.ToString(), new Vector2(10, 25), Color.Black); 
     spriteBatch.DrawString(font, "CameraY :" + camera._position.Y.ToString(), new Vector2(10, 40), Color.Black); 
     spriteBatch.DrawString(font, "Col : " + colis.ToString(), new Vector2(10, 55), Color.Black); 
     _spriteBatch.End(); 

    } 
} 

你看它是不同層的視差背景。在圖層[8]上是我們的玩家將在稍後運行的「地面」。

現在的問題是碰撞檢測工作不正常。 它看起來像檢測正在加載緩慢或什麼的。

我們記住,玩家將會通過檢測到地面。所以他沒有價值,他停在地上。所以它必須是exate。

這是碰撞類:

 public bool PixelCollision(Texture2D sprite1, Texture2D sprite2, Rectangle player, Rectangle enemy) 
    { 
     Color[] colorData1 = new Color[sprite1.Width * sprite1.Height]; 
     Color[] colorData2 = new Color[sprite2.Width * sprite2.Height]; 
     sprite1.GetData<Color>(colorData1); 
     sprite2.GetData<Color>(colorData2); 

     int top, bottom, left, right; 

     top = Math.Max(player.Top, enemy.Top); 
     bottom = Math.Min(player.Bottom, enemy.Bottom); 
     left = Math.Max(player.Left, enemy.Left); 
     right = Math.Min(player.Right, enemy.Right); 

     for (int y = top; y < bottom; y++) 
     { 
      for (int x = left; x < right; x++) 
      { 
       Color A = colorData1[(y - player.Top) * (player.Width) + (x - player.Left)]; 
       Color B = colorData2[(y - enemy.Top) * (enemy.Width) + (x - enemy.Left)]; 

       if (A.A != 0 && B.A != 0) 
        return true; 
      } 
     } 
     return false; 
    } 
} 

我們將非常高興,如果有人可以幫助我們找出答案。 我們並不是那麼多程序員。所以我們認爲問不花費任何東西。 :)

K.

編輯: Player.Update和Draw:

public override void Update(GameTime gameTime) 
    { 
     moveAnimation.IsActive = true; 
     inputManager.Update(); 


     if (inputManager.KeyDown(Keys.Right, Keys.A)) 
     { 
      moveAnimation.currentFrame = new Vector2(moveAnimation.CurrentFrame.X, 2); 
      velocity.X = moveSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds; 
     } 
     else if (inputManager.KeyDown(Keys.Left, Keys.A)) 
     { 
      moveAnimation.currentFrame = new Vector2(moveAnimation.CurrentFrame.X, 1); 
      velocity.X = -moveSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds; 
     } 
     else 
     { 
      velocity.X = 0; 
      moveAnimation.IsActive = false; 
     } 

     if (inputManager.KeyDown(Keys.Up, Keys.W) && jump) 
     { 
      velocity.Y = -jumpSpeed * (float)gameTime.ElapsedGameTime.TotalSeconds; //Position += theDirection * theSpeed * (float)theGameTime.ElapsedGameTime.TotalSeconds; 
      jump = false; 
     } 

     if (!jump) 
      velocity.Y += gravity * (float)gameTime.ElapsedGameTime.TotalSeconds; 
     else 
      velocity.Y = 0; 


     moveAnimation.Position = position += velocity; 

     jump = moveAnimation.Position.Y >= 480; 

     if (jump) 
      position.Y = 480; 


     base.Update(gameTime); 
     moveAnimation.Update(gameTime); 
    } 
    public override void Draw(SpriteBatch spriteBatch) 
    { 
     moveAnimation.Draw(spriteBatch); 
    } 

Layer.Draw:

public class Layer 
{ 
    SpriteBatch spr1teBatch; 
    public Layer(Camera camera) 
    { 
     _camera = camera; 
     Parallax = Vector2.One; 
     Sprites = new List<Sprite>(); 
     spr1teBatch = new SpriteBatch(Game1.reference.GraphicsDevice); 
    } 

    public Vector2 Parallax { get; set; } 

    public List<Sprite> Sprites { get; private set; } 



    public void Draw(SpriteBatch spriteBatch) 
    { 
     spr1teBatch.Begin(SpriteSortMode.Deferred, null, null, null, null, null, _camera.GetViewMatrix(Parallax)); 

     foreach(Sprite sprite in Sprites) 
      sprite.Draw(spr1teBatch); 

     spr1teBatch.End(); 
    } 

    public Vector2 WorldToScreen(Vector2 worldPosition) 
    { 
     return Vector2.Transform(worldPosition, _camera.GetViewMatrix(Parallax)); 
    } 

    public Vector2 ScreenToWorld(Vector2 screenPosition) 
    { 
     return Vector2.Transform(screenPosition, Matrix.Invert(_camera.GetViewMatrix(Parallax))); 
    } 

    private readonly Camera _camera; 
} 
+1

玩家和地面紋理經常變化嗎?如果沒有,你可以嘗試一次提取這些紋理的顏色數據(例如'LoadContent()'),然後將這些數據傳遞給碰撞檢測?只是爲了不需要每次都使用'GetData()'。 – neeKo

+0

你的碰撞代碼看起來不錯。你對檢測到的碰撞有什麼期望?你只需將'player.Collision'設置爲'true',然後?順便說一句,精確碰撞檢測幾乎不是一個好主意,因爲大多數幀速率正在改變,這會影響物體的移動。 –

+0

地面紋理只會加載我認爲的,但玩家的紋理會因不同的移動和交互而不同。 – K213

回答

2

讓我們想像你是畫什麼:

Visualization

您可以在屏幕上的recPlayer.x,recPlayer.y上繪製播放器。然後在recGround.x,recGround.y上繪製該圖層。但是這個位置被視圖矩陣轉換了。

你現在要做的是迭代兩個矩形的所有相交像素。結果的x和y值在屏幕空間中。我突出了x和y的一個例子。您現在需要在這個位置檢索bot紋理的顏色。

玩家的顏色可以很容易地找回,因爲它已經在屏幕空間。紋理中的位置是xTex = x - recPlayer.x和​​3210。顏色數組中的索引可以通過index = yTex * width + xTex來計算。您已經完成此操作以訪問顏色。

檢索地面的顏色有點棘手,因爲它不像玩家那樣在屏幕空間中。它可能已被翻譯並縮小了一些。你還沒有發佈代碼,圖層的精靈是如何繪製的。我假設它在recGround.x,recGround.y(然後轉換)的位置繪製。我們需要做的是計算x/y在地面世界空間中的位置。所以我們使用你已有的方法:

var screenPosition = new Vector2(x, y); 
var groundPosition = ScreenToWorldPos(screenPos); 

這將基本上反轉圖層的轉換。如果將它向右平移20px,則新的groundPosition將位於原始位置左側20px(因爲這是實際位於該位置的像素的位置)。

您可以像訪問xTex = x - recGround.x等玩家一樣訪問顏色。

我剛剛意識到的另一個問題是計算你的相交矩形。當然,你必須使用變換後的矩形來獲得真實的位置。


舊文章:

的問題是,玩家和層不一樣的座標系中繪製。

播放器被繪製在「默認」系統中。這些圖層用相應的視圖矩陣進行繪製轉換,因此被翻譯,縮放等等。

PixelCollision中,您遍歷所有可能相交的屏幕像素。這些像素像玩家一樣處於「默認」系統。由於這個原因,你可以用下面的公式計算紋理位置:

texX = x - player.x 
texY = y - player.y 

但是,這對層不起作用。您必須將屏幕空間中的xy轉換爲圖層的世界空間。

layerPos = ScreenToWorld(new Vector2(x, y)); 

然後在layerPos.x - enemy.xlayerPos.y - enemy.y訪問的顏色。如果你在他們的系統中繪製enemy.x, enemy.y的圖層,這將起作用。如果你有一個額外的變換或將它們拉到別的地方,你需要考慮這個。

+0

我應該這樣做嗎?我爲圖層創建矩形? 或直接在PixelCollision方法中? – K213

+0

在碰撞方法中,您應該傳遞必要的附加信息參數 –

+0

好吧,我會在PixelCollision中做一個「Vector2 layersPos」 然後我會用一個新的Vector2. 調用ScreenToWorld方法,我會從Layers [8]傳遞(x,y).Sprites [ 0] .Position(x,y)? 然後在哪裏放我layersPos.X - enemy.x? – K213