Обработка векторов скорости во время столкновения максимально аккуратно - PullRequest
4 голосов
/ 03 апреля 2010

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

То, что я сделал до сих пор (я создаю типичную игру, в которой у вас есть доска и вы отскакиваете шарик от кирпичей), это проверка, пересекаются ли прямоугольники, и, если они это делают, инвертирование скорости 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();
    }

1 Ответ

1 голос
/ 03 апреля 2010

Вот несколько советов, которые могут помочь.

Прежде всего, все ваши объекты, такие как Player, Bal (не уверен, что это такое) и Brick имеют несколько похожий интерфейс - все они имеют sprite (определяющий размер объекта) rect (ограничительная рамка объекта), position (текущая позиция), velocity (текущая скорость). Это говорит о том, что вы можете создать общий базовый класс для инкапсуляции этой функциональности.

Также обратите внимание, что вы всегда пересчитываете rect на основе текущих position и sprite. Это говорит о том, что 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();      
}      

Также неплохо разделить функцию на две: одна проверяет bal и player, а другая проверяет кирпичи.

...