I’m about to talk a little bit about what this editor is for and a bit about our framework architecture, if you’re not interested in that then you can just skip right down to the “editor and tools” section near the bottom.
Introduction to Pepper Wars 0.5 and Tall Order Games
If you’ve checked out my portfolio already then you might have seen one of my previous solo games, ‘Pepper Wars’. Pepper Wars is a PVP local multiplayer networked game, where two players fight with their armies to destroy the other army and or castle in order to win. There were multiple units, each with their own unique abilities.
It was similar to Advance Wars, Fire Emblem and Final Fantasy Tactics. All games that I’ve played and adored. It was fun to build (and my first time networking a game), but it didn’t have good replayability and was very confusing for people who hadn’t played games like it before.
I recruited a few very talented people from my University and together we started to build what I am code-naming ‘Pepper Wars 0.5’. Development began as of February 2017 and since then I have been building a SFML based framework with an editor and tools. Before I show you them, I’ll quickly go through our game architecture and answer some questions you might be wondering.
Software & tools used
- Visual Studio 2017
- Sublime Text for JSON & Lua
- ReSharper C++
- SourceTree & BitBucket for Source Control
- JIRA for handling tasks, bugs and improvements.
- SFML 2.4.2 C++
- Elias Daler’s ImGUI SFML bindings
- Signals, a C++ delegate/signal/event library.
- nlohmann’s JSON for modern C++
Why not Unity, Unreal or another game engine?
This is one of the questions that I’ve been asked a lot when talking to people about this project – and it’s a completely fair question. I’ll outline my main reasons now and get them out the way.
- SFML is a 2D dedicated framework. It’s free, easy to pick up and can be extended to make any sort of 2dgame.
- A lot of our team members come from an XNA/MonoGame and SFML background.
- Some of us have also spent time modding games (including Dota2) where the scripting language used is Lua.
- We have full control over everything. We can design our systems from the ground up and if there’s a bug, or something sucks, it’s our fault and we can do something about it.
- Building a framework is time consuming, but it’s also fun, teaches you a lot and looks good on your CV.
- Our game has tools-driven workflow and mod-ability in mind. We want the designers to be a able to create lots of missions and have a lot of control over the game.
- We can use dear ImGui. I really like dear ImGui.
- We can use C++ and a ton of awesome C++ libs.
A brief overview of our games architecture
Our architecture is heavily inspired by many patterns outlined in “Game Coding Complete, 4th edition” by Mike McShaffry/David Graham and “Game Programming Patterns” by Robert Nystrom. These are both great books and I recommend them thoroughly – even if you’re not making games.
Actors and our component system
Actors are made up of a set of components. Components are not behavioural and contain only data (similar to a Entity-Component-System).
Game state, logic and view
The game state is a “Scene”. A scene is split into the “Logic” and the “Views”.
The logic directs the current game states direction by doing things like deciding on what unit has what turn, what scripts should be run and creating/ending certain game processes. Logic can be defined in C++ or Lua, but typically it will be defined in Lua.
The views are responsible for the way that the player perceives the game. For example, the “RenderView” is responsible for rendering every actor that has a “DrawComponent” and the “EditorView” is responsible for drawing whatever editor widgets are active, if any. Views are typically defined in C++, as they are a time critical part of the game but they can also be done in Lua, for things like the UI that may require a lot of time to edit/perfect.
The event system is how all of our games logic, view, processes and editor communicate without knowing about one another.
For example: When the game scene object is being imported and the actors are being generated, the “ActorManagerProcess” will listen for the “CreateActorEvent“. The CreateActorEvent holds a shared/smart pointer to an actor that has just been created. The actor manager, upon hearing that this event has been triggered, will now store a reference to the actor that has been created. When the “DestroyActorEvent” is triggered, the same ActorManagerProcess will remove its reference to that actor. Thus the ActorManagerProcess now has a internal collection of all active Actors on the scene (as well as keeping them in memory!).
This allows for decoupled behaviour between all of our processes/systems and scripts.
Also: Events can easily be serialized and sent down a network!
A process is a lifetime object. By that, I mean that it has a beginning (initialize()), a life (update()) and an ending (onComplete()/onFail()). This exact pattern is covered in Game Coding Complete, so I don’t want to go into it too much.
A process, once started, can be completed or failed. Completion or failure can will sometimes have different behaviours. It can also have a child process, which is the process that takes over after its parent dies. It can also be paused, which means its update() will not run until it is unpaused.
A process in our application can be relevant to our current scene or it can be global. Essentially this means that some processes will run through the entire lifetime of the application (global) and some processes will run only for the lifetime of the scene.
An example of a global process would be networking or io and an example of a scene process would be script execution (as it’s actor-specific).
The editor and tools
At this point, you might be thinking “thank god, finally!” – so without further ado, here are the editor and tools that we have built for Pepper Wars. I’ve also included some features that we’re currently implementing and some ideas of what we’ll be looking at in the future.
[Editor] Tilesheet importing
The tilesheet importer allows the designer to import a spritesheet and split it up into it’s individual tiles.
Right now we’re working on a feature that will allow the designer to create default components for tiles that we import, so when they are painted into the map those components will be there. This stops the designer from having to manually edit each tiles data as it’s painted, making the workflow quicker and easier.
Tilesheets also help us keep a record of what large spritesheet textures have been brought into memory, so we can remove them from memory when the scene ends.
The tilemap editor allows the designers to create our in game maps.
- Painting and erasing individual tiles from an imported spritesheet.
- Ability to select individual tiles as actors and edit their components, id and data.
- Ability to fill neighbour tiles so you don’t have to paint everything.
- (To do) Define pathing data for the pathfinder to use.
- (To do) Allow importing of a .tmx file from the popular tile map editor, Tiled.
- (To do) Define and preview light sources.
[Editor] Actor and component editing
The actor editor allows the designer to create an actor that is saved for later importing (in the scenario designer, in a script, etc). It allows you to edit the actor data (name, id, active) as well as adding, removing and editing components.
Actors are exported in JSON, which means they can also be edited directly inside the file if necessary.
Later, when the command line is complete – this can also be an environment for running scripts against our actor.
[Editor] Level & Scenario designer
The scenario designer allows our designers to customise levels and scenarios inside the game without having to touch the underlying code or markup files.
- Import and create a copy of a tilemap that has been created.
- Import (or create) actors and edit their components, scripts and data.
- (Todo) Align actors to the tile grid.
- (Todo) Customise pathing data for the pathfinder, overriding the tilemap data.
- (Todo, Lua) Customise the scenario specific settings, (e.g. type of scenario, conditions and scripts).
[Editor] Animation editing & importing
The animation editor allows the designer to create reusable animations for the game. While editing the animation component, to add an animation you just point to a saved animation file that we’ve created.
- Ability to manually define each frame of the animation from the sprite sheet.
- Change the order that the frames are played in without editing the sprite itself.
- Test the animation in a controlled environment, where no other actors or logic will interfere.
- Change and test different frame rates
- Change the texture without breaking code in other scripts.
- (Todo) Use the splitter tool to automatically figure out each frame of the animation.
[Runtime Tool] Process list & editor
When we talked about the architecture of our game, I mentioned that we have processes that run in the background of the game. These processes can be completed, failed, paused and unpaused.
Testing these processes can be difficult without writing certain trigger code or a command line argument to edit that specific process, so we created a tool that keeps a track of all alive game processes and allows you to edit their state during the games runtime. This helps us debug the scene and figure out what processes are causing the problem, if any.
[Runtime Tool] Actor hierarchy tracker & editor
This is much the same as the actor editor mentioned before, but instead of editing an actor to save to a file – this tool allows you to edit and view all actors that are available on the scene. There are even options to filter actors by their name, as well as the components that they do and do not have.
If an animation isn’t playing correctly, or an actor isn’t doing something it’s supposed to – you can simply open the actor hierarchy tracker tool, find the actor that you’re looking at and view its current components and data. This allows you to track down bugs and strange behaviours in an easier manner.
[Runtime Tool] Event log & tracker
This simple tool is incredibly useful for understanding what is going on in the current game loop, as well as debugging behaviours and finding errors.
It simply keeps a log of all of the last four-hundred events that have been triggered in the game, with options to filter out events so you can see if the event you’re expecting to be triggered is actually being triggered and listened too.
Another feature that we’ll be adding later is the ability to view the event data in JSON.
[Runtime Tool] Logger
Our logger is a simple tool that displays the last one-hundred logger messages and allows the user to filter them by their categories. Messages can be sorted into the categories ‘Debug’, ‘System’ and ‘Error’.
[TO-DO, Runtime Tool] Network log
The network log just records incoming and outgoing packets from the client and the server and holds a record of them in the log.
We will also be able to hover over an entry in the log, which will show the packet data in JSON. There will also be filter options to help find certain logs.
[TO-DO, Runtime Tool] LUA based command line
A command line would be great for editing, debugging and trying new things out in an empty scene. Our commands will all be done in LUA syntax, as we are embedding Lua as our games scripting language. A small set of features that we could do through our command line:
- Anything we can do inside of a Lua script, including moving the actor, changing the animation, etc.
- Create blank actor & load actor from a file.
- Run script against actor.
- Open and close network sessions to specific IPs.
- Generate packets and events.
Conclusion on the editor and tools so far
Editors and tools are awesome! This is the first project I’ve ever done that has required a full tool set. A few final thoughts:
- I need to spend a bit of time thinking about the UI design of the editor. So far, other people that have used them have found them quite un-intuitive, so I’ll probably redo all of the interfaces before handing it out to team members or consumers. I’ll also need to write a guide.
- It’s amazing how much code has been reusable in the editor. Designing it has shown me a lot of great examples of good abstraction and code re-usability. Something I’ll discuss further in a system design / architecture post.
- I’ve spent longer on them then I’d like, but honestly I’m having quite a lot of fun making them – and I think there’s a good argument for having a full set of easy to use tools that speed up the games development – especially if you’re planning on having a mission creator / mod-ability in the game release.
- I need to figure out what’s up with my compile time. Currently taking 2 full minutes for compilation on a project that’s relatively small. (Yet another argument for Lua.)