Topic: Game Programming /
Deeper Topic (part 4): Examples and advanced techniques
Deeper topic – Components and Events
Part 1
Part 3
Part 4
Examples and advanced techniques
Now that we have a basic idea about what components are and how they work together with events, let’s talk about some examples and more advanced techniques. For this post, I will be posting more plain English description of the components rather than actual component code. Just ask if you are unsure of how something would be implemented.
Let’s add some more functionality to our Entity class:
class Entity {
public function attachComponent(component:Component):Bool
public function getComponent(type:Class):Component
public function dispatchEvent(keyword:String, data:Object = null):Object
public function attachEvent(keyword:String, callback:Function, priority:Int = 0):Event
public function breakEvent():Void
public function removeComponent(type:Class):Bool
public function detachEvent(e:Event):Bool
}

removeComponent() and detachEvent() should be fairly self-explanatory. The only gotcha here is that our attachEvent() function has been appended to return an Event instance, soley used for the purpose of identification so that we can detach it later if we want to.
breakEvent() is a fairly simple function with a lot of power, and you can invoke it at any time inside your components as they are reacting to a dispatchEvent. Calling it prevents any other components that were listening for this event from ever getting their turn. Of course, it only works for components with specified a lower priority value, as the ones with a higher priority value have already executed.
In short, with breakEvent() a component can stop other components from hearing an event. It only stops the single current ongoing event as breakEvent() is called, if another event is dispatched afterwards it will work normally.
This can be used when we wish to invoke special rules that should override the regular flow of things. A prime example is the Invincibility Star that Mario can acquire. When he is under it’s affect he should not die when an enemy inflicts harm upon him.

A star power component could be designed like this:
Starpower Component
new Starpower(target) – add component to target, and listen for all events mentioned below.
Events
‘damage’: Priority 100, breakEvent() to prevent the damage from ever being picked up by any other components on Mario.
‘collide’: Priority 10, dispatchEvent() with ‘death’ to whatever we are colliding with, because nothing survives Mario with starpower
‘update’: Spawn some glittery star effects around Mario every frame, and check if it’s time to end the startpower buff. When it is time, dispatchEvent ‘starpowerExpire’
‘starpowerExpire’: removeComponent() the StarPower component, and detachEvent() all the events, so that there is no trace that Mario ever had this component.
This is a well designed component, because it is portable and can be entirely contained to it’s own file. Nothing in our Mario code would imply the existance of this powerup, which shows how easy it would be in the future to create more powerups, without having to do any retroactive adjustments on Mario.
Now, let’s make something deadly. A poison debuff that inflicts damage every frame to an enemy, and also spreads to other enemies that touches the poisoned victim.
SpreadingPoison Component
new SpreadingPoison(target) – add component to target, and listen for all the events mentioned below.
Events
‘update’: inflict damage, and check if it is time for the poison to expire.
‘collide’: check if the target we are colliding with is an ally, and if so, apply the poison to it too.
‘draw’: Priority -1, draw some green poison bubbles on top of the target to show that it is poisoned.
As you can see, we can even use events for graphical stuff. By using a priority of -1, we are telling the entity that we want the green poison bubbles drawn after (and thus on top) the enemy sprite, which has a priority of 0 for the ‘draw’ keyword.
Now let’s implement the famous Protoss shield from Starcraft
ProtossShield Component
new ProtossShield(target, 500) – you know the drill by now
Events
‘damage’: Priority 5, subtract the damage amount from the shield. If the shield is greater than the damage amount, subtract the damage amount from the shield and call breakEvent(). If the damage amount is greater than the shield, subtract the shield from the damage amount, set shield to 0, and let the ‘damage’ event resume.
‘update’: Regenerate 1 shield point
If the unit has so much shield that the damage is entirely absorbed, the ‘damage’ event is stopped entirely. This means that if you have a component for splashing some blood, or playing a “ugh!” sound, it’s not gonna trigger unless the shield runs out.
But enough gameplay components, let’s look at some general purpose components also.
Repeater Component
new Repeater(keyword,frequency) – This component dispatches the specified event to it’s parent entity as often as the frequency given.
new Repeater(‘jump’,100) would trigger the ‘jump’ event on the enemy every 100th frame. As long as there is some other movement component listening for this ‘jump’ event and acting upon it, you would have the enemy jump in intervals.

Reaction Component
new Reaction(oldKeyword, newKeyword) – This component dispatches newKeyword when it hears the oldKeyword.
new Reaction(‘damage’,‘trigger’) would cause any damage to trigger the a bomb’s countdown mechanism, making it behave in a volatile manner. The Reaction mechanism is great for bridging two pieces of functionality without having to write a completely new component.
Delay Component
new Delay(keyword, time)
Fairly self-explanatory. Works almost like a task scheduler, helping us quickly set up actions to happen in the future. For instance, we could simply have our Starpower component with a new Delay(‘starpowerExpire’,5000) so that we don’t need to keep track of the time ourselves in the Starpower component.
These general purpose components can help us with rapid prototyping, and just saving keystrokes in general, so that we can create more content faster. A lot of them can even outperform customized components at scale with some clever mass optimizations.