CBES: Creating a component-based game

During the last weeks I wrote several posts about our approach of a component-based entity system:

I’d like to wrap it up with the next posts, connecting all the single parts to a working game.

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.

Setting up the project

Let’s start completely from scratch: Our game will be called “Kill Stuff”, a cutting edge Unity3D top down 2D shooter.

Our most simple folder structure for Unity projects looks like this:

  •  Source
    • KillStuff.Unity

The first level is where we make the distinction between the different parts of a project: Documentation, Source, Tools, Builds,…

On the second level in the Source folder we add the different projects. In the simplest case this is only our Unity project.

Now you can start up Unity and let it create a new 2D project called “KillStuff.Unity” at the “Source” path. After it started up, you should consider importing Unity Tools for Visual Studio as a first package. It automatically generates the projects and solution for the Unity project with all the source files in your game. Alternatively you could use the Unity internal functionality in the menu under “Assets/Sync MonoDevelop Project” to create the projects/solution.

UPDATE 16.11.16: With Unity 5 the Visual Studio Tools are already integrated. Looks like the Unity devs saw it as useful as I did 😉

It’s time to add the framework to the project. As a first start, those projects will be enough:

  • Slash.Collections
  • Slash.Diagnostics
  • Slash.ECS
  • Slash.Math
  • Slash.Reflection
  • Slash.Serialization
  • Slash.System
  • Slash.Unity.Common

There are several ways to add the framework to a project:

  1. Copy the DLLs to the Assets/Plugins folder
  2. Copy the projects into the Assets folder
  3. Create symbolic links to the projects inside the Assets folder

The first is the easiest, if you aren’t planning to change the framework. The second one gives you access to the sources, so you can adjust them. The third one is best one if you don’t want to adjust the framework for that single project only.

You can also use this Unity package to import the DLLs into your Unity project, if you don’t want to mess with the framework: Unity Package for Kill Stuff Example

If you build the framework yourself, please make sure to use the branch examples/kill-stuff, otherwise the project may not run correctly because the framework changed a bit since this example was created.

Beside the framework projects we use two game projects: KillStuff.Logic contains all the Unity-independent game logic, KillStuff.Unity the scripts and data for the presentation.

First things first: Movement

The first feature we need for our game is some kind of movement for our character. The player should be able to move his character around in the world via WASD or the arrow keys. Therefore our first two features for the game would be:

  • Movement
  • Input

The movement feature consists of two components and a system:

  • TransformComponent
  • MovementComponent
  • MovementSystem

The TransformComponent contains the current position of an entity, the MovementComponent the current velocity and the maximum speed.

The MovementSystem connects those two data holders. At each update the position of the entity is moved depending on the current velocity.

You may realize some attributes on the class, fields and properties. Those are mainly for the blueprint editor that you can use within Unity to configure your entities. But one attribute is also important for running the game correctly: The Inspector… (e.g. InspectorVector or InspectorFloat) attribute on the component properties is required, so the components are configured correctly via reflection, so make sure they are there 🙂

This is all the logic there is for the movement, let’s move on to the next feature, the user input.

Handling the user input

The logic of the input doesn’t care about key mappings and such things, this will be implemented on the Unity side. Instead it provides actions which the presentation side of the game can use to influence the game state.

For the movement there’s only one event which provides some additional event data so the logic knows what to do.

The presentation side can tell the logic that for a specific direction an entity should either move or not move there anymore. E.g. when a key was pressed or released.

The InputSystem will store the new information in the InputComponent of the entity and updates the velocity of the entity accordingly.

As you can see, the Velocity property in the MovementComponent is the connection between the input and the movement feature. It would be easy to have other features connecting to the movement feature now. An AI feature could set the velocity for example depending on the behavior of an AI entity.

Visualizing the game

Right now we have only set up the logical part of the game. To see something we should connect the logic to the presentation side which we implement in Unity.

To move the visualization of the entity, we create a MonoBehaviour which updates the game object transform depending on the TransformComponent.Position.

The EntityComponentBehaviour is a base class from the framework which automatically fetches a specific logical component of the entity the GameObject represents.

To send the inputs to the game, we can create a MonoBehaviour which sends events to the game depending on the key inputs we receive in Unity.

The behaviour expects that you set up the InputManager of Unity correctly for the inputs “Forward”, “Backward”, “Left”, “Right” and later “Reload”. If you don’t know how that works, checkout this article.

Both behaviours are located on a prefab for the player character. The EntityBehaviour is part of the Slash.Unity.Common project like the EntityComponentBehaviour was. It’s primary function is to hold a reference to the game the entity is part of and the entity id. This way the EntityComponentBehaviours can get their logical components and send events to the game.

Prefab of the player character
Prefab of the player character

As a child in the prefab you can see the Visualization node. This is the one which contains the actual sprite of the player character. You can use anything you like right now, just add a SpriteRenderer and assign the sprite to it.

Getting the game running

We have almost all parts together that we need to build a first game. The logic is in place and the presentation uses the data from the logic to update their state and sends events to the logic to influence the logical state.

As with every Unity project you need a scene where the game starts. In this scene we add a GameObject that has behaviours which connect the presentation and the logical side.

Root scene of the game to create the logic and connect it to the presentation
Root scene of the game to create the logic and connect it to the presentation

The GameBehaviour creates a the game on start up. Via reflection our systems (MovementSystem, InputSystem) are added to this game. The behaviour also updates the game every frame and sends the passed time since the last update.

The EntityGameObjectsBehaviour reacts on the generic events from the logic, e.g. when an entity was created. For each entity it creates a GameObject in the EntityObjectPool and sets it up correctly. I.e. setting the game reference and the entity id in the EntityBehaviour.

Both behaviours are generic and part of the framework, so you don’t need to write them yourself in every new project.

The last bit

Now you can start the game by running the scene. And you will see…nothing. The reason is that the player character wasn’t instantiated yet, we just set up its parts.

Therefore we add a third system, the LevelSystem. Later it could take care about the initial setup of a new level, but right now we just create a player character when the game starts.

If you start the game now, you should see a GameObject which was created by the EntityGameObjectsBehaviour that represents the player character. You can move it with the keys you assigned to the input commands “Forward”, “Backward”, “Left”, “Right”. In my scene it looks like this:

Not much action, yet, but we got things moving! Thanks a lot to Riley Gombart for providing the free-to-use top down character!

Conclusion

This is a good break for the first part. We set up the basic player movement and made the connection between the pure C# game logic and the Unity presentation. If you like to check out the whole project, just head over to Bitbucket.

Feel free to play around a bit and if you have any questions, don’t hesitate to contact me. In the next blog post, I’ll continue with this sample project, showing how to add gun firing and targets.

  • Daniel Lupascu

    Hi! I tried to get the framework dlls to load in my project. I ahve unity 5.3 and I am trying to build for webGl. Do you know why am I getting the following error?

    The Assembly UnityEditor is referenced by Slash.Unity.Editor.Common (‘Assets/Plugins/Slash.Unity.Editor.Common.dll’). But the dll is not allowed to be included or could not be found.
    UnityEditor.AssemblyHelper.AddReferencedAssembliesRecurse (System.String assemblyPath, System.Collections.Generic.List1 alreadyFoundAssemblies, System.String[] allAssemblyPaths, System.String[] foldersToSearch, System.Collections.Generic.Dictionary2 cache, BuildTarget target) (at C:/buildslave/unity/build/Editor/Mono/AssemblyHelper.cs:156)

    I have the Plugins folder directly in the Assets.

    Thank you!

    • Daniel Lupascu

      Moved the Editor.Common dll into editor folder. it is solved.

      • coeing

        Good to hear 🙂 Editor dlls have to go into a folder called “Editor”, so Unity only uses it inside the editor and removes in when building the project.

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