Lived 3D

Technical Art Ramblings

  • BLOG
  • Privacy Policy

SeaBomb – Getting Started

Getting Started Header.

Back to Basics

Logo for the SeaBomb game engine.

At the start of my epic stay-cation I had huge ambitions: I was going to have a basic playable demo of the game up and running by the end of my break for anybody to check out. Well, it didn't take to too long to realize that I was lying to myself on my time estimates when scheduling.

I simply neglected to double my time estimates when planning. Normally this is second nature for me at work when dealing with a high stress production environment. Even in that situation where we already have huge advantages like, I don't know, a game engine, or a decent pipeline, tools, and lots of talented people; Even with these advantages, sometimes those time estimates can be tight.

So throwing down into an environment where I'm staring at an empty C# project called "SeaBomb” (the name of my intended game engine) and a little voice in the back of my head telling me “What the hell are you doing, just go download Unreal?!?” I found that all my initial expectations and plans ran over by at least 3 times as what I initially predicted.

In the end, I looked over my initial post, and decided to re-prioritize. I wanted to make sure that I could get a lot of the heavy lifting and back end work done fairly well before going back to work. The kind of things that are demoralizing and difficult to do after a full day at work. Additionally, I reinforced the desire not to use a ready made game engine, this exercise was to primarily educate myself better in programing. Keeping that in mind, here's the break down on “The Plan 2”:

  • Project setup and git repository structure for the game engine (hereby dubbed “SeaBomb”), and the game.
  • An “Asset Manager” for handling the loading of all game data.
  • A build pipeline for building all of the game data and making sure the game only loads prepared data.
  • The start of a “Render Manager” for abstracting away Sharpdx from the game.
  • An implementation of the entity component system.

5 goals, in 5 weeks. That blank project file was looking better already. Still didn't stop me from procrastinating away on an engine start up screen though :P

Project Setup

I decided to keep the core engine code, the game project, and build pipeline in the same repository. Additionally, I set up a post build step to copy the game and the build tools into a folder outside the repository, and created links to them on my desktop. A .Gitignore file was set up to ignore any files that were built by Visual Studio, and any back up files produced by art programs. I know it all seems like simple things to do, but they achieve a couple of things I find important:

  • Built data is never stored in the repository. Sure, cache it somewhere to help the build pipeline, but don't version control it.
  • Backup art files are never version controlled. Seriously.. backups are what version control is for.
  • The engine, data, and game are always in sync. At any time I can got back in my version history and know everything will work.
  • I have access to my build pipeline easily outside visual studio when I'm doing art.
Screenshot of project layout.

Ok, so sue me, I spent some time procrastinating on making icons for the build tool, and the game... Hey, it's the little things in life sometimes.

Asset Manager and Build Pipeline

To start out with (and indeed for the majority of my holiday time), I wrote the asset classes. These are things like Image, Material, Shader, and Model, and the AssetManager. It's this work that XNA had already done for me on my last engine, and is where my time estimates fell apart. The asset manager deals with loading and caching of these items, and their dependencies, so they never get stored in memory twice. Requesting an asset looks like this:

  • AssetID gunID = @"\Source\Models\Guns\Wraith.dae";
  • AssetManager.Load<Model>(gunID);
  • Model gun = AssetManager.Get<Model>(gunID);

Along side this I worked on my build pipeline. I really wanted to keep any external libraries that are not core parts of the game engine completely away from the game code.

The build pipeline at the moment is fairly simple. It works out a dependency tree, and then builds everything in the order needed. I don't currently cache any intermediate data, and I always build everything for now; All problems I can tackle later on when I'm building enough data to need it. As an aside, this morning I played around with Graphviz and the dot language in my build project to produce a nice graph of the dependencies. If you haven't seen this program, check it out, it's pretty neat!

Build pipeline graph.

As you can see from the graph, I've used Lua to describe a lot of data formats. There are a couple of reasons I've done this over using XML:

  • I just plain like how Lua tables look for storing data.
  • I find them pretty easy to use in conjunction with C# using LuaInterface. Integration into the project is dead easy.
  • It's nice to be able to use code to define data. I could conceivably have a random level generator in my build pipeline using Lua; My game engine wouldn't have to know anything about it other than the final output data.
  • I can use mathematical operations in line in my table. That material color is too bright? Just go “color * 0.5”.

I'm not yet committed to using Lua in my game project, but converting this data into binary files in a build pipeline means I can put off that decision until later. An example of a material definition would look like this:

  • Shader = "\\Source\\ShaderDefinitions\\Basic.lua"
  • Properties = {
    • {name="AlphaClip", type="float", value = {0.5}}
  • }
  • PixelShader = {
    • Textures = {
      • colMap = {Asset = "\\Source\\Images\\Guns\\Wraith_col.png", Register = 0},
      • nrmMap = {Asset = "\\Source\\Images\\Guns\\Wraith_nrm.png", Register = 1},
      • mskMap = {Asset = "\\Source\\Images\\Guns\\Wraith_msk.png", Register = 2},
      • glsMap = {Asset = "\\Source\\Images\\Guns\\Wraith_rfn.png", Register = 3}
    • }
  • }

The pipeline is also driven by a Lua file. For example, to build the loading screen models, and a gun, my content file looks like this:

  • AddAsset("\\Source\\Models\\LoadingPositive.dae", "ModelFactory")
  • AddAsset("\\Source\\Models\\LoadingNegative.dae", "ModelFactory")
  • AddAsset("\\Source\\Models\\Guns\\Wraith.dae", "ModelFactory")
Screenshot of a work in progress space ship.

At any rate, after a tough couple of weeks of programming, I sat down to do some low poly 3D doodling for the main character ship idea. Yup, procrastinating again!

The Entity Component System

At a very basic overview, an Entity Component System (ECS) is a way of organizing data and functionality in a modular way, that allows for flexibility, and (hopefully) efficient processing of data for game systems.

The entity is effectively your game object. The components are effectively data that get added onto entities. The systems are the processes that run over that data defining how everything behaves. I won't go over this in detail, I read many great blog posts about this, and they'll explain it far better than I ever would:

  • Boreal Games - Understanding Component-Entity-Systems
  • Boreal Games - Implementing Component-Entity-Systems
  • Mick West - Evolve Your Hierarchy

I set about implementing a fairly basic ECS with 4 basic components:

  • Transform3D – The objects location in the world.
  • Camera – A component that contains the camera data.
  • RenderImage – A 2D image that docs to any specified part of the screen, and offsets by the Transform3D.
  • RenderModel – A 3D model.
Screenshot of a work in progress space ship.

This finally allows me to render something on the screen! So, coming up to the last weekend of my stay-cation I quickly jammed in a couple of game states:

  • My engine boot up screen that shows the logo.
  • A loading screen that runs while the game loads in the background (At the moment I've had to sleep the loading thread to even see this. The ship model loads too fast).
  • A game state that loads and spins around a Gun model for the ship I've been procrastinating on (again)!
Video of the early tests

Enjoy the vid :) I know it's not much, but hey, I've learnt so much over the last few weeks! Additionally, I feel like I've done enough heavy lifting that I'll be able to continue on with some interesting things in my own time after work.