Программирование игр и обработчики событий

Я не программировал игры в течение примерно 10 лет (мой последний опыт был DJGPP + Allegro), но я думал, что проведу XNA в течение выходных, чтобы посмотреть, как он развивается.

Я довольно впечатлен, однако, продолжая соединять игровой движок, у меня есть (возможно) основной вопрос.

Сколько стоит полагаться на делегаты и события С#, чтобы управлять игрой? Как программист приложений, я активно использую делегаты и события, но я не знаю, есть ли значительные накладные расходы для этого.

В моем игровом движке я разработал "chase cam", который можно привязать к объекту и затем пересчитать его положение относительно объекта. Когда объект перемещается, есть два способа обновить кулачок преследования.

  • Имейте метод UpdateCameras() в основном цикле игры.
  • Используйте обработчик событий, и камера chase подписывается на object.OnMoved.

Я использую последнее, потому что он позволяет мне объединять события вместе и красиво автоматизировать большие части движка. Внезапно, что было бы огромным и сложным, он упадет до нескольких 3-5 обработчиков событий... Его красота.

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

Идеи?

Ответ 1

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

Если вы хотите, чтобы ваш код был общим или динамическим, вам нужно проверить, подписано ли что-либо до вызова события. Механизм событий/делегатов С# и .NET предоставляет вам это с очень небольшими затратами (с точки зрения ЦП).

Если вы действительно обеспокоены каждым часовым циклом, вы никогда не будете писать общую/динамическую логику игры. Это компромисс между поддерживаемым/настраиваемым кодом и прямой скоростью.

Хорошо написано, я бы предпочел события/делегаты, пока не смог доказать, что это проблема.

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

Ответ 2

Важно понимать, что события в С# не представляют собой асинхронные события в очереди в очереди (например, очередь сообщений Windows). Они по сути являются списком указателей на функции. Таким образом, повышение события не имеет худших последствий для производительности, чем повторение списка указателей на функции и вызов каждого из них.

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

Ответ 3

Главный вопрос здесь выглядит следующим образом: "Каковы накладные расходы, связанные с использованием делегатов и событий С#?"

События имеют незначительные накладные расходы по сравнению с обычным вызовом функции.

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

Следующий код генерирует около 2000 байт мусора в секунду (со скоростью 60 кадров в секунду) в виде объектов EntityVisitor:

    private delegate void SpacialItemVisitor(ISpacialItem item);

    protected override void Update(GameTime gameTime)
    {
        m_quadTree.Visit(ref explosionCircle, ApplyExplosionEffects);
    }

    private void ApplyExplosionEffects(ISpacialItem item)
    {
    }

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

Ответ 4

XNA поощряет использование интерфейсов, событий и делегатов для записи чего-то написанного с ним. Взгляните на классы, связанные с GameComponent, которые задают это для вас.

Ответ: "Насколько вам комфортно".

Чтобы немного разобраться, если вы, например, берете и наследуете класс gamecomponent в класс cameracontroller и добавляете его в коллекцию Game.Component. Затем вы можете создать свои классы камер и добавить их в свой cameracontroller.

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

Вот пример этого (все его уроки превосходны): ReoCode

Ответ 5

В мое дополнительное время от реальной работы я тоже изучал XNA.

ИМХО (или не так скромно, если вы спрашиваете моих коллег) заключается в том, что накладные расходы на ручки событий будут перегружены другими элементами в игре, такими как рендеринг. Учитывая интенсивное использование событий в обычном программировании .Net, я бы стал основным кодом, который хорошо оптимизирован.

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

Ответ 6

В стороне, вам может быть интересно узнать, что Shawn Hargreaves, оригинальный разработчик Allegro, является одним из основных разработчиков в команде XNA: -)

Ответ 7

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

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

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

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

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