направляя массу врагов одновременно - PullRequest
9 голосов
/ 20 марта 2012

Я работаю над простой 2d игрой, в которой постоянно появляется множество врагов и преследуют игрока или игроков в python + pygame.Проблема, с которой я столкнулся, и один из многих, кто запрограммировал этот тип игры, состоит в том, что враги сходятся очень быстро.Я временно решил эту проблему с помощью функции, которая раздвигает любых двух врагов случайным образом, если они находятся слишком близко друг к другу.Это хорошо работает, но имеет дело с алгоритмом O (n ^ 2), который запускается каждый кадр, и при больших врагах программа начинает замедляться.

Когда моя программа запускается с этой функцией, враги, кажется, образуют круглый объект, который я прозвал «глыбой».Кажется, что скопление обычно эклиптическое, но на самом деле может быть более сложным (не симметричным), потому что, когда игрок движется, враги тянутся в разные стороны.Мне нравится, как ведет себя этот скопление, однако мне интересно, есть ли более эффективный способ его расчета.В настоящее время каждый враг в группе (часто> 100) сначала перемещается в направлении игрока, а затем раздвигается.Если бы вместо этого был способ вычислить фигуру, которую создает скопление, и то, как он перемещается, это спасло бы много вычислений.

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

Также мои две функции, используемые в настоящее время для перемещения врагов:

def moveEnemy(enemy, player, speed):
    a = player.left-enemy.left
    b = player.top-enemy.top
    r = speed/math.hypot(a,b)
    return enemy.move(r*a, r*b)

def clump(enemys):
    for p in range(len(enemys)):
        for q in range(len(enemys)-p-1):
            a = enemys[p]
            b = enemys[p+q+1]
            if abs(a.left-b.left)+abs(a.top-b.top)<CLUMP:
                xChange = (random.random()-.5)*CLUMP
                yChange = ((CLUMP/2)**2-xChange**2)**.5
                enemys[p] = enemys[p].move(int(xChange+.5), int(yChange + .5))
                enemys[p+q+1] = enemys[p+q+1].move(-int(xChange+.5),-int(yChange+.5))
    return enemys

Редактировать: некоторые скриншоты того, как выглядит сгусток: http://imageshack.us/photo/my-images/651/elip.png/ http://imageshack.us/photo/my-images/832/newfni.png/

http://imageshack.us/photo/my-images/836/gamewk.png/

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

Ответы [ 4 ]

6 голосов
/ 20 марта 2012

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

  1. Допускается некоторое перекрытие.
  2. Сократите проверку расстояния после фиксированного количества кадров.
  3. Улучшите формулу проверки расстояния. Если вы используете стандартную формулу расстояния, это может быть оптимизировано многими способами. Например, избавиться от квадратного корня. Точность не имеет значения, только относительное расстояние.
  4. Каждый юнит может отслеживать список соседних юнитов. Выполняйте свои расчеты только между единицами в этом списке. Время от времени обновляйте этот список, сверяясь со всеми юнитами.
  5. В зависимости от того, как настроена ваша игра, вы можете разделить поле на такие области, как квадранты или ячейки. Юниты проверяются только против других юнитов в этой ячейке.

РЕДАКТИРОВАНИЕ: Когда юниты приближаются к своей цели, они могут вести себя неправильно. Я бы посоветовал вместо того, чтобы они находились дома на точной цели издалека, чтобы они действительно искали рандомизированную близлежащую цель. Как смещение от их реальной цели.

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

4 голосов
/ 20 марта 2012

Вы можете определить сгусток как отдельный объект с фиксированным количеством пространственных «слотов» для каждой вражеской единицы в сгустке.Каждый слот будет иметь набор координат относительно центра скопления и будет либо пустым, либо будет содержать ссылку на одну единицу.

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

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

1 голос
/ 11 июня 2012

Лучшее вступление к движению стека / рулевого поведения: http://www.red3d.com/cwr/steer/. См. Прилагаемую бумагу red3d paper . И связанные OpenSteer

1 голос
/ 23 марта 2012

Я думаю, вы ищете стекаются .

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