Sign in to follow this  
stoopdapoop

Separating my engine and game code, should the game or the engine contain main()?

Recommended Posts

So I'm writing my own engine for fun, and I want to have several games using this engine but I'm not sure where the program initialization code should live.  Should it be present in each game project, then the game passes system events down to the engine? That seems incorrect to me, but if I have main in the engine, then how does the project know which game I'm trying to run?

I want to link my engine to my game statically, and I want my boilerplate application initialization code to be in my engine. But I want to be able to compile my games as separate executable that link against my engine. I'm unsure how to achieve this decoupling with all of these properties. Does anyone have any advice?

Share this post


Link to post
Share on other sites
But I want to be able to compile my games as separate executable that link against my engine

Fine. In this case you have three stages of initialization:

  • The game-specific code in the "separate executable" does ad-hoc, game specific things and decides what the engine will do
  • The shared engine initializes itself with the requested configurations and variant behaviours
  • Game-independent code in the engine loads game-specific data files and possibly game-specific executable plugins and uses them.

The main choice is between putting game-specific content in the first stage or in the third stage, corresponding to the two architectural extremes of a bunch of libraries whose game-specific client code makes all decisions and a game allowing data-only mods without custom code.

A reasonable engine should evolve from a single game (in which the distinction doesn't matter) when it is refactored to share code with a second game.

Edited by LorenzoGatti

Share this post


Link to post
Share on other sites

it would seem that the location of the main game loop more or less determines whether its an "engine" or a "library". engines tend to have the main game loop in the engine - and use callbacks so you can add code at various "hooks" in the code.. games built from libraries have the main game loop in the game specific code and seldom / never require callbacks.   Either way, the usual order of initialization is:

1. init engine/library. usually the first thing in main() 

2. load game assets that use standard formats (meshes, textures, wavs, etc). IE stuff the engine deals with. This may be data driven and occur automatically as part of engine iniit.  or it may be done on a per level or per terrain chunk basis.

3. load game specific assets that are custom to the game, perhaps a level map of some sort for example.

Edited by Norman Barrows

Share this post


Link to post
Share on other sites

One way you can do it:

- Shared engine code into a static library

- Dynamic link library containing the entire game code without any platform specific code, importing the shared engine library

- Main executable contains just the platform specific code + handling the loading of the game code dll and give the dll access to platform specific functions, like file loading and creation, memory allocations, etc.

 

This will support hot-load of code - meaning you can change the code, compile it and while the game is running you see the changes immediatly - given that you have good handling of game memory/state.

 

Another way is to use the exact opposite:

- Put the game code into a executable with all the game specific code in it and include the engine static library like you have suggested

- Full engine code in a static library and abstract away the platform parts, like entry point, window creation, event handling, rendering etc.

 

Oh and there is a really good book about game engine stuff -> Game Engine Architecture by Jason Gregory (Naughty Dog). There may be others as well, just search for it.

Edited by Finalspace

Share this post


Link to post
Share on other sites

No, do not include your own main. What if someone wants to compile your engine as a lib and import it? For example to run the game engine inside of a level editor or UI. Maybe someone wants to run your game inside of wxWidgets. In this game wxWidgets needs to call a function and pass a function pointer, something like:

DoGame( user_data_ptr ); 

The best practice is to expose your engine through C functions, this way it is easy to compile the engine as a static library, or a dynamic library, or by copy/pasting source code directly into a project.

Share this post


Link to post
Share on other sites

What Hodgman said is basically how ID tech worked (I don't know if the recent version continue on this road).
What you can do is to have one Game.exe compiled, and do all with loading of scenes and then you only have scene which launch script, all script based.
So basically you have a way to say the start scene and then all other scenes are loaded from this one using script and gameplay using script as well.

Edited by Alundra

Share this post


Link to post
Share on other sites

I have had a lot of research on this topic just before setting up my engine because I wanted the perfect repo structure, the perfect code clearness and perfect speed. Now I now that there isnt something perfect just that what you are willing to work with or not work with.

One of the results I'm very happy with is to compile anything from the framework/engine code into static linked libraries that has the advantage that you could easiely modulate your code. I have set up everything to be as most standalone as possible but also capable to use the full power of any module that exists. When a module uses functions from another one it is not a problem to make a static linked library from them because linker will assemble anything into the executable correctly (Tested in MSVC 2010/2015, GCC LLVM)

To setup a new project a need just a build file where I specify whatever module I want to use and run the tool from the engine directory that setups a VS project for it even when I have also seen a lot of copy/paste project setup or starting a project from a tutorial of the library we then used, I think this is something more clean to get it.

In my system I have a macro that setups the typical main call for targeted platforms requireing an init, main and cleanup function to be called. In the engine I'm currently working on there is a file Engine that contains static functions in a namespace that setup memory management and clears it after anything is finished running. These two functions are put into the macro so that

int main(Array<const char*> const& args)
{
  return Engine::Run();
}
__app_entry(Engine::Initialize, main, Engine::Cleanup)

is anything that the executable needs to call to get the game up working. The Run function then takes control over the OS specific message loop, queries main thread of the job system and registeres a small event callback to shutdown everything properly; thats it! And in my opinion it is enougth because anything else like loading config settings into the engine or register systems at the task manager has to be done before Run.

The rest is scheduled by the task manager when the system is setup and running regardless of if it is an engine system like rendering or something gameplay related like character controller.

I also decided a completely data driven approach like old TES Oblivion did where replacing the main .bsa file meant to have a completely new game (what some modders did) but the decision against it was simply performance related where having anything in scripts may be a critical impact.

I'm happy with it because it is as generic as possible and also as near to the engine code as needed. Maybe you might think that there is something that better fits your needs

Edited by Shaarigan

Share this post


Link to post
Share on other sites
My engine provides an Application object that does all the mucky Win32-ish stuff, configurable by what it is passed to its constructor.

WinMain is in the game, but it's only five or six lines of code usually.

Qt takes this approach too. Good system to my mind.

Share this post


Link to post
Share on other sites

So I'm writing my own engine for fun, and I want to have several games using this engine but I'm not sure where the program initialization code should live.

 

In my simple OpenGL VR engine, I have different approach then normal.

( https://github.com/simviu/IcEng ).

It's not game engine, but simple static model graphics engine support VR.

The Engine is built in static lib. There is class call IcApp wrap everything inside.

The Application specific logic derive IcApp and override it's onInit()/onUpdate() member functions.

There are IcWindow and IcScene class, works similar way.

Thus the main() simply launch the MyApp class, which is derived from IcApp.

This method helps to implement cross platform consistent code , even on iOS/Android.

 

S. Chen

Hope that is helpful.

Edited by schen2000

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this