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

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

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

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

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

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

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

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

Идеи?

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
12
0
10 106
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Ответ принят как подходящий

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

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

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

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

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

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

Ответ: «Насколько вам удобно».

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

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

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

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

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

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

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

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

Кроме того, вам может быть интересно узнать, что Шон Харгривз, оригинальный разработчик Аллегро, является одним из основных разработчиков в команде XNA :-)

Я это заметил. Это маленький маленький мир.

FlySwat 16.09.2008 01:22

Главный вопрос здесь, кажется, таков: «Какие накладные расходы связаны с использованием делегатов и событий C#?»

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

Использование делегатов может создать неявный и, следовательно, скрытый мусор. Мусор может быть основной причиной проблем с производительностью, особенно на 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)
    {
    }

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

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

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

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

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

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

Другие вопросы по теме