Обнаружение столкновений и прямоугольников - PullRequest
0 голосов
/ 09 марта 2020

Я пытаюсь получить скорость моего персонажа равной нулю, когда он сталкивается с другим спрайтом. Это делает это, однако расстояние между текстурами увеличивается, когда оно сталкивается, если я выбираю более высокое значение для скорости, чем выше значение, тем больше расстояние между текстурами при столкновении.

При скорости 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;
                }
            }


1 Ответ

0 голосов
/ 16 апреля 2020

Для правильной обработки нескольких столкновений потребуется подшаговый шаг, повторение проверок столкновений до тех пор, пока не прекратятся столкновения или не истечет счетчик. Вот как работают физические движки.

Я собираюсь показать другой метод. Это требует, чтобы не делать движение, которое вызвало столкновение и регулировать скорость наполовину каждого шага. Замедляйте до тех пор, пока не получите максимум log2(Velocity) шагов (для скоростей <32, 5 шагов): </p>

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;
      }
   }      
}
...