Applying ECS to a simple game

I’ve been going back to work on my Entity-Component-System framework. Aside from being a side project, I will also plan to use it for my voxel platform game. I’ve already created a Minimum Viable Product using it, which is the Bomberman clone game I mentioned a few posts back. Animations are still very buggy, and there is no AI implemented, but a barebones 2-4 player version is working.

Previously I initialized all the Components, Systems, and Entity templates in the framework code. While I did this for testing out the game, it’s not good for portability, so I had to remove all that initialization code out and update the framework so that it can accept new Components, Systems and templates from outside.

Finally, I isolated the code into its own assembly, so it would be possible to just link it as a DLL. This also meant I had to remove any XNA/MonoGame specific classes and all the rendering will have to do be done from outside. In short, it’s really is meant for game logic only, and your game will have to handle the rendering separately.

The framework itself is lightweight (and I hope it stays that way), and only consists of 5 files/classes: Component, EntityManager, EntitySystem, EntityTemplate, and SystemManager. The SystemManager handles all the high level control and flow of the EntitySystems, which you make custom systems from. EntityTemplate is a simple class used as a blueprint to add Components that define an Entity, and is deep-cloneable. EntityManager handles the creation of Entities from these templates, and also the organization of its components. Despite its name, there is no Entity class. I think I wil rename this manager to “ComponentManager” in another revision.

The Bomberman game has the following components:

  • Bomb
  • Collision
  • InputContext
  • PlayerInfo
  • PowerUp
  • ScreenPosition
  • Spread
  • Sprite
  • TilePosition
  • TimedEffect

They are used by the following systems:

  • BombSystem
  • CollisionSystem
  • ExplosionSystem
  • InputSystem
  • MovementSystem
  • PlayerSystem
  • PowerUpSystem
  • TileSystem

Some of the systems are more generic than others. There are a couple of systems like the Bomb system or Power-up system that have very specific logic pertaining to the game, while others like the Input system are pretty abstract and can be adapted to other game types with little or no change. Some are Drawable systems so they have an extra Draw() function that is called in a separate part of the game loop.

The funny thing is that I was going to talk about using Messages in this update, but in the time between, I did away with them completely. Messages were a static list of Message objects that was in the base System class. They were mostly used for one-time player triggered events (like setting a bomb) and every system had access to them, but I decided to just pass along the InputContext component into the systems that will be dependent on player input.

Setup and Gameplay

The game is started by initializing all the components and systems and then creating the entire set of Entities using a Level class. This class has only one job- to lay out the level. Specifically, it adds the components needed to make the tiles, sprites and players. My implementation of the game pre-allocates 9 Bomb entities (the maximum a player can have) for each player.

Each player can be custom controlled but right now that’s facing issues now that I moved from invoking methods to instantiate new Entities, to deep-cloning them. This works as well as long as none of the component have reference types.

The only Component that has reference types is the InputContext component as it needs to keep a Dictionary of the available control mappings. This breaks with deep-cloning and thus with multiple players, they all share the same control scheme. Other than that, it makes the component too bloated, especially with helper functions to initialize the mappings. So I am figuring out how to use value types only to represent an arbitrary group of control mappings.

The game starts immediately after setup, and every InputContext that is tied in with a PlayerInfo controls a player. Movement around the level is handled with the Movement System, while placing and remote-detonating bombs is handled with the Bomb System.

The Input System detects key and button presses from an InputContext’s available control mappings, and changes two integers, “current action” and “current state”, based on it. It is up to other systems to determine what it should do with these values, if needed.

The Tile System is responsible for keeping sprites aligned to a tile grid, or giving them their closest “tile coordinates” which is important in knowing where a bomb should be placed, for example.

Collision System is self-explanatory. It handles different collision types varying by enum, to differentiate solid objects, destructible objects or damaging objects, as well as the response (it pushes players off walls, for example). If a player walks into an explosion, the Collision System knows.

An Explosion System is used to propagate the explosions in pre-set directions. By default it’s in all 4 cardinal directions with a bomb’s Power attribute copied to a Spread component, subtracting one with each tile. It keeps creating more explosions until this attribute reaches 0 or it hits a wall.

The Powerup System handles tracking tile locations with the players’ own tile locations so if two identical locations are found, we know a player is over a power-up and it can be applied.

There used to be a system for drawing sprites, but I decided to remove it and have the rendering be done outside the ECS scope. This makes the code more portable and you can use your own renderer.

Now that the game is now done (with minimal specs), I am now ready to extend its use to produce one of the games I have wanted to make for a while, a top-down arena style shooter. This game will have similarities with components and systems for player movement, tile collision, and power-ups (which will be changed simply to items). I plan to make it in 2D at first but eventually switch the renderer to 3D and also offer customizable maps.

Advertisements

Returning to form?

It’s been over a year since I updated this blog so I should probably tell you what I’ve been up to. While I was working on my main XNA project, Meteor Engine, I have also been unemployed most of the time, just getting by with a bit of freelance web developer work here and there. Last April I got a full time job and it’s been great most of the time, but the company financial difficulties so they made tough choices I wasn’t happy about. Now it’s back on the job hunt for me. With my much improved experience, hopefully my job hunt now will go much quicker than last time.

So while I’m keeping an eye on my own budget, I decided to get back into the C#/XNA programming I was familiar with. This also means I am taking a new angle.

Previously I was focusing a lot on making a graphics engine. Going back where I left off, I was going to be making a shooter game. The blog will shift focus to “I actually will be making some GAEMS!!!” this time around. So my goal is to start with some base code I have and make a finished game from it.

The graphics engine could be a tool I can now add to my arsenal for making a game and it’s very likely I’ll use it here. My journey into developing the game will begin with my next post.

The current game plan

Bye bye geo-clipmaps, here comes geo-mipmapping! I’ve been busy at converting my terrain rendering code to use it from now on. It’s not fully completed but the basics work. I just need to fix up the holes that appear in the borders between different detail meshes. The terrain system has advanced a lot more than when I used geo-mipmapping. While it still only supports two textures, the cliff texture can be sampled twice in two different scales to remove any semblance of repetition. No fractals or noise patterns here, it’s all from pre-made texture images. I’m also messing around with a vignette effect, currently made part of the Depth of Field shader. The engine is also now running with a game screen framework built on top of the official XNA sample.

screen28-1

Now to move on to the game structure itself. I’m not too keen into drawing UML diagrams or other fancy charts, also because I have not gotten really comfortable with a diagram editor. I’d rather sketch them on paper and take some photos of it with a phone. But I do have a tree-like structure to organize my code in.

This planning comes easier as I figure out the first thing I want to do with my terrain renderer is to put it in a game state that will later on be the in-game map editor.

The puzzle game I made earlier made a good learning experience in understanding how a screen and menu system can be put together where multiple states and screens run independently of each other. The game may not be 100% done, but its code is stable enough for me to be able to port the screen system into this new game. Because this would be the most complex game I’ve attempted, I look forward to seeing how far I can take it. With a loading screen and transition to game modes are in place, it will at least finally start feeling more like something with a greater purpose than a tech demo.

The graphics engine is still a work in progress so I will work on it together with making the game. The game code will be organized in three different areas: Core, Game, and Screens.

Core

  • Graphics engine (my own)
  • Physics engine (BEPU or maybe Bullet)
  • File saving/loading
  • Input
  • Networking
  • Screen system (from my last game)
  • Menu interactions
  • Screen drawing/updating system

Game

  • Game logic, AI
  • Player interactions
  • Game objects
  • Editor
  • Editing tools and functions

Screens

  • Background(s)
  • Loading screen
  • Menus
  • Gameplay modes
  • HUDs and interfaces

Core contains all the systems that deal with the lower-level workings of the game. Sending data to the graphics engine, setting up and managing physics, input management, and the loading and saving of files all go here.

Game contains all the very game-specific logic that’s all about setting the rules, game modes, and specific interactions with game objects. They all tie into Core in some way, depending on what they are responsible for doing. A more specific area, Editor would include all the tools and functions used for the game’s map editor mode.

Screens can be seen sort of like game states and also like components that, when grouped together, can describe a game state or mode of behavior. They are loaded and ran from the screen system, and either specialize on displaying information related to the game, or tell the user what actions are available. Background screens, gameplay screens, HUDs, inventory screens, and menus would belong here.

As you may have noticed, the three groups tend to progress from low-level to high-level code. This was not really intended, but does give me a better idea of how to pass data around.

The graphics engine is already running in the screen system. When the program launches it add a Screen to a list, which loads the content to be rendered. Here is the game loading a terrain in real-time, with some interactions handled by an “Editor” screen.

(lolwut, YouTube detected this video to be shaky. It’s all rigid camera movments in here)

There are a few issues I have to take care of with the screens and graphics. Both the screen system and graphics engine are loaded as XNA game components, which means they draw and update automatically within the game, outside of the screen system’s control. Although the content loading code is in the Editor screen, I need the option to make the explicit choice of what order the graphics should be drawn, so that any graphics that are set in a particular screen get drawn with that screen’s Draw call.