【问题标题】:Processing velocity-vectors during collision as neatly as possible尽可能巧妙地处理碰撞过程中的速度矢量
【发布时间】:2011-02-03 21:26:34
【问题描述】:

我正在尝试创建一种处理两个对象之间所有可能碰撞的好方法。通常情况下,一个会移动并撞到另一个,然后应该“弹回”。

到目前为止,我所做的(我正在创建一个典型的游戏,你有一块木板并在砖块上反弹一个球)是检查矩形是否相交,如果相交,则反转 Y 速度。

这是一个非常丑陋且临时的解决方案,从长远来看是行不通的,由于这种处理在游戏中很常见,我真的很想为未来的项目找到一种很好的方法。感谢任何链接或有用的信息。

下面是我的碰撞处理函数现在的样子。

protected void collision()
    {
        #region Boundaries
        if (bal.position.X + bal.velocity.X >= viewportRect.Width ||
            bal.position.X + bal.velocity.X <= 0)
        {
            bal.velocity.X *= -1;
        }
        if (bal.position.Y + bal.velocity.Y <= 0)
        {
            bal.velocity.Y *= -1;
        }
        #endregion
        bal.rect = new Rectangle((int)bal.position.X+(int)bal.velocity.X-bal.sprite.Width/2, (int)bal.position.Y-bal.sprite.Height/2+(int)bal.velocity.Y, bal.sprite.Width, bal.sprite.Height);
        player.rect = new Rectangle((int)player.position.X-player.sprite.Width/2, (int)player.position.Y-player.sprite.Height/2, player.sprite.Width, player.sprite.Height);

        if (bal.rect.Intersects(player.rect))
        {
            bal.position.Y = player.position.Y - player.sprite.Height / 2 - bal.sprite.Height / 2;
            if (player.position.X != player.prevPos.X)
            {
                bal.velocity.X -= (player.prevPos.X - player.position.X) / 2;
            }

            bal.velocity.Y *= -1;
        }
        foreach (Brick b in brickArray.list)
        {
            b.rect.X = Convert.ToInt32(b.position.X-b.sprite.Width/2);
            b.rect.Y = Convert.ToInt32(b.position.Y-b.sprite.Height/2);
            if (bal.rect.Intersects(b.rect))
            {
                b.recieveHit();
                bal.velocity.Y *= -1;
            }
        }
        brickArray.removeDead();
    }

【问题讨论】:

  • 要从中得到什么,我认为您必须更准确地说明您想要什么行为。说“这真的很丑而且暂时”并没有削减它。
  • Bal 的意思是一个球,它应该准确地反弹它以直角撞击的任何表面,当速度太高时不会“传送”通过它等。

标签: c# xna collision


【解决方案1】:

这里有一些可能会有所帮助的建议。

首先,您的所有对象,例如PlayerBal(不确定那是什么)和Brick 都有一些相似的接口——它们都有sprite(定义对象的大小), rect(物体的边界框),position(当前位置),velocity(当前速度)。这表明您可以创建一个通用基类来封装此功能。

另外请注意,您总是根据当前的positionsprite 重新计算rect。这表明rect 实际上应该是一个隐藏重新计算的属性(始终相同!)

因此,您可以从定义一个像这样的通用基类开始(我将遵循 .NET 标准编码风格并使用属性和CamelCase 名称):

class GameObject {
  Point Position { get; set; } 
  Vector Velocity { get; set; }
  Sprite Sprite { get; set; }
  Rectangle Rect { 
    get { 
      // Ecnapsulated calculation of the bounding rectangle
      return new Rectangle
        ( (int)Position.X + (int)Velocity.X - Sprite.Width/2, 
          (int)Position.Y + (int)Velocity.Y - Sprite.Height/2, 
          Sprite.Width, Sprite.Height);   
    }
}    

如果您现在将此类型用作所有游戏对象的基类,您应该可以这样写:

protected void Collision() {      
    #region Boundaries        
    if (bal.Position.X + bal.Velocity.X >= viewportRect.Width ||        
        bal.Position.X + bal.Velocity.X <= 0)        
        bal.Velocity.X *= -1;        
    if (bal.Position.Y + bal.Velocity.Y <= 0)        
        bal.Velocity.Y *= -1;        
    #endregion

    if (bal.Rect.Intersects(player.Rect)) {      
        bal.Position.Y = player.Position.Y - player.Sprite.Height/2 
                       - bal.Sprite.Height/2;      
        if (player.Position.X != player.PrevPos.X)      
            bal.Velocity.X -= (player.PrevPos.X - player.Position.X) / 2;      
        bal.Velocity.Y *= -1;      
    }      
    foreach (Brick b in brickArray.list) {      
        if (bal.Rect.Intersects(b.Rect)) {      
            b.RecieveHit();      
            bal.Velocity.Y *= -1;      
        }      
    }      
    brickArray.RemoveDead();      
}      

将函数拆分为两个函数听起来也是个好主意 - 一个检查 balplayer,另一个检查砖块。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-06-03
    • 2015-01-25
    • 1970-01-01
    • 1970-01-01
    • 2023-03-29
    • 1970-01-01
    • 1970-01-01
    • 2012-01-15
    相关资源
    最近更新 更多