Статьи

Совет: Обнаружение столкновений между кругами

Обнаружение столкновения — это ветвь алгоритмов, которая проверяет, перекрываются ли две фигуры. Если вы строите физические или экшн-игры с помощью ActionScript, вы наверняка не избежите знакомства с этой темой. Это первый из серии, касающейся обнаружения столкновений. В этом кратком совете мы рассмотрим встроенный в ActionScript метод обнаружения столкновений hitTestObject() и напишем собственный для обнаружения перекрытия между двумя кругами.


Это последний SWF, который мы создадим в этом кратком совете. Нажмите на синий круг и перетащите его к зеленому. Как только они перекрываются, зеленый круг изменит свой цвет; если вы снова удалите синий круг, другой снова станет зеленым.


Те, кто знаком с ActionScript 2.0, обязательно узнают метод hitTest() . Эта команда проверяет перекрытие между двумя фигурами или между фигурой и одной точкой. В ActionScript 3.0 он разделен на два отдельных метода: hitTestObject() и hitTestPoint() .

hitTestObject() мы рассмотрим hitTestObject() . Этот comnad обычно подходит для обнаружения столкновений для коробчатых форм (квадраты, прямоугольники). Ограничительная рамка рисуется вокруг фигур, и когда эти ограничивающие hitTestObject() перекрывают друг друга, hitTestObject() возвращает true.

Проверьте пример ниже. Перетащите синюю коробку к зеленой. Когда они перекрываются, оттенок зеленой коробки темнеет.

Я прилагаю здесь соответствующий ActionScript, который генерирует вышеуказанное представление. Box — это пользовательский класс, который легко генерирует квадратные формы. Я включил классы в исходную папку; обращайтесь к ним. Важный скрипт для обнаружения столкновений выделен ниже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package
{
    import flash.display.Graphics;
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    /**
     * Simple hitTest with boxes
     * @author Shiu
     */
    [SWF(width = 400, height = 300)]
    public class Simple extends Sprite
    {
        private var box1:Box, box2:Box;
         
        public function Simple() {
            box1 = new Box(0x0000FF);
            box1.x = 250;
            box1.addEventListener(MouseEvent.MOUSE_DOWN, start);
            box1.addEventListener(MouseEvent.MOUSE_UP, end);
             
            box2 = new Box(0x00FF00);
            box2.x = 100;
        }
        private function start(e:MouseEvent):void {
            e.target.startDrag();
            e.target.addEventListener(MouseEvent.MOUSE_MOVE, check);
        }
        private function end(e:MouseEvent):void {
            e.target.stopDrag();
            e.target.removeEventListener(MouseEvent.MOUSE_MOVE, check);
        }
        private function check(e:MouseEvent):void {
            if (e.target.hitTestObject(box2)) box2.color = 0x00AA00;
            else box2.color = 0x00FF00;
        }
    }
}

Однако столкновение между кругами не может быть эффективно проверено с помощью этой команды. Проверьте презентацию ниже. Перетащите синий круг к зеленому. До столкновения фигур их ограничивающие hitTestObject() уже перекрываются, и hitTestObject() имеет значение true. Нам нужно более точное решение.

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


Различные неточные столкновения обнаружены через hitTestObject.

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


Расстояние между кругами.

Соблюдайте диаграмму выше. r 1 относится к радиусу круга 1, а r 2 относится к радиусу круга 2. Расстояние между кругами рассчитывается для каждого кадра. Если (и только если) он равен или меньше суммы обоих радиусов (r 1 + r 2 ), то эти два круга должны касаться или перекрывать друг друга.


Вот важный ActionScript для реализации концепции выше:

1
minDist = circle1.radius + circle2.radius;
1
2
3
4
5
private function check(e:MouseEvent):void {
    var distance:Number = Math2.Pythagoras(circle1.x, circle1.y, circle2.x, circle2.y);
    if (distance <= minDist) circle2.color = 0x00FFAA;
    else circle2.color = 0x00FF00;
}

Вот образец решения. Перетащите синий круг к зеленому. Когда они перекрываются, вы увидите изменение зеленого цвета. Он возвращается к нормальному состоянию, когда оба круга не сталкиваются.

Я включил реализацию ActionScript ниже.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
package
{
    import flash.display.Sprite;
    import flash.events.MouseEvent;
    /**
    * Simple collision between 2 circles
    * @author Shiu
    */
    [SWF(width = 400, height = 300)]
    public class Simple3 extends Sprite
    {
        private var circle1:Circle, circle2:Circle;
        private var minDist:Number;
         
        public function Simple3() {
            circle1 = new Circle(0x0055AA, 30);
            circle1.x = 250;
            circle1.addEventListener(MouseEvent.MOUSE_DOWN, start);
            circle1.addEventListener(MouseEvent.MOUSE_UP, end);
             
            circle2 = new Circle(0x00FF00, 30);
            circle2.x = 100;
             
            minDist = circle1.radius + circle2.radius;
        }
     
        private function start(e:MouseEvent):void {
            e.target.startDrag();
            e.target.addEventListener(MouseEvent.MOUSE_MOVE, check);
        }
     
        private function end(e:MouseEvent):void {
            e.target.stopDrag();
            e.target.removeEventListener(MouseEvent.MOUSE_MOVE, check);
        }
     
        private function check(e:MouseEvent):void {
        var distance:Number = Math2.Pythagoras(circle1.x, circle1.y, circle2.x, circle2.y);
            if (distance <= minDist) circle2.color = 0x00FFAA;
            else circle2.color = 0x00FF00;
        }
    }
 
}

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