【问题标题】:Collision detection and Rectangles碰撞检测和矩形
【发布时间】:2020-03-08 22:04:16
【问题描述】:

我试图让我的角色在与另一个精灵碰撞时的速度为零。它会这样做,但是如果我选择更高的速度值,当它发生碰撞时纹理之间的距离会增加,值越高,发生碰撞时纹理之间的距离就越远。

在 1f 的速度下,碰撞似乎可以正常工作(两个纹理都接触),但 1f 对我的游戏来说太慢了,我不知道如何在不增加碰撞距离的情况下增加它。

我相信这是因为我在碰撞区域中使用了:rectangle.Right + Velocity.X,但我不确定如何更改它来解决我的问题。帮助将不胜感激。

//In Sprite class
    #region Collision
    protected bool IsTouchingLeft(Sprite sprite)
    {
        return rectangle.Right + Velocity.X > sprite.rectangle.Left &&
               rectangle.Left < sprite.rectangle.Left &&
               rectangle.Bottom > sprite.rectangle.Top &&
               rectangle.Top < sprite.rectangle.Bottom;
    }

    protected bool IsTouchingRight(Sprite sprite)
    {
        return rectangle.Left + Velocity.X < sprite.rectangle.Right &&
               rectangle.Right > sprite.rectangle.Right &&
               rectangle.Bottom > sprite.rectangle.Top &&
               rectangle.Top < sprite.rectangle.Bottom;
    }

    protected bool IsTouchingTop(Sprite sprite)
    {
        return rectangle.Bottom + Velocity.Y > sprite.rectangle.Top &
               rectangle.Top < sprite.rectangle.Top &&
               rectangle.Right > sprite.rectangle.Left &&
               rectangle.Left < sprite.rectangle.Right;
    }

    protected bool IsTouchingBottom(Sprite sprite)
    {
        return rectangle.Top + Velocity.Y < sprite.rectangle.Bottom &
               rectangle.Bottom > sprite.rectangle.Bottom &&
               rectangle.Right > sprite.rectangle.Left &&
               rectangle.Left < sprite.rectangle.Right;
    }
    #endregion
    //In MainChar class
            foreach (var sprite in sprites)
            {
                if (sprite == this)
                {
                    continue;
                }

                if (Velocity.X > 0 && IsTouchingLeft(sprite) || Velocity.X < 0 && IsTouchingRight(sprite)) 
                {
                    Velocity.X = 0;
                }

                if (Velocity.Y > 0 && IsTouchingTop(sprite) || Velocity.Y < 0 && IsTouchingBottom(sprite))
                {
                    Velocity.Y = 0;
                }

                if (sprite.rectangle.Intersects(rectangle))
                {
                    hasDied = true;
                }
            }


【问题讨论】:

  • 我认为这是因为您的 IsTouching* 方法确实应该命名为 WillBeTouching* 因为您正在将速度添加到当前位置。我想到了两件事。降低速度以使它们完美碰撞,或将位置设置为发生碰撞的位置。
  • 当你检测到因为一个精灵与另一个精灵重叠而发生碰撞时,将移动精灵的速度设置为 0,但同时也设置它的位置,使其停留在/反对/触摸(无论哪一侧)其他精灵?
  • 如果我降低速度,我的角色会移动得太慢,但是,如果我错了,请纠正我,我认为我不能将位置设置为它们碰撞的位置,因为我正在与不同的多个精灵发生碰撞地点。

标签: c# collision-detection monogame rectangles


【解决方案1】:

正确处理多个碰撞将需要子步进,重复碰撞检查,直到不再有碰撞或计数器到期。这就是物理引擎的运作方式。

我将展示一种不同的方法。它需要不进行导致碰撞的移动,并且每一步将速度调整一半。减速直到你到达那里最多log2(Velocity) 步(对于速度

foreach (var sprite in sprites)
{
   if (sprite == this)
   {
       continue;
   }
   // it is good practice to use () for mixed && and || 
   if ((Velocity.X > 0 && IsTouchingLeft(sprite)) || (Velocity.X < 0 && IsTouchingRight(sprite))) 
   {
      Velocity.X *= 0.5f;
      // by halving, the velocity will exponentially decay to 0 
   }

   if ((Velocity.Y > 0 && IsTouchingTop(sprite)) || (Velocity.Y < 0 && IsTouchingBottom(sprite)))
   {
      Velocity.Y *= 0.5f;
   }

   if (sprite.rectangle.Intersects(rectangle))
   {
      hasDied = true;
   }
   // use new velocity to update the position.
}

您可能需要修复死亡条件,尚不清楚何时应该触发。编写的代码将向上移动到另一个对象,但不会自行重叠。

以下代码是我相信你想要的(以 1 的速度移动直到重叠)

foreach (var sprite in sprites)
{
   if (sprite == this)
   {
       continue;
   }
   // it is good practice to use () for mixed && and || 
   if ((Velocity.X > 0 && IsTouchingLeft(sprite)) || (Velocity.X < 0 && IsTouchingRight(sprite))) 
   {
   if (Velocity.X >= 2) // cap it at a minimum above 1
      {
         Velocity.X *= 0.5f;
         // by halving, the velocity will exponentially decay to 0 
      }
      if (sprite.rectangle.Intersects(rectangle))
      {
         Velocity.X = 0; // probably need to do this for Y here as well.
         hasDied = true;
      }

   }

   if ((Velocity.Y > 0 && IsTouchingTop(sprite)) || (Velocity.Y < 0 && IsTouchingBottom(sprite)))
   {
      if (Velocity.Y >= 2) // cap it at a minimum above 1
      {
         Velocity.Y *= 0.5f;
         // by halving, the velocity will exponentially decay to 0 
      }
      if (sprite.rectangle.Intersects(rectangle))
      {
         Velocity.Y = 0; // probably need to do this for X here as well.
         hasDied = true;
      }
   }      
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-12
    • 2016-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多