Advice for a "decoupled" game engine

Started by
9 comments, last by Norman Barrows 8 years, 2 months ago

Hopefully, the word in the title is appropriate to express what I'm looking for, but basically...

I'm looking for a game engine that doesn't tightly integrate with the game logic itself. Certainly, I know that the more batteries-included an engine gets, the less true that tends to be, so I'm looking for that sweet spot where I don't have to write a bunch of rendering/windowing/audio code, but that I can rip out my gameplay logic and port it over to a new engine within a week or two of work. Reason being that I don't really know how my game will scale, but I have a sneaking suspicion it could cause performance problems on an engine not well-tailored to it.

Normally I wouldn't mind just writing everything myself (and actually started to), but at the same time, I do actually want to get something done for once. However, I don't want to be stuck in a situation where I can't do what I want to do because "Engine X" doesn't support it. I suspect that sweet spot might be just picking up a rendering engine a la ogre (since my workloads probably won't be graphics-heavy) and running with it, but I'm not sure. In common software parlance, I guess I'm looking for a library rather than a framework.

Advertisement

I am sure there are better things out there than anything I've made, but if you're interested I've got an engine (and an assortment of tools) which can be found here. https://github.com/cppcooper/ToolBox

I have it separated to three separate libraries.

class glEngine (provides windowing / input event callbacks / threaded environment ) : ToolBox/GFX/gl_engine.h

class Asset_Faculties (Asset Management + Asset Definitions) : ToolBox/GF/game_faculties.h

class Game (flexible Framework) : ToolBox/GF/GameFramework.h

It would thrill me to have somebody else trying to develop with it to point out flaws or bugs I have yet to find, or missing features.

Switching game engines mid development will never be an easy thing to do, even if you write your code in a way to do it. I would recommend picking an engine from the start and sticking with it.

That being said, to write your game logic game engine agnostic, you will need to build out lots of interfaces. You would implement your logic using the method available on the interfaces and have concrete implementations for each environment you want to support. This would add a lot of work to the game, so again, I wouldn't recommend it. Although one benefit to this approach would be that your code with be testable. You could write unit tests around your game logic using a test implementation of the game interface. The same applies for server side logic, you could run the same game logic code server side outside the game engine.
My current game project Platform RPG
Just write all your gameplay code so that there's one layer between it and the engine. That should be possible in Unity/etc...

I've rewritten the renderer of an engine before, without the gameplay team being aware :)
First I made a convoluted layer on the engine side that was compatible with the old game->renderer code, and then I worked with them to rewrite the small amounts of gameplay code that directly touched this API and port it to the new one.
Ideally, the parts of gameplay directly touching engine APIs can be quite small.

A bigger issue may be that different engines run on different languages. You might make a full C# game in Unity and have to port it to Unreal's C++...
Be careful not to fall into the trap of writing layers of abstraction over an engine that is already one or more layers of abstraction itself.

Also, API coupling is a minimal concern, IMO, which is what you are looking to eliminate. Transitioning to a different API is a pain and takes time, but how much more time than building and maintaining additional abstractions up front that you're not even sure you'll need?

A concern that you should have beyond API coupling -- and in my experience is a bigger problem than API coupling -- is feature and pattern coupling. If you set out from the beginning to write a codebase that is decoupled from the engine, you will have to be careful to only use the subset of features of that engine you can be sure will be available in any other engine you may wish to transition to. Otherwise you will find it simply impossible to use another engine, or at the very least find yourself writing code of your own to replace the lost features.

Just write all your gameplay code so that there's one layer between it and the engine. That should be possible in Unity/etc...

I've rewritten the renderer of an engine before, without the gameplay team being aware smile.png
First I made a convoluted layer on the engine side that was compatible with the old game->renderer code, and then I worked with them to rewrite the small amounts of gameplay code that directly touched this API and port it to the new one.
Ideally, the parts of gameplay directly touching engine APIs can be quite small.

A bigger issue may be that different engines run on different languages. You might make a full C# game in Unity and have to port it to Unreal's C++...

Not being experienced in Unity, I thought it was based around writing gameplay code in some special snowflake C# variant? I want to avoid being tied to magical scripting languages like Unity/C# or Unreal blueprints.

What I'm after is an engine where I don't lose control of the program flow (i.e. the IoC "don't call us, we'll call you" style of frameworks or mobile apps); where I can still control thread management and the like. I'm expecting my game to be very CPU-bound, and I'll probably need the flexibility to be able to squeeze everything i can out of it.

You're right that language portability is an obvious issue. I should have clarified that I'm targeting C++, and I think being stuck in C++ ecosystems is a reasonable constraint on what i'm looking for.

Be careful not to fall into the trap of writing layers of abstraction over an engine that is already one or more layers of abstraction itself.

Also, API coupling is a minimal concern, IMO, which is what you are looking to eliminate. Transitioning to a different API is a pain and takes time, but how much more time than building and maintaining additional abstractions up front that you're not even sure you'll need?

I'm not really worried about API coupling. It pretty much goes without saying that switching engines will require restructuring, which is why I cited a few weeks rather than something like a day. What I'm worried about is platform coupling. I want to ensure my game code has enough autonomy that if I need to do something like change what database I'm using, how I'm handling IO, how I manage my threads, or how I manage memory to be beholden to anything but my language runtime (which is usually circumventable anyway). Basically, I don't want my gameplay code to be sandboxed (is that the right term?)

Sounds like what you really want is a good engine with full C++ source code available so that you're not trapped by it's current implementation issues. Working at large game studios, the things you cite aren't a concern because there's no great big wall between gameplay code and engine code -- if something isn't possible, you just add the code to make it possible (whether that code goes into the engine folder or the game folder).

From the big boys, that's Unreal 4, or Stingray if you have money (or charisma to dodge the money requirement), or CryEngine if you have money/charisma and are also a masochist.
Then there's the smaller engines like C4 (soon Tombstone), or all the open source ones made out of Ogre plus Bullet plus FMOD, etc... Or you can join that latter category with your own wink.png
I would shamelessly pimp my own but it's not usable yet laugh.png

Not being experienced in Unity, I thought it was based around writing gameplay code in some special snowflake C# variant? I want to avoid being tied to magical scripting languages like Unity/C# or Unreal blueprints.

Unity uses C# v2 IIRC, or any language that runs on that version of Mono - e.g. a friend was writing a Unity game in Boo, and then ported it to Lua for CryEngine sad.png
You can always call out to external DLLs though - whether they're also .NET languages, or native code (See Mono's PInvoke)


Sounds like what you really want is a good engine with full C++ source code available so that you're not trapped by it's current implementation issues. Working at large game studios, the things you cite aren't a concern because there's no great big wall between gameplay code and engine code -- if something isn't possible, you just add the code to make it possible (whether that code goes into the engine folder or the game folder).

From the big boys, that's Unreal 4, or Stingray if you have money (or charisma to dodge the money requirement), or CryEngine if you have money/charisma and are also a masochist.
Then there's the smaller engines like C4 (soon Tombstone), or all the open source ones made out of Ogre plus Bullet plus FMOD, etc... Or you can join that latter category with your own
I would shamelessly pimp my own but it's not usable yet


I really should look into Unreal. It's gotten so stupidly easy to acquire over the years that I really have no excuse. I didn't know what Stingray was until I looked it up and found out it was a rebranding of BitSquid, which I remember for some interesting technical blogs some years back. I've heard enough about CryEngine to know to stay the hell away from it. :)

Honestly, engine tech fascinates me, and I'd be all over building my own engine for fun, but I also want to finish something at some point.

Thanks for the suggestions.

seems there are two basic approaches:

1. use a generic game engine. the engine has all the low level stuff: audio, graphics, timers, input devices, etc, including the list(s) of game objects (or CES) and the main loop. you in turn hang game specific code off that via callbacks. porting to another engine can be tricky. do they have hooks (callbacks) in the same places in the main loop? you have to adapt the game code you hang off the engine to the way the new engine works, shuffle things around a bit most likely. as hodgman says, if you have source access to the engine, you can mod the current engine instead of switching to a different engine.

2. a custom engine with low level libraries. the engine has the main loop, objects list, world map, etc. low level iibraries used by the engine provide audio, graphics, timers, etc. the trick to keeping it decoupled is an abstraction layer between the game engine and the low level libraries - again as mentioned by hodgman. take audio for example. for basic audio all you need is a simple API like playwav(wav_ID), loopwav(wav_ID), stopwav(channel_ID) wav_is_playing(channel_ID). so you write those four routines for whatever audio library you choose, and the engine just calls them, not the audio library directly. so if you change audio libraries you just write new versions of those four routines, and don't have to change any game code at all. using this method i've used the same basic audio API for all my games with diamondware STK, directaudio, and xaudio2. heck, the getmouse() routine API for my game library has been unchanged since Dos interrupt 0x31 ! and it now uses win32 sdk message queue. i've managed to keep the same basic game library API through: dos 5, dos 6, dos extenders, and win95 through windows 10; basic, pascal, and C++; diamondsware STK, directsound, and xaudio2; mode 0x13, VESA SVGA, in-house p-correct t-mapped software poly engines, directx8, and directx9. how's that for flexible and decoupling? <g>. right now for low level ibraries i use dx9 for graphics, xaudio2 for audio, and winsdk for things like high rez timers and input devices. but any time i want i could make a dx12 version of the graphics API and simply recompile all the games and voila, the're all ported to dx12! (not necessarily using dx12 capabilities, but running dx12 code).

Norm Barrows

Rockland Software Productions

"Building PC games since 1989"

rocklandsoftware.net

PLAY CAVEMAN NOW!

http://rocklandsoftware.net/beta.php


1. use a generic game engine. the engine has all the low level stuff: audio, graphics, timers, input devices, etc, including the list(s) of game objects (or CES) and the main loop. you in turn hang game specific code off that via callbacks. porting to another engine can be tricky. do they have hooks (callbacks) in the same places in the main loop? you have to adapt the game code you hang off the engine to the way the new engine works, shuffle things around a bit most likely. as hodgman says, if you have source access to the engine, you can mod the current engine instead of switching to a different engine.

This is the exact thing I'm trying to avoid. I despise IoC architectures. My ideal renderer would be a self-contained object that I initialize, and then manually call functions on every frame in order to to draw to the screen. I never want to give up my main loop. I don't want my code to be hosted by anything but the C++ runtime.

I realize now that "decoupled" was a poor choice of word, because I'm not really concerned about API coupling. I just want a decently performant engine that's not some kind of IoC framework.

This topic is closed to new replies.

Advertisement