It’s been a while and I apologize for that.
Over the past few months, I’ve nearly abandoned my game project. However, the process didn’t follow the blog exactly. First I did some major changes to the architecture and advanced the process of making Pucaj miles ahead of what it was. Then I abandoned it for over two months, only to return to it a few days ago. Because of that, it took some time to reintroduce myself with code, but it also exposed some holes in code readability and maintainability that I will now be able to fix. This is almost a completely different project now, so I’ll try to make a short list of what’s new.
What’s new?
- Shift from a purely object oriented design using a sort of MVC architecture to an Entity-Component System
- Removal of old graphics and switch to single color placeholder tiles.
- Removal of the shooting mechanic and action controls with keys.
- Addition of proper touch controls, including gestures.
- Map generation using a slightly modified diamond-square algorithm.
- Menu system using the Scene2D UI functionality.
- Background asset loading with a loading screen.
- Basic AI.
So let’s go through this one at a time
Shift to an entity-component system
An entity-component system (ECS) is something completely new for me, but I’ve been reading about it a lot and the more I look at it, the more it makes sense, so I made the shift.
I won’t explain in detail what it is, but in short, instead of a hierarchical relation between game objects, we now have a world object which holds a list of entities.
What is an entity? Each entity is a simple identifier, in my case an integer, nothing more. You use this integer to give an entity components. So what’s a component? A component is an object holding some data for an entity, related to some aspect of it. A map position is a component holding the X and Y coordinates for the entity. Sprite is a component holding the texture for the entity. Animation is a component holding an array of sprites for an entity. Movable is a component holding an array of coordinates the entity can move to.
The important thing here is that entities should not contain logic, only data. For logic, in an ECS, you use systems. Systems are basically entity processors. They maintain a subset of entities currently existing in the game world, that have certain components. A movement system would have access to all the entities in the world that have the position and velocity components. On each tick, it would go through all of these specific entities and use the velocity data to update the position data.
Again, there is an entire science behind this, so instead of going into details, I’ll just give you some links…
Links
This is an entire series explaining the idea behind an ECS. If you’re interested in this approach (and I really think you should be), go and read it. It will give you the basics and explain the logic and motivation behind some aspects of the ECS approach.
This is another good article that explains the idea behind it all. It’s a shorter read, but it’s a bit quicker to go into the practical approach.
Another good read. Be sure to visit the articles and sites he’s linking to also, just like with all the other links.
A good idea is to also visit gamedev.stackexchange, since there are plenty of specific questions about ECS there.
In the case of Pucaj
In the case of Pucaj, I’m still working out the details, but here’s where we’re at for now:
Components
- Abilities – for any entity that has access to abilities. This one is likely to go away, break apart or change completely in some other way, as I’m still working out the actual game mechanics.
- AI – for controlling a computer unit/player. It’s a very dumb AI implementation and will likely be replaced by several different AIs, or possibly even a sort of network of AIs, working together.
- ColorAnimation – for entities that change color over time.
- Cursor – not used anymore. I had an idea to have a key-controllable cursor displayed on the map, but keyboards controls have been removed for now.
- Damage – for giving damage to an entity.
- Expiration – for an entity that will be removed after a specific amount of time.
- FadingMessage – for displaying a message that disappears after a while. It should probably be broken apart into something like TextSprite + Expiration + Movement + Fading or something.
- MapPosition – for entities that are placed on a spot in the map grid.
- Movable – for entities that can be moved, so they need to have possible places to move to displayed.
- Movement – for entities that are currently moving along a path.
- Player – for entities controlled by the player.
- ScaleAnimation – for entities that change size over time.
- Selectable – for entities that can be touched/clicked on.
- Sprite – for entities with a simple graphic.
- SpriteAnimation – for entities with an animation graphic.
- Stats – for entities with stats. Like Abilities, this one is extremely likely to go away, break apart or change in some other way.
- Velocity – for entities that move at a certain rate in a certain direction. Not used for now, since this is a grid-based game. It might be used later, for missile entities.
So those are the components I have right now. As I said, entities only hold the data, so most of them contain some fields or properties and a constructor. A select few, such as Player are completely empty and only exist to serve as an indicator. Their attachment to an entity itself is the data – a flag indicator.
Systems
Systems are there to handle the logic. Each system handles a subset of entities that hold specific components and processes them on each tick (or in some other way, depending on the type of system.
- AISystem – handles entities with AI components, making decisions for them. For now, these entities also need to have a Stats, Movable and Abilities component, but that’s bound to change eventually. A good example of where it might change is if we ever have a stationary turret – it would not have a Movable component.
- CameraMovementSytem – this is actually a system that doesn’t work with a list of entities. It simply moves the camera in certain ways as needed.
- ColorAnimationSystem – handles entities with the ColorAnimation component and changes their color as indicated by the component data.
- DamageSystem – handles entities with the Damage, Stats and a MapPosition component. It creates damage labels (entities with FadingMessage), handles removal of dead units, etc.
- ExpirationSystem – handles entities with an Expiration component in a very obvious way.
- FadingMessageRenderSystem – again, a very obvious system. Handles fading messages.
- HudRenderSystem – another system that doesn’t deal with components directly. For now, it just renders the FPS counter.
- MovementSystem – handles entities with MapPosition, Movable, Sprite and Movement using the data to update the position.
- PathRenderingSystem – obsolete. It used to render a dotted path from the current position of a unit to the target position.
- ScaleAnimationSystem – this one should be fairly obvious. It handles entities with ScaleAnimation and Sprite in order to change their size.
- SpriteAnimationSystem – much in the same way, this one handles entities with SpriteAnimation and Sprite. It sets the sprite texture to the current animation frame.
- SpriteRenderSystem – very obvious. It takes entities with Sprite and MapPosition and draws them on the screen. It also uses a list of SpriteAnimation entities to handle their insertion into the world and set their initial frame.
- TurnManagementSystem – this one handles entities with Stats. It determines their acting order.
I also have a few classes that currently aren’t actual Systems, but will probably become systems in the future. I’m just having trouble figuring out how to best do it.
- MapRenderer and MapHighlighter render the map and the movable to area around the unit once you select it. I’m thinking they should be fairly easy to transform to proper systems, but I didn’t get a chance to do it yet.
- Various input controllers – I have several different input controllers, each handling a different aspect of user input. Some should be easy to transform, but some not so much. Most people seem to agree that the input layer should be mostly decoupled from the ECS and communicate with it via a system of intents, but I haven’t completely figured out what those intents are supposed to be and how it would work with a turn-based grid game.
Switch to new graphics
Let’s be honest here. I suck at graphics. Using the old set I’ve been spending hours to make is useless for me, since they are bound to be different eventually. Because of that, I’m keeping it simple. I kept the tank graphic I was using and switched to single color tiles for the map. Once the logic behind it all is in place, I’ll start worrying about making actual, proper graphics. Who knows if this will ever be an actual game – it’s better to worry about those things later.
The tiles I have now are easy to maintain and simple to work with.
No more action controls
This was expected, since it wasn’t supposed to be an action game. I was just playing in a sandbox previously. Instead..
Addition of proper touch controls
You can now zoom the camera in and out and move it around as you please. Even better, it works with a mouse as well as touch gestures. You can scroll and/or pinch to zoom in and out and you can drag to pan. A double click/tap smoothly moves the camera to the active unit.
Map generation
I found some guides and I made a map generation. I’m not completely certain maps will be generated in this game, but it was a fun side-project to do and figure out, so I did it. Look into Diamond-Square if you’re interested in it. Basically, it generates sort of realistic looking topography maps and is well-suited for square based grids, but it could also be adapted to hex grids, for instance.
The current parameters make a relatively small map, so the above video won’t make it look especially great, but you can go way bigger if you want to.
Here are a couple of screens of a slightly bigger one:
See those tiny little dots on the pictures? Those are the tanks from the video above. Also, all three of these screenshots are different places of the very same map. Fun stuff, right?
Menu system
Scene2D, which is part of libGDX, has a built in menu system I’m currently using. It’s not pretty, but it’s functional. I haven’t decided yet if I’ll keep using it, modify it, or go with something more visually oriented.
Background loading and loading screen
This should be self-explanatory. I don’t have many assets right now, but I’m expecting the amount to grow, so there will be a need for some sort of preloading mechanic. Since it will hopefully be a relatively tiny game, I feel it’s best to just preload everything into memory at start-up.
Because of that, I designed an asset loading singleton. At game start-up, this manager loads everything into memory and holds it there. Instead of loading each individual asset as I need it somewhere in the game, I now simply ask the manager to give me the desired asset. I use a loading screen to notify the user of this process.
Now, as I said, the amount of assets is very low right now, so the loading screen goes away quickly. I actually had to add an explicit delay in order to show it during testing.
Basic AI
I also implemented a very dumb AI player to control the two enemy teams. Right now, as you start the game, three teams are generated – the player team and the red and blue AI teams. It’s a free-for-all so everyone is fighting everyone. You can see this in one of the previous videos, the one demonstrating the menu system.
As I said, the AI is extremely dumb, but it does heal and execute attacks, so it’s fun for messing around with. I’ll make it smarter and try to give it more personality at a much later stage.
And that’s it! This is the scope of the changes that happened to my “game” over the last few months. I’m back into it now, so hopefully, you’ll get more frequent updates for a while.