3
\$\begingroup\$

I'm starting to develop a 2D fighting game using C++ and SMFL. I'm relying (at least sort of) on a Entity Design Pattern.

I'm struggling to see how my code should update and manage a heads-up-display (HUD).

I think there are two main possibilities:

  1. The HUD object has references to the players. It periodically updates itself by querying them.

  2. The different systems (input, physics, ...) update the HUD anytime by sending it new information.

The first seems costly because the information might not have changed as often as the HUD queries for it. The second one seems less automatic because the systems NEEDS to specifically call to update the HUD (plus the HUD needs to provide various methods).

What should I do?

\$\endgroup\$
  • \$\begingroup\$ possible duplicate of What is a good approach for making a relationship between the HUD and Environment? \$\endgroup\$ – jmegaffin Feb 5 '14 at 20:29
  • \$\begingroup\$ I'd disagree, although I see your point. This question focuses on polling versus messaging, whereas the other question is about whether the HUD drives the game or whether the game drives the HUD. In this question, the game is always driving the HUD, it's just a question of how it drives the HUD. Plus, although the only answer (your answer now I look at it) is general, that question itself is actionscript-3 specific, which I'd expect to have its own nuances in terms of how things are structured. \$\endgroup\$ – MrCranky Feb 6 '14 at 8:31
2
\$\begingroup\$

This is most often done with your second option, the event system. When something happens, send out an event describing what happened. Anything the HUD cares about it will listen for. It will potentially need to keep copies of some data (like health), but this is often beneficial for a variety of reasons.

One example of why the copy is useful is that you can animate these values. The player health may immediately drop by 10 points but the HUD can flash the health bar, set the lost amount to a different color, and then shrink the bar by the lost amount over some short period of time.

Event-based approach is necessary for some other things, as well. For instance, to display the damage of an attack, you can't just query the state of the game. The attack will quite likely have been fully resolved and forgotten by the time the HUD queries if any attacks are going on. If every attack also emits an event then the HUD and buffer those up and display them during the next HUD update.

Event-based approaches also come in handy in larger scale games. Many games make use of UI middleware with embedded but inefficient scripting languages that often have severe performance concerns when calling between script and C++ code. Letting the C++ code buffer up the events and then dispatch them all to the UI script code in one call can be very beneficial for performance, both bercause it reduces C++-to-script calls and because it is more friendly to the CPU cache.

Athur's answer is a good one for some higher-level languages that already have Observer-like properties built-in. For lower-level code the overhead of making some data observable with a generic framework may not be worth the cost, especially if you still also have an event system (which you need anyway for things that aren't state-based, like the attacks example). We've used observers in some Unity code (non-real-time game) combined with an MVVM pattern for the various HUD components and inventory screens and that worked well. In bigger real-time games we have definitely seen observer and reflection systems take up significant portions of frame time and so I recommend avoiding them and going with a simple event-based architecture since you can optimize that down the road quite easily if you end up needing to.

\$\endgroup\$
  • \$\begingroup\$ I +1 but I think it would be good to clarify what differences between Events driven, Observer and or Slots and Signals you refer to that will affect performance greatly. I think that we don't have the same view on what is the difference between Observer and Event driven patterns are and while yours may be more learned, mine is very common: stackoverflow.com/questions/6439512/… , stackoverflow.com/questions/807778/… \$\endgroup\$ – wolfdawn Feb 5 '14 at 18:14
  • \$\begingroup\$ Just to be specific, I think that events and observers are nearly identical only that in an Observer pattern the emphasis is on the object being observed and in an Event driven design the emphasis is on a specific occurrence. \$\endgroup\$ – wolfdawn Feb 5 '14 at 18:17
  • \$\begingroup\$ @ArthurWulfWhite: An event system architecture that allows registration of listeners is not the same as an observer pattern. There's a difference between events like AttackEvent (gameplay event) and HealthModifiedEvent (subject state changed). Observers can't handle "player attacked and hit but did 0 damage because of armor" with no state change. The point of naming design patterns is to communicate ideas clearly and that is defeated if you conflate them with "nearly identical" patterns. :) \$\endgroup\$ – Sean Middleditch Feb 5 '14 at 19:09
  • \$\begingroup\$ I am not trying to conflate them. I meant that they are nearly identical in terms of performance (I can't edit it now). As you can see I mentioned that in my original comment " clarify what differences ... will affect performance greatly" \$\endgroup\$ – wolfdawn Feb 5 '14 at 19:50
  • \$\begingroup\$ @ArthurWulfWhite: I gotcha. Short version: observer-like events can have a negative impact on cache behavior if unqueued but mostly it's that observer-based approaches focus on an avalanche of small events (X changed; then Y changed) or overly large events requiring follow-up polling ("something" changed) vs gameplay events that can package together all related information with little excess (attack did X damage vs Y armor causing Z hit point damage with W status effect). Every event and every listener registration has overhead so you want to carefully choose and tune message payload data. \$\endgroup\$ – Sean Middleditch Feb 5 '14 at 21:41
1
\$\begingroup\$

I suggest decoupling the two and relying on an event-like (signals and slots) system.

In short, make a generic base Observable class and an Observed class. The Observable class has a list of Observing object instances. When the health changes it notifies everyone who is interested about the new health status. That way health change code can be decoupled from code handling death. So you could have the HUD as an observer and the some other parts of the game perhaps like maybe the rage value handler could observe health changes too.

It is often good to decouple objects when possible and write generic code to reduce duplication.

You can find more on the Observer pattern here.

\$\endgroup\$
  • \$\begingroup\$ Thank you for your answer. I did not understand something by the way: a HUD needs to observe the life but also energy level (see it as mana or magic power), another sort of combo bar that fills when the player is effectively attacking. It should also display the name of the special attack when it is launched etc. So should there be as many observer/able classes as there are life/energy levels ? It seems heavy... \$\endgroup\$ – Nightzus Feb 5 '14 at 12:50
  • \$\begingroup\$ @Nightzus What, no.. There is normally one observable for each object/value that needs to be observed. In this case, it appears the GUI will include three observers and the characters will have three observable members. I don't understand why you would need one per level. \$\endgroup\$ – wolfdawn Feb 5 '14 at 13:02

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.