CBES – Creating a component-based game (Part II: Weapons)

In my last post I started a little sample project to show you how our component-based entity framework is used in practice. The game is a little top-down shooter, but so far only movement is possible, so it’s more of a top-down walker. Time to add some shooting!

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.

Starting with the interfaces

One easy way to get started with a new feature is to think about the actions and events you want to implement with it. Our new feature would be to add weapons to the game, so we call it the “Weapon” feature. The new actions our player (and of course also all other entities in the game) would have, would be to fire a weapon and to reload it:

On the output side of the WeaponSystem which would take care about the logic of the new feature, there would be two events:

Next we can go and implement the fire action in detail.

Firing a weapon

Weapons have some data which is stored in its own component, the WeaponComponent:

 

Let’s continue to approach the feature from the action flow. After the Fire action was send to the game, it is catched by the WeaponSystem. The system needs to know which entity fired, so its Id is passed with the event.

We have to check then if the entity has a weapon anyway to determine, e.g. which projectiles are fired and if any bullets are left. Those information are gathered by getting the WeaponComponent of the entity and checking its attributes.

Now we can be sure that the entity has the ability to fire a weapon. Shooting it just means to create a bullet, so let’s do it.

Creating and initializing a bullet

The initial values of the bullet are dependent of the position of the entity which fired it and the speed with which the weapon fires its bullets. All other information are included in the blueprint of the projectile itself.

After creating the projectile our system just decreases the bullet count and queues an event, that a weapon was fired and adds the projectile entity id as the event data:

Call to action

To make sure our player is able to fire his weapon on a button or key press, our input system has to be adjusted. We add a new InputAction.Fire event and just forward it to the weapon feature:

On the Unity side we have to adjust the Update method of our InputBehaviour to map a button to the input action:

Now each time the user presses the button/key which is mapped to the command “Fire”, the WeaponSystem will get notified about the desired action.

Giving the player entity a weapon

Nothing happens right now as we haven’t given our character a weapon yet. We can do so by giving the player entity a WeaponComponent and defining the kind of projectiles which are fired.

To define the blueprint of the projectiles that are fired, we just have to add a blueprint with a unique id to the BlueprintManager where we define the components the entities of this blueprint will have:

Now we can adjust the player character we create in our LevelSystem by giving him a WeaponComponent, 10 initial bullets and defining which projectiles are fired:

Note: In a real game you wouldn’t create the blueprints in the code but via a XML configuration file. This would be a topic for a separate blog post, though, so let’s keep it quick and dirty for the moment.

If you try again to fire the weapon now, you should be able to spawn 10 entities which move to the right.

Firing a "weapon"
Firing a “weapon”

There are two problems though: The spawned entities are too slow for projectiles and they look like the player character. While the first problem is easily fixed by increasing the  WeaponComponent.AttributeSpeed value when adding the WeaponComponent to the player character, the second problem is a bit more complicated.

Let there be bullets

To have different visualizations for the entities we instantiate, we have to split the entity prefab from the visualizations. Right know we just used one that also contained the visualization, so all our entities looked the same.

First we add a component that holds the path to the prefab which should be used for the visualization:

Now we can remove the visualization from our general prefab and add a VisualizationBehaviour instead that creates the visualization from the specified prefab as soon as the entity is instantiated:

Now all there is to do is creating prefabs that contains the visualizations of the player character and the projectile and tell the blueprints where to find them:

If you start the game now, the bullets look a lot more like bullets.

Firing a weapon with actual bullets
Firing a weapon with actual bullets

Reloading your weapon

As you notice you can only fire 10 bullets right now. Our action for reloading already exists, but is neither handled by the WeaponSystem yet, nor fired on a button/key press.

For now, I leave it as an exercise for you to implement the weapon reloading. If you understood how the events in the framework move, it should be straight forward. In the next blog post you’ll find one possible solution.

You can find the source code of the whole project on Bitbucket.

Conclusion

Hopefully adding weapons to our game let you realize the nice, uncoupled way the features of a component-based game behave. We just had to adjust some existing core features (Input, Visualization) to make the new feature work with them. Other features like the movement wasn’t touched at all, but instead were reused for brand new entities (bullets) that didn’t exist before.

For the bullets we didn’t need a single new component for now, we just had to setup the entities the way we needed them. The more components we get, the more possible combinations we get. And if they are designed in a good way, we can reuse them for a lot of different types of entities.

In the next post I’ll implement some nice additions like the reloading and a UI for the game, before moving on to new features like rotating our player character and really hitting stuff with our bullets.

If you’ve got any feedback or questions, just leave a comment or send me a mail!

 

  • Veovis Muad’dib

    I’ve been having to heavily reference the Bitbucket repository in order to follow this tutorial, but now I’m really stuck.

    After the heading “Giving the player entity a weapon” I put CreateProjectileBlueprint() in WeaponComponent, because that’s where there’s a reference to ProjectileBlueprintId.

    But now I’m updating CreatePlayerCharacter() and I’m quite lost. There’s no reference in LevelSystem to WeaponComponent.ProjectileBlueprintId, and I don’t think the solution is to get a reference to a WeaponComponent either. Really I should just be setting up future WeaponComponents here. So what am I supposed to be doing?

    Thanks for all your efforts on these tutorials, there’s a serious lack of getting started materials for ECS, even for professional developers. While the high level concepts are easy to understand, following along has really helped me understand how an implementation might work.

  • coeing

    Hey Veovis,

    Thanks for your comment and question. Reading my lines again it is indeed a bit hard to follow if you are not that familiar with entity systems.

    To add a new projectile blueprint, you should add it to the Blueprints.xml in Assets\Resources\Blueprints. You can also use our Blueprint Editor in Unity (Slash Games/Blueprints/Blueprint Editor).

    The blueprints are completely data driven. You can add blueprints via code, too, but you should do it during initialization, e.g. in an Init method of one of the systems.

    Blueprints are just templates for the final entities which are identified by the BlueprintId. No component should create one. The WeaponComponent contains the ProjectileBlueprintId, so you can define which type of projectiles the weapon fires. This way it is easy to reuse the same kind of projectile with multiple weapons.

    Hope my explanations help a bit, feel free to ask more questions if there are!

    Have some nice Christmas days
    Christian

  • Pingback: CBES – Creating a component-based game (Part III: Reloading) – Coding with Style in Unity3D()