Эффективный способ проверки объектов, пересекающих линию обзора в AS3 - PullRequest
5 голосов
/ 10 мая 2011

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

Вот как я обычно это делал:

function cast(end:GameObject, walls:Array, accuracy:uint=10):Object
{
    var xp:Number = skin.x;
    var yp:Number = skin.y;

    var ang:Number = Math.atan2(end.skin.y - yp, end.skin.x - xp);
    var xvel:Number = Math.cos(ang)*accuracy;
    var yvel:Number = Math.sin(ang)*accuracy;

    var i:uint = 0;
    for(i; i<800/accuracy; i+=accuracy)
    {
        xp += xvel;
        yp += yvel;

        var j:GameObject;
        for each(j in walls)
        {
            if(j.skin.hitTestPoint(xp, yp))
                return {visible:false, x:xp, y:yp};
        }
    }

    return {visible:true};
}

Использование этого было бы в основном:

var sight:Object = cast(player, impassable);

if(sight.visible) trace('can see');
else trace('cant see - collision at ' + sight.x + ", " + sight.y);

Работает, но, как мы знаем, это будет очень медленным с каждой новой ракетой или с увеличением количества непроходимых объектов.

Я предполагаю, что есть действительно простой эффективный способ, который мне не хватает - я имею в виду, что все игры делают это (Diablo и т. Д.) С сотнями врагов, которые ничего не делают, если вы не видны.1012 * Идеи?

Ответы [ 3 ]

4 голосов
/ 10 мая 2011

Я имею в виду, что все игры делают это (Diablo и т. Д.) С сотнями врагов, которые ничего не делают, если вас не видят.

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

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

Далее движок на основе плитокпоиск пути также очень полезен в игровых движках на основе тайлов и может довольно легко выполнить вашу задачу;Длина пути и / или сложность могут позволить вам легко выяснить, могут ли два объекта «видеть» друг друга.(Скорее всего, если вам нужно пройти сорок шагов, или по лабиринтному пути объекты не будут видны друг другу)

Движки на основе плиток радикально уменьшат накладные расходы, которые вы ''начинаю рассматривать.

1 голос
/ 16 мая 2011

Избавьте себя от необходимости кодировать так много и попробуйте использовать радиопередачу с использованием физического движка Box2d, он выполняет большую часть тяжелой работы за вас, и вам не нужно беспокоиться о скорости, поскольку box2d уже оптимизирован, но если вы настаиваетеОпределенно, можно было бы использовать кодирование на основе тайлов, возможно, с указанием пути для перемещения и того, что сказал Брайан о стрельбе.Но если вам нужно учесть сценарий cell.gif, просто измените условия поиска плитки.

0 голосов
/ 10 мая 2011

Для столкновения обычно имеет смысл поддерживать какую-то сетку (или пространственное дерево, но сетка должна быть достаточно тонкой), каждая ячейка знает объекты в ней, чтобы вы могли непосредственно находить объекты в определенном пространстве.

Затем вы пишете процедуру, которая извлекает все рассматриваемые ячейки для столкновения, в данном случае все ячейки вдоль луча. По мере их извлечения выполняйте проверку столкновения для объектов в них.

Этот код должен в основном делать это:

function rayCollision(start:Point, dest:Point, grid:CollisionGrid, ignore:* = null):CollisionData {
    var direction:Point = new Point(dest.x - start.x, dest.y - start.y);
    if (direction.length == 0) return null;//just in case
    const limit:Number = direction.length;
    direction.normalize(grid.cellSize);
    var pos:Point = start;
    var cur:Array, last:Array = null, tested:Dictionary = new Dictionary();
    if (!(ignore is Function)) {
        if (ignore is ICollidable) tested[ignore] = true;
        else for each (var entry:* in ignore) tested[entry] = true;//assume it is a collection
    }
    var collision:CollisionData = null;
    while (grid.containsPoint(pos) && (pos.subtract(start).length < limit) {//stop when you're off the grid or out of range
        cur = grid.getCellByPoint(pos);
        if (cur == last) continue;//cell already checked, skip
        last = cur;
        for each (var object:ICollidable in cur) {
            if (tested[object] || (ignore && ignore(object))) continue;//object already checked or should be ignored, skip
            tested[object] = true;
            collision = object.collideWithLine(start, dest);
            if (collision) return collision;
        }
        pos = pos.add(direction);
    }
    return null;
}

CollisionData должно содержать координаты и объект. ICollidable - это интерфейс для всего, что может столкнуться, которое должно быть реализовано индивидуально, потому что, например, столкновение между линией и стеной должно быть довольно легко вычислено.
И на самом деле, вы должны сделать это методом CollisionGrid, так что вы просто идете myGrid.rayCast(start, end, theCaster), и вы сможете удобно отбрасывать лучи между тем, что вы хотите.

Удачи с деталями;)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...