2011-04-12 105 views
1

我最近開始進行XNA開發,並且在過去有一些(非常有限)的經驗,我決定嘗試做一個Pong克隆,看看我能記得多少。我所知道的大部分都回到我身上,但我在蝙蝠和球之間的碰撞檢測方面遇到了問題。我有3個矩形設置爲更新位置以及我正在使用的精靈,當球長方形與蝙蝠長方形相交時,我將球的X速度乘以-1。然而,這產生了一種不尋常的效果,球在球棒上跳動,如this video所示。我在這裏做了什麼錯誤?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 Pong 
{ 

public class Game1 : Microsoft.Xna.Framework.Game 
{ 
    GraphicsDeviceManager graphics; 
    SpriteBatch spriteBatch; 

    System.Random generator = new Random(); 

    Texture2D ball; 
    Texture2D bat1; 
    Texture2D bat2; 
    Texture2D middle; 

    Vector2 midPos; 
    Vector2 bat1Pos; 
    Vector2 bat2Pos; 
    Vector2 ballPos; 
    Vector2 ballVelo; 

    public Game1() 
    { 
     graphics = new GraphicsDeviceManager(this); 
     Content.RootDirectory = "Content"; 
    } 

    protected override void Initialize() 
    { 
     base.Initialize(); 
    } 

    protected override void LoadContent() 
    { 
     // Create a new SpriteBatch, which can be used to draw textures. 
     spriteBatch = new SpriteBatch(GraphicsDevice); 

     //Load sprites 
     ball = Content.Load<Texture2D>(@"sprites/pongball"); 
     bat1 = Content.Load<Texture2D>(@"sprites/pongbat"); 
     bat2 = Content.Load<Texture2D>(@"sprites/pongbat"); 
     middle = Content.Load<Texture2D>(@"sprites/pongmiddle"); 

     //Set default sprite positions 
     midPos.X = (Window.ClientBounds.Width/2) - 5; 
     midPos.Y = 0; 

     bat1Pos.X = 10; 
     bat1Pos.Y = (Window.ClientBounds.Height/2) - 50; 

     bat2Pos.X = Window.ClientBounds.Width - 20; 
     bat2Pos.Y = (Window.ClientBounds.Height/2) - 50; 

     ballPos.X = (Window.ClientBounds.Width/2) - 5; 
     ballPos.Y = (Window.ClientBounds.Height/2) - 5; 

     //Generate random ball velocity 
     ballVelo.X = generator.Next(5,10); 
     ballVelo.Y = generator.Next(4, 7); 
    } 

    protected override void UnloadContent() 
    { 

    } 

    protected override void Update(GameTime gameTime) 
    { 


     //Update rectangle values 
     Rectangle bat1Rect = new Rectangle((int)bat1Pos.X, (int)bat1Pos.Y, 10, 100); 
     Rectangle bat2Rect = new Rectangle((int)bat2Pos.X, (int)bat2Pos.Y, 10, 100); 
     Rectangle ballRect = new Rectangle((int)ballPos.X, (int)ballPos.Y, 10, 100); 

     //Move ball 
     ballPos += ballVelo; 

     // Allows the game to exit 
     if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) 
      this.Exit(); 
     if (Keyboard.GetState().IsKeyDown(Keys.Escape)) 
      this.Exit(); 

     //Bat 1 movement and restriction 
     if (Keyboard.GetState().IsKeyDown(Keys.Up)) 
      bat1Pos.Y -= 4; 

     if (Keyboard.GetState().IsKeyDown(Keys.Down)) 
      bat1Pos.Y += 4; 

     if (bat1Pos.Y <= 0) 
      bat1Pos.Y = 0; 

     if (bat1Pos.Y >= Window.ClientBounds.Height - 100) 
      bat1Pos.Y = Window.ClientBounds.Height - 100; 


     //Bat 2 movement and restriction 
     if (Keyboard.GetState().IsKeyDown(Keys.W)) 
      bat2Pos.Y -= 4; 

     if (Keyboard.GetState().IsKeyDown(Keys.S)) 
      bat2Pos.Y += 4; 

     if (bat2Pos.Y <= 0) 
      bat2Pos.Y = 0; 

     if (bat2Pos.Y >= Window.ClientBounds.Height - 100) 
      bat2Pos.Y = Window.ClientBounds.Height - 100; 

     //Ball movement restrictions 
     if (ballPos.X <= 0) 
      ballVelo.X *= -1; 

     if (ballPos.Y <= 0) 
      ballVelo.Y *= -1; 

     if (ballPos.X >= Window.ClientBounds.Width - 5) 
      ballVelo.X *= -1; 

     if (ballPos.Y >= Window.ClientBounds.Height - 5) 
      ballVelo.Y *= -1; 


     //Collision detection between bats and ball 
     if (ballRect.Intersects(bat1Rect)) 
     { 
      ballVelo.X *= -1; 
     } 

     if (ballRect.Intersects(bat2Rect)) 
     { 
      ballVelo.X *= -1; 
     } 

     base.Update(gameTime); 
    } 

    protected override void Draw(GameTime gameTime) 
    { 
     GraphicsDevice.Clear(Color.Black); 

     spriteBatch.Begin(); 
     spriteBatch.Draw(middle, midPos, Color.White); 
     spriteBatch.Draw(bat1, bat1Pos, Color.White); 
     spriteBatch.Draw(bat2, bat2Pos, Color.White); 
     spriteBatch.Draw(ball, ballPos, Color.White); 
     spriteBatch.End(); 

     base.Draw(gameTime); 
    } 
} 
} 
+0

以前問: http://stackoverflow.com/questions/2707059/2d-gaming-how-to-reflect-a-ball-off-the-bat – 2011-04-12 14:15:31

回答

1

一種方式是做做如下改變你ballRect.Intersect(barXRect)) if語句:

if (ballRect.Intersects(bat1Rect)) 
    { 
     ballVelo.X = Math.Abs(ballVelo.X) * -1; 
    } 

    if (ballRect.Intersects(bat2Rect)) 
    { 
     ballVelo.X = Math.Abs(ballVelo.X); 
    } 

這樣左邊的酒吧只會將球發送給右邊,右邊的酒吧只會將其發送給左邊。我可能會有錯誤的方式,所以最好仔細檢查一下,但這只是意味着將* -1移到另一隻蝙蝠。

+0

這似乎很好地工作,謝謝。 – David 2011-04-12 14:27:12

+0

不用擔心,很高興我能幫上忙。 – Lyise 2011-04-12 14:35:39

9

萊利斯的解決方案將工作,但它不會攻擊問題的實際來源。在更大的遊戲中,您將需要更強大的解決方案,所以我將解釋高級別的修復。

問題在於當球仍在蝙蝠內部時,您正在更改X速度。在下一幀中,最可能的結果是球將移開,但不足以退出蝙蝠,因此檢測到新的碰撞。速度再次改變,循環重複,直到球通過其下方或上方離開球棒。

精確的解決方案需要將球移出球棒,然後反轉速度。
選項:

  • 將球返回到框架開始時的位置。球永遠不會碰到蝙蝠。如果球速足夠高或幀頻足夠低,這將是顯而易見的。
  • 計算球進入球棒的距離,並從球的位置減去該球的位置。
    // Colliding from the right
    impactCorrection = bat.Right - ball.Left;
    // Colliding from the left
    impactCorrection = bat.Left - ball.Right;

    要獲得額外的分數,您可以將球移出X2 * impactCorrection,以便球總是在每一幀中移動相同的距離。
+0

+1優秀的解釋。這應該是被接受的答案-_- – George 2013-03-10 16:49:09