Как правильнее создавать игровой цикл?

Здравствуйте, уважаемые :)
Пытаюсь написать игровой движок для стратежки типа Dune или RedAlert. Просто для себя, покоряю, так сказать, вершины геймдева ))
Свой игровой цикл я делаю в классе мира и все операции над объектами-моделями провожу в нем же. В этом классе за все это отвечает функция tick() и выглядит примерно так:
void tick() 
{
  foreach ( body1 in mapBodies ) 
  {
    foreach ( body2 in mapBodies )
    {
       /*
         и тут я проверяю всевозможные взаимодействия этих двух
         объектов друг с другом. Если это танк, пушка, солдат и т.п., то 
         они могут кого-то видеть, атаковать или ехать по приказу и т.д.,
         если здание - что-то производить...

         В общем эта функция становится всё "жирнее и жирнее" с 
         добавлением нового функционала...
       */
    }
  }
}


но сегодня в одном из исходников я наткнулся на такую реализацию этой функции:
void tick()
{
  foreach ( body in mapBodies )
  {
    body->tick();
  }
}

И все. В этой функции цикл просто перебирает все объекты и вызывает "тик". Так вот мой вопрос: какая модель "тика" проще/правильнее ?
И как во втором случае объекты должны взаимодействовать друг с другом? Ведь по логике получается, что tick(), вызываясь в каждом объекте, порождает цикл проверки всех объектов на возможность взаимодействия с текущим объектом? А если объектов тысячи? За один игровой "тик" должно родится и уничтожится тысяча циклов? А комп не помрет? Или я что-то неправильно понимаю? :)
  • Вопрос задан
  • 2691 просмотр
Пригласить эксперта
Ответы на вопрос 4
@suslik2015
В вашей "архитектуре" "класс мира" осуществляет операции со всеми игровыми объектами. НАлицо нарушение принципов низкой связности и высокого сцепления. Функционально игровой цикл должен пнуть объекты игры или их менеджеры о том, что пора обновить свое состояние, максимум расчитав при этом дельту. Он не должен знать о графике, звуке, физике и т.п. Решение - делегировать аспекты поведения отдельным объектам Можете прочитать здесь про систему компонентных сущностей в играх.
Ответ написан
Deerenaros
@Deerenaros
Программист, математик, задрот и даже чуть инженер
Вы всё правильно понимаете. Только от того, что Вы вынесите тик в отдельный метод ничего толком не измениться в плане производительности. Ну а по поводу количества объектов - чем их больше, тем выше требования к производительности. В средней стратегии с ИИ я где-то вычитал, что проблемы начинаются свыше 1000 объектов, но они в основном решаемые, тогда как где-то с 10000000 (десять миллионов) - нерешаемые. При этом имеются ввиду полноценные объекты, для которых надо искать путь и считать статистику.
Ответ написан
gbg
@gbg
Любые ответы на любые вопросы
Кстати, проверок можно делать в половину меньше - у вас тут A взаимодействует c B, а потом B взаимодействует с A. А нужна только проверка "A и B повзаимодействовали."

Вы не рассмотрели третий вариант - наличие класса "Взаимодействие A и B", от которого наследуется куча классиков с методами, реализующих взаимодействия разных пар объектов. Это наиболее гибкий вариант, да еще и экономящий время:
Без этого вам придется написать два метода:
в классе A - описание взаимодействия с классом B,
в классе B - описание взаимодействия с классом A.

Двигаясь дальше, можно заранее составить список всех возможных пар взаимодействий (с заранее развернутыми типами, чтобы каждый раз A не выясняло, с каким классом мы считаем взаимодействие сейчас), который будет обходится одним циклом.
Ответ написан
tsarevfs
@tsarevfs
C++ developer
Вызов tick() /*мне привычнее называть ее update()*/ для каждого объекта предпочтительней. За счет полиморфизма для каждого типа объекта может быть вызвана своя реализация этой функции. В зависимости от объекта, возможны различные варианты взаимодействий. Например куст может ничего не делать на своем update. А солдат должен посмотреть на всех врагов и выбрать в которого стрелять. Такое поведение не очевидно как реализовывать вашим способом. Ну и отпадает необходимость писать гигантские функции.
Если юнитов становится слишком много, возможны различные оптимизации. Например обсчет только юнитов в определенной зоне или объединение стаи птиц в один объект с упрощенным поведением, вместо рачсета каждой птицы. Но об этом стоит думать, когда оптимизация становится необходимой.
Еще подозрительна фраза про родящиеся и уничтожающиеся циклы. Это прероготива объектов. Циклы это просто часть кода, которая исполняется практически как набор последовательных инструкций.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы