Game Engine Modules/Projects

Started by
30 comments, last by Hodgman 8 years, 3 months ago

Strictly speaking you can also live dangerously and take the approach that the engine DLL and the game simply need to be compiled with the same C++ compiler, and therefore allow working through C++ ABI directly instead of making a proper C API (C4 engine, and some graphics libraries like Ogre work this way.)

But I agree that dynamic libraries are a complication and the OP likely doesn't need them right now.

Advertisement
Strictly speaking you can also live dangerously and take the approach that the engine DLL and the game simply need to be compiled with the same C++ compiler, and therefore allow working through C++ ABI directly instead of making a proper C API (C4 engine, and some graphics libraries like Ogre work this way.)

Very true, but at that point (in case the OP is interested) I feel like you are abandoning enough of the benefits of a DLL that you still have to raise the "why bother" question.


This does not really have much to do with your stated organization of DLL/EXE/EXE though. Which means you're likely overcomplicating your approach for no reason. You have not stated a compelling reason why your project needs to use that approach, so you shouldn't (since it is a more complicated approach).

It does because i cant make the game as well at the moment because i have no way of separating the game from the engine.


A static library will be significantly simpler to start out with, and can be easily adapted to a DLL if needed later. However starting out with a DLL, unless you're familiar enough with their production (and I don't think you are since you had to ask the question in the first place) will introduce a lot of boilerplate code, such as the necessity to expose a C-style ABI for your engine and do the appropriate marshaling and/or data hiding that gets in the way of accomplishing your actual goal of making something.

After what I've been reading recently I would prefer to compile to a static lib to begin at least because it is simpler, I agree with that.

It does because i cant make the game as well at the moment because i have no way of separating the game from the engine.

You can do this entirely within a single .exe project if you have good engineering discipline about it. If you'd like an extra layer of protection against you're making mistakes (a reasonable idea), a static library works fine (it will be a separate project). The DLL aspect is what I'm objecting to here.


You can do this entirely within a single .exe project if you have good engineering discipline about it. If you'd like an extra layer of protection against you're making mistakes (a reasonable idea), a static library works fine (it will be a separate project). The DLL aspect is what I'm objecting to here.

That is what I have been aiming to do. Initially I just made the Engine project compile to a static lib and had the game as the EXE but i couldn't come up with a way to make that work without having the entry point in the game project and have that load the engine, which means i have to write that main function for every game i ever want to make with the engine

which means i have to write that main function for every game i ever want to make with the engine

You'll (generally) have to write a main function for all of your games, since the games are the .exes where your main entrypoint has to be. However you can reduce the amount of boilerplate to something like:


int main () {
  MyAwesomeGame game;
  return game.run();
}

or similar with a bit of work (here "MyAwesomeGame" is a subclass of "YourEngine::Game" or whatever which implements only the game-specific logic, the boilerplate stuff being taken care of by the YourEngine::Game base class from your static library. Is that what you were going for? Where did you run into trouble along that path?

(there are ways to avoid having to write a main function, including a paradigm where you engine is the .exe and your games are shipped as DLLs, but again, that's probably overcomplication).

which means i have to write that main function for every game i ever want to make with the engine

You'll (generally) have to write a main function for all of your games, since the games are the .exes where your main entrypoint has to be. However you can reduce the amount of boilerplate to something like:


int main () {
  MyAwesomeGame game;
  return game.run();
}

or similar with a bit of work (here "MyAwesomeGame" is a subclass of "YourEngine::Game" or whatever which implements only the game-specific logic, the boilerplate stuff being taken care of by the YourEngine::Game base class from your static library. Is that what you were going for? Where did you run into trouble along that path?

(there are ways to avoid having to write a main function, including a paradigm where you engine is the .exe and your games are shipped as DLLs, but again, that's probably overcomplication).

I have a class that basically brings all the main subsystems together such as the graphics manager, the timer, the world manager, the game loop (which does essentially what a main function would do)


int GameLoop::Run()
{
	m_pTime = m_pEngine->GetTime();

	MSG msg = { 0 };

	while(!m_bWantToQuit)
	{
		if(PeekMessage(&msg, (HWND)m_pWindow->GetHandle(), 0, 0, PM_REMOVE))
		{
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}

		if (msg.message == WM_QUIT)
			break;


		m_pTime->Tick();
		m_pEngine->Update(m_pTime->GetDeltaTime());
		m_pEngine->Render(0);
	}

	return 0;
}

I did this to allow me to abstract the platform specific code so all implementation is in the cpp file and there are different ones for each platform.

would the Engine class be the one you are talking about? Or are you saying to make a separate class that starts up the Engine class so to speak?

No, what you've got there seems like a fairly reasonable implementation of the idea I was talking about (just using different names or terminology than my example).

Your earlier posts seemed to imply there was some difficulty with this approach that led you to have to rewrite a lot of code for every "game" using your engine, but I'm not clear now what that difficulty was?

No, what you've got there seems like a fairly reasonable implementation of the idea I was talking about (just using different names or terminology than my example).

Your earlier posts seemed to imply there was some difficulty with this approach that led you to have to rewrite a lot of code for every "game" using your engine, but I'm not clear now what that difficulty was?

That class is tied into the engine project not a separate one its part of the platform abstraction layer the header and class declaration resides in Core/Platform/GameLoop.h and the definitions reside in Core/Platform/Windows/GameLoop.cpp where windows would be the platform for which the game is being compiled. this makes it a fundamental part of the engine, which means i can't put it in the game project

Ah, but you could write a Game class in your engine, one that is basically an abstract base class:


struct Game {
  virtual void OnSetup() = 0;
  virtual void OnUpdate (float elapsed) = 0;
  virtual void OnRender (float elapsed) = 0;
  virtual void OnShutdown () = 0;
};

Then you expect the "user" of the library to create code that subclasses the Game object, implementing each function to perform the appropriate actions. Then you expect your game loop to be given a pointer to the user's game object when it runs:


struct MyAwesomeGame : Game {
  ... implement functions...
};

int main ()
  MyAwesomeGame game;
  GameLoop::Run(game);
}

And your "run" method takes a Game&, which allows dynamic dispatch (you could do a Game* if you wanted, but a reference works and enforces the idea that you have to pass one, you can't pass nullptr). At the appropriate points in your "run" method you call the appropriate methods of the game object, e.g., you call OnStartup before you enter the loop proper, OnShutdown right before you return, and OnUpdate and OnRender during the actual loop.

The above is a simplified form of the idea (you'd probably want to take a closer look at what goes on in what is currently your m_pEngine->Update() calls and the like, but it gets the basic point across. In "real world" implementation you might use a non-virtual interface idiom to ensure that things that are "supposed" to happen on Update or Render happens regardless of what the user puts in their derived implementation. But essentially what you're doing here is using the game class to provide the basic required functionality of the game engine (this may be what your 'engine' class currently does) and use inheritance to allow user code to implement methods that are called at the right point to supply custom, game-specific behavior.

Then you have only the game-specific code in the game project, and the general part of the code (the Game base class and/or the Engine class, the GameLoop class, etc) in the engine library.

This topic is closed to new replies.

Advertisement