2011-04-12 81 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