Оптимизация обнаружения столкновений в Actionscript 3.

#flash #actionscript-3 #collision-detection

#flash #actionscript-3 #обнаружение столкновений

Вопрос:

Я пытаюсь сделать свою первую игру в Actionscript 3. Это простая артиллерийская игра, в которой у вас есть пистолет в нижнем левом углу и ИИ, летающие по экрану, которые вы должны сбивать. Теперь, в классификационном шутере, это достигается либо выстрелом из пистолета и попаданием этой пули с помощью видеоролика AI, либо простым удалением (или воспроизведением анимации смерти) видеоролика AI. Но вот в чем проблема. Я не хочу делать ни то, ни другое. Я хочу показать пистолет с быстрой скорострельностью и, следовательно, без пуль. И я также не хочу, чтобы игрок нажимал точно НА видеоролик AI, чтобы уничтожить их (должно быть достаточно просто пушки / башни, направленной в правильном направлении). направление). Итак, вот что я попробовал.

Это изображение должно помочь представить все это.

изображение

  1. Попытался прикрепить «линию» к турели и проверить наличие столкновения с помощью AI clip. Очевидно, что это не удалось из-за проблемы с ограничительной рамкой, когда линия наклонена.

  2. Я попытался поместить несколько крошечных видеороликов в строку и перебирать их в цикле и проверять наличие каких-либо столкновений с ИИ. Этот метод частично работал, но он был слишком медленным и не казался «правильным» методом.

  3. Я рисую 2 гипотетические линии. Один между p1 и p2, а другой соединяет p3 и p4 (см. Изображение выше). p3 —- длина p4 = AI.width и представляет собой горизонтальную линию, проходящую прямо через центр видеоролика AI. При щелчке мыши я проверяю наличие любого пересечения между этими двумя строками. Теперь, если у меня на экране несколько ИИ, мне снова нужно перебрать каждый из них, нарисовать новый p3 —— p4 и проверить пересечение с p1 —— p2.

Сейчас я использую метод 3, и у меня такое чувство, что, как только я начну добавлять в игру больше материала, частота кадров резко упадет. Я уверен, что для этого должен быть более простой / оптимизированный метод (возможно, что-то очень простое). Прикрепление некоторого соответствующего кода.

shipGame.as

 var baseAI:BaseAI;
var AIList:Array= new Array;
public function shipGame():void{
            trace("still connected!!");
            /*
            irrelevant code..
            */
            stage.addEventListener(Event.ENTER_FRAME, updateGame);
            var a:MovieClip = new MovieClip;
            aiTimer = setInterval(StartAI, 2000);
}
public function StartAI():void {
            baseAI = new BaseAI(this);
            AIList.push(baseAI);
}

public function updateGame(event:Event):void    {
            /*
            code to rotate the turret here..
            */

            for (var i:int = 0; i < AIList.length; i  ) 
            {
                if (AIList[i].myx < 100) {
                    AIList[i].basicAI.parent.removeChild(AIList[i].basicAI);
                    AIList.splice(i, 1);
                }
            }

            if (mouseDn) {
                basicTurret.gotoAndPlay(2);// Fire animation
                for (var j:int = 0; j < AIList.length; j  ) 
                {
                    if ( intersection(AIList[j])) // intersection(bai:BaseAI) returns boolean. Works fine. 
                    {
                        AIList[j].shot = true;
                    }
                }
            }
}
  

BaseAI.as

 var main:shipGame;
var myy:Number;
var myy:Number;
public function BaseAI(doc:shipGame):void{
            main = doc;
            basicAI = new BasicAI(); // BasicAI is a movieClip in the library
            main.addChild(basicAI);
            basicAI.x = 400;
            basicAI.y = Math.abs(Math.random() * (280))   20;
            myy = basicAI.y;
            basicAI.addEventListener(Event.ENTER_FRAME, keepMoving);
}

public function keepMoving(evt:Event):void {
        basicAI.x -= 5;
        myx = basicAI.x;

        if (shot amp;amp; alive) {
            alive = false;
            basicAI.gotoAndPlay(2);
        }
}
  

Ответ №1:

Все ваши текущие методы, по сути, полагаются на средство визуализации Flash, чтобы знать, где находятся корабли и маркированные строки. Но в вашем случае, поскольку у вас относительно простая геометрическая взаимосвязь между движущимися частями, было бы намного быстрее решить проблему аналитически.

Рассмотрим случай, когда корабль находится точно на линии огня вашего орудия. В этом случае оружие, корабль и нижняя часть экрана образуют прямоугольный треугольник. Если мы определим theta угол между пистолетом и нижней частью экрана, то будет выполнено следующее:

 tangent(theta) = ship.y / ship.x
  

где x и y измеряются вправо и вверх от пистолета. Теперь вы можете обобщить это и использовать для тестирования попадания. Когда оружие выстрелит, сначала найдите theta . Затем для каждого корабля вы можете легко определить, насколько далеко по вертикали или горизонтали находится корабль от линии огня, выполнив что-то вроде этого:

 var theta = /*determine theta based on where the mouse was clicked*/
var tanTheta = tangent(theta);
for each (ship) {
    var gunX = ship.y / tanTheta;
    if ( abs(gunX - ship.x) < ship.width/2 ) {
        // a hit occurred
    }
}
  

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