CBES – Creating a component-based game (Part III: Reloading)

This is part III of a series where I’d like to show with the help of a practical example how to start a small game with a component-based entity framework. Hope it gives you some ideas how to structure your own games.

This one covers the reloading of the weapon, a feature that I left out on part II. Furthermore I’d like to have a look at a helpful utility class called CompoundEntities.

This example uses an older version of the Slash Framework which can be downloaded here and is in the branch examples/kill-stuff of the repository. If you want to follow the examples step-by-step make sure to use those older versions. If you are already familiar with the framework you may be able to adjust the code to fit the current version of the framework.

Small addition for correct bullet spawning

In the last part we just spawned the bullet right at the position of the weapon. This is almost never the correct position where the bullet enters the world. So I added another component called AnchorComponent which defines an anchor for an entity as a relative offset.

This anchor is used to spawn the bullets at the correct place, we just add the offset when spawning the bullet in the WeaponSystem.Shoot method:

It is optional for the weapon entity, but this we can easily define:

So if we add a AnchorComponent to the weapon and set up the offset, the bullets should spawn at the correct place relative to the weapon position.

Not running out of bullets anymore

A feature I left out last time was to reload the player weapon. Maybe some of you tried or at least thought about how it could be implemented. There are definitively multiple good ways to add this feature. I thought about some different ones myself:

  • Adding a completely new feature called “Reloading”
  • Adding just a ReloadableComponent  that is used by the WeaponSystem  to implement the feature
  • Having everything in the WeaponComponent  for now

The first idea sounded really nice at first. We would need a ReloadableComponent  that gives an entity the ability to be reloaded. Furthermore the current load and the maximum load has to be stored for an entity. E.g. in a CapacityComponent  and a LoadComponent . The bullet count would then be moved out of the WeaponComponent  and moved into the LoadComponent .

Than I thought this might be a bit over-engineered at the moment. I could still have added the ReloadableComponent , but there would be no data in it (there could be e.g. a reload duration later).

So in the end I took the easiest way and put the maximum bullet count right into the WeaponComponent :

And that’s completely okay! As tempting as it might seem to split everything up right in the beginning to give your designers new ways to combine components to new entities, you should always weight this advantage against the time you invest and the complexity you add.

During game development features might change quite radical and all your new components might be obsolete. Nonetheless, if the game goes in a direction where you might need already existing logic (e.g. power packs that can be recharged) or entities only need a part of a component (e.g. one-way weapons that can’t be reloaded), you should definitively refactor your existing code. The systems are really decoupled plus you know what you want to achieve, so it shouldn’t be very difficult.

Adding new logic without influencing existing code

The decoupled structure of a component-based architecture makes adding new features very less prone to error. For the reloading feature I touched a handful existing classes, but the code was mostly alongside the existing one than changing it, e.g. the  WeaponSystem got the handler for the Reload action:

Same with the InputBehaviour  and the InputSystem  which map the player input to the correct action:

 

And we are done with the new feature! Press R or Right Shift to reload your weapon and shoot as much as you like. If you have any feedback or a completely different implementation, I’m very eager to hear about it in the comments or send me a mail!

Systems that only care about a specific combination of components

Let’s move backwards and have another look at the MovementSystem  we added in the very first part of the series:

The interesting part here is the field movementEntities  which is an object of the generic type CompoundEntities . It takes a lot of work off us by providing an easy method to get only the entities a system is interested in. Each system has a specific set of components it expects the entities to have so its logic can be applied to them.

You can specify the components that are required (and optional) by passing a class to CompoundEntities  which contains fields or members that are attributed with the CompoundComponent  attribute. The class will monitor the entity manager to get informed about new entity that match and will even take care about the components of the objects being set correctly.

There are three common use cases how you deal with the entity combinations:

  • Checking if an entity with a specific id is made of the combination. CompoundEntities  has a method GetEntity(int entityId)  therefore.
  • You can iterate over all entities that are made of the required components.
  • Last but not least there are two events that the class provides: EntityAdded  and EntityRemoved .

We dealt with finding the appropriate entities for a system for a long time without this utility class by listening to the EntityInitialized  and/or ComponentAdded/Removed  events from the entity manager in each system. This created quite a lot of boilerplate code which is now capsuled in the CompoundEntities  class.

Other frameworks do it, too

After implementing CompoundEntities , we stumbled upon very similar concepts in other frameworks. It would have been much more useful if we found it a bit earlier, of course 😉

For example the Ashley framework has a concept called Family which is a much nicer name in my opinion. So we might go and rename our utility class. They also have a utility class called ComponentMapper  which cares about exactly one component type and provides a performant way to iterate over all components of a type.

The more your components get split up, the more common it is that a system doesn’t work on a single component alone, but on a combination of them. So it gets more and more useful to have a utility class to take over the work of finding the right entities.

Conclusion

Not much has been added to the game this time, but I hope the post was a good read anyway. The reloading feature showed the main advantages of a decoupled structure. And you might find the CompoundEntities  class helpful when adding your own systems.

I’ll try to add some more features again next time. Particularly with regard to such important missing features like rotating and shooting things! At least I added an offset for the bullets, so they are not spawned in the middle of the player character anymore:

Bullets spawned in front of the weapon
Bullets spawned in front of the weapon

 

Have a look at the repository on bitbucket if you like to see how it was implemented.

In the meantime and like every time: If you’ve got any feedback or questions, just leave a comment or send me a mail!