Archived

This topic is now archived and is closed to further replies.

Peon

Writing a generic / reuseable engine

Recommended Posts

I'm currently trying to write a simple 2D engine that's as generic as possible. I want to be able to use this engine for RTS games, platformers, whatever. So far, I have a basic system of loading external files, a generic base objects, and several templated classes for use with other object types I might have. I've run into some problems making it generic, however. For each application, I need to make special messages for my message handler, I need to rewrite most of the input checking code, and a whole slew of other things that make me feel like it's not generic enough. So I guess my real question, what is the "acceptable" level of application specific hard-code if I want to make a reuseable engine? [edited by - Peon on October 23, 2003 11:35:01 PM]

Share this post


Link to post
Share on other sites
Well, it depends on how your engine is designed.

Ideally, your application should use the engine, not the other way around, so you never ever put application code within the engine. For instance your game loop may loop something like this (vastly simplified)


#include "Engine\Engine.h"


int main()
{
float fTimeElapsed;

EngineInit();

while (EngineLoop() & !bExit)
{
fTimeElapsed = GetElapsedTime();
AppUpdate(fTimeElapsed);
AppRender();
}

EngineKill();
}

void AppUpdate(float fTimeElapsed)
{
if (state == APP_MENU)
{
// perform menu update

// change currently selected item colour etc.

}
else
if (state == APP_GAME)
{
// update position of the game objects, check which ones

// are visible and update the rest of the engine

EngineUpdate(fTimeElapsed);
}
}

void AppRender()
{
if (state == APP_MENU)
{
// Add menu entries to the engine''s rendering list

// ...

// use the engine to render

EngineRender();
}
else
{
// Add game objects to the engine''s rendering list

// ...

// use the engine to render

EngineRender();
}
}


You''ll notice that the engine never ever knows of the application, but it takes care of things like alpha-sorting, object culling, visibility determination etc..

You''ll want to do something exactly the same for your sound engine (or ingredient as GRhodes puts it :D) or AI engine. The idea is to make the application dependent on the engine, not the other way round.

Hope this helped,
FReY

Share this post


Link to post
Share on other sites
I believe a good level or genericity (is that even a word?) is when you only have to give your engine the game objects and only have to implement the games rules.

You have to break down what the most important elements are in a game, and specify their behavior.
If you are working on a game and you find out you need something extra from one of the elements, you add it to your engine. That way it grows.

I''m now trying to get my 3D engine to work, and my main elements are gameobjects and models. Gameobjects have behavior, such as movement and rotation and are linked to a specific model. The renderer uses the gameobjects to get the position of the object, and the model to render it. I also included a menumanager for creating easy menus on the screen.
As a demo for the engine I''m making a simple connect4 game, and so far I only have to give the menu items to the engine, load two models and add a list of objects that will act as my game pieces. I have to implement the games rules in my application itself. So the application will have to check if I got a four in a row.
All game dependent physics will be implemented in the game itself. So if I want a piece to fall down when it''s placed, I will have to implement this in my game, not in my engine. Or when your Super Mario jumps, you will have to program the jump in your game, not in your engine.

So, in short, first analyze what the main aspects of a random game are and what their most likely behavior is. Then you think up a system for managing and using these aspects.

Share this post


Link to post
Share on other sites
Thanks for the comments so far

Let me give a more specific example of what I''m thinking:

As I said before (I think) I''m making an asteroids type game. The way I handle messages is that when a button is pressed, an appropriate message is sent. When player 1 hits the button that says "fire" I create a MSG_FIRE message that I send to the object to handle. The thing is, these messages very heavily on the program. For a platformer, I might need that button to jump. In an RTS, to tell a unit to move. Is it appropriate to code specific messages for each game into the engine? It''s just a basic GDI engine with GetAsyncKeyState for input... each game, I will have to rewrite the input checking code, and what message it generates. Is this considered acceptable? I feel bad every time I hardcode something into my engine that I feel shouldn''t be; I just can''t see any way around it.

FReY: You say "the idea is to make the application dependent on the engine, not the other way round." Do you mean to say I would derive an application from my engine? Or that my application HAS an engine? I''m not quite sure how I would impement this.

Share this post


Link to post
Share on other sites
Well, for retrieving keys, you could create an input manager. This input manager looks at the keystate, and if a key is pressed it makes a callback to your application.

Then, you get your callback when FIRE is pressed. You don''t pass a FIRE message to your engine, but instead, in your game application, you create a new bullet object and set its position and velocity with the already existing messages SET_POSITION and SET_VELOCITY (or how you called those messages).

Now, if you want to make Super Mario, and mario fires a fireball, you do the same thing. Wait till you get a callback from the fire key -> tell the engine to create a new object that looks like a fireball -> set its position and velocity -> profit.

What you mention as FIRE is NOT a generic game event. Some games don''t have FIRE events. Tic Tac Toe for example. So it shouldn''t be in your engine. It should be in your game code.

Share this post


Link to post
Share on other sites
I think this is a very good question, and it deserves a good answer, because the way you answer this question effects the way you structure your engine from day 1. I had to answer these kinds of questions with my engine because I also wanted it to be as generic as possible.

The problem is, there is a lot of code that is neither a part of every possible game and not really a part of game logic. Pathfinding is a good example - it''s something that you don''t want to have to rewrite for every application that uses it but doesn''t apply to every application. So you can have a system of modules. You load or compile in the parts of the engine you need or add your own modules, which can be reused later.

To directly address your input handling concerns, you have two options:

1. Set up an associative array (VK_SPACE => ''CMD_FIRE'') that your engine uses to send events to your application in a flexible way

or

2. Load a separate input-handling module into your engine (basically the same idea as a callback) that processes the keystrokes directly.

Hope this helps.

Tom

Share this post


Link to post
Share on other sites
Alot of people mix up the term game and engine and game-engine and there are lots of articles out there that aid this confusion.

If you want a reusable engine, you have to design it in such a way that it contains no application specific coding.

Think of an engine (at least a reusable one) as a *library* that you can use to make your game coding easier. For instance, your engine may implement several functions for testing various shapes (eg. triangle, abbox, obbox, sphere, capsule etc...) for collisions. However, you never have functions inside your engine such as ''test_tank_vehicle_for_collisions''. That is done in your application where that function may use the engine''s functions for testing collision based on the shape of a ''tank_vehicle'' at an application level.

Implementing a general gameobject within the engine is a difficult task because you have to completely abstract it so that it is neither application specific or unuseful. The game object may represent any kind of object such as a particle emitter or a sound emitter or a trigger that responds to some collision between physics game objects or even a script event or ai entity. As a side note: don''t confuse resources (sound files, graphics, models and text) with game objects either - they are separate although the resources may be managed and loaded by using the engine.

Peon, in response to your question: the application *uses* the engine, it''s like a car engine: a Peugeot 206 may have the body work and it''s own electrics and air conditioner and wheels, but it uses the engine to make the rest of it work. Without the engine, the wheels won''t go round, but it doesn''t make sense to make the seat-recliner a part of the engine because that is specific to the car and all future designs of cars would have to have their seat-recliners based on that engine''s seat recliners. It''s the same with games.

I would advise when you do your coding to create different statically linked libraries (easy to do with VC6/.NET). Use at least one library for your engine (you could use more by breaking your engine down into more libraries such as maths, rendering, physics, input handling). Your application (in this case your game) will then include files from the engine library. The engine library will never include files from your application. I''m not sure if I''m explaining this clearly enough.

Also, it may be worth thinking about a plugin-in system for your engine. As ParadigmShift so aptly pointed out, you may never need certain modules in a particular game. In this case you need to include those modules as part of the engine, but make them completely excludable from compilation when they are not used. This is where libraries come in handy - definitely invest some time in learning to use these properly.

With regards to input-handling. I find it''s best to implement most of it in the application and then manually pass messages to those affected eg. (again vastly simplified)


// app.cpp and app.h


// an enumeration for keyboard presses based on the action, rather than their associated key code.

typedef enum
{
K_FIRE,
K_ROTATELEFT,
K_ROTATERIGHT
};

// a keyboard binding which associates a keyboard action with

// a key code.

EKey globalkeyboardbinding[]
{
EK_leftctrl, // corresponds to K_FIRE

EK_cursorleft, // corresponds to K_ROTATELEFT

EK_cursorright // corresponds to K_ROTATERIGHT

};

void GameAppCheckInput()
{
if (EGetKeyStatus(globalkeyboardbinding[K_FIRE]) == EKEYDOWN)
{
ESendMessage(globalplayerobject, MSG_FIRE, NULL); // NULL is the extra data.

}
}


void GameAppFireKeyPressed(EGameObject *psGameObject, int iMessage, void *pvExtraDataAttachedToMessage)
{
// check the type of the game object

// get orientation from the game object (if it has)

// get the position from the game object

// create a bullet with that orientation and position or

// pass the message along to the game object''s dependents.

}


int main()
{
// tell the engine that whenever MSG_FIRE is sent to a game

//object, it must call GameAppFireKeyPressed

EngineAddMessage(MSG_FIRE, (void *)GameAppFireKeyPressed);

while (bRunning)
{
GameAppCheckInput();
EngineProcessMessages();
}
}



Everything prefixxed with an E in the above code is implemented within the engine library. The globalkeyboardbinding[] array is a structural array which corresponds to those events which can occur within the game. It is implemented in this way so that you can load and save your keyboard bindings and alter them between game user profiles. Also, all message routing is implemented within the engine, whilst all responses to those messages are implemented in the application. In this way we can also setup things like AI agents to pass messages through the engine whilst
making sure those responses are all centrally located within the application.

So Peon, to answer your question "is it appropriate to code specific messages for each game into the engine?". No, never. You have to abstract everything within a general engine. At the same time, be aware that it''s not easy designing with all of this in mind. Most of the time you will be thinking more about the required structure than actually doing any coding. Of course, the more engine''s you write, the more you learn and the better and quicker you will think about these things based on past experiences.

Hope this helped even more

BTW Structural: the word is generality :D


Share this post


Link to post
Share on other sites
Thanks Frey, that did help I THINK my design is pretty modular right now, but I really don't know how to use DLLs in my program. I'm sure it's simple, but right now I just have each part broken up into an appropriate header file. My generic game object has one, my renderer has one, my database template has one, etc... Is this modular, or is there more to it than that?

After some thinking, I decided that the part of my engine that was causing me problems was mainly input handling and messages. So I came up with a possible solution. I would however like a little feedback before I implement it.

I would create a custom file type that would contain a listing of actions that could be performed. It might look something like this:


0 //an int that represents an enumerated type for an application specific action. For this example, call it MSG_FIRE

1 //another int; this specifies a generic action. Let's call it MSG_CREATE

1000 //The generic message would take parameters; in this cases, the ID of the object type to create, and a location. A special key, say '@' could be used in this case to tell the engine to use the object's coordinates

5
5

... more actions
So for this, my application would #include some files that specified application specific messages, and it would load up these game-specific 'input configurations' to find out what it should do when it encounters a game specific message. The game specific messages are just that: they wouldn't be able to perform any actions. Only the generic messages could perform actions.

The generic messages would be a part of the engine and include things such as MSG_CREATE, MSG_DESTROY, MSG_CHANGEFRAME, MSG_UPDATE, and other messages. Each take some parameters that allow it to be more specific.

I'm also in the process of writing my input handler. Each frame, the manager class will GET an array of bools from the handler, specifying if a key is current down or up. If I'm thinking about it correctly, the only thing I will need to write for my application in terms of input would be the message handler. For example, I need to be able to detect a MSG_FIRE message, and it will need special handling since it's not a generic handling. This is where the game specific handler comes in (that won't be part of the engine)

I don't know how clear my explanation is, but hopefully I got it across. Is this a good idea, or too weird? Am I making this harder than it really is?

Thanks for the feedback and ideas; it's appreciated.

-=Peon=- : A Poorly Implement Forum Bot
© Kordova, 2003

[edited by - Peon on October 27, 2003 1:23:04 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Peon
Thanks Frey, that did help I THINK my design is pretty modular right now, but I really don''t know how to use DLLs in my program.


Got Triple Buffer. and check out the plugin manager (you''ll see it on the left of the home page in the latest files section). Should get you started...


:::: [ Triple Buffer ] ::::

Share this post


Link to post
Share on other sites
just write a wrapper, thats as generic as can be,
for example making a window with a lil text with my wrapper

void loop()
{
d3d::beginScene(D3DCOLOR_XRGB(14,14,10));
d3d::font ::draw("heading1","Hello world",100,60,200,30,D3DCOLOR_XRGB(250,250,250));
d3d::endScene ();
}
void init()
{
d3d::font ::set("heading1","Times New Roman",16,300,true,true);
}
int WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR, INT )
{
d3d::createWindow("DXWrapper", "DX Wrapper Test", true, 800,600, init, loop);
return 0;
}

Share this post


Link to post
Share on other sites
I've been thinking about something that applies to this; I was recently looking into gameboy emu's and deving (not gba but the older gb....)

The gb gave you very specific structures to work with; a char array for a tile map, a bunch of 8x8 tiles (in 4 colors) and upto 40 sprites 8x8 or 8x16 that would point to a tile for its representation. input was 2 buttons and a direction pad. Given this simple slate some very servicable games were produced. This would be an example of the ultimatly generic engine.

Take this one step further and give you game objects more automatic behavior; like every sprite knows the type of every tile it overlaps, and it knows which sprites it is in contact with and you can very quickly build up complex behavior in your scripting system.

I do think that trying to cover genres so different as an rts and a platformer is a bit extreme. In a platformer your going to have gravity to consider which normally wouldn't be a consideration in an rts for example. Bouncing is a pretty complex behavior to code for.

Just my 2 cents.

Oh yeah, for message passing who is to say that you can't pass an unlimited number of arguments very easily? ie

void gameobject->addtomessagequeue( int [] args, int num_of_args);

and set args[0] as the message type? You could extend this to floats as well.

So if you pass ({3,140,200},3) your telling the object to do action 3 (moveto) x = 140 y = 200.

(I never really spent time on stdarg.h I should have...)



[edited by - nonnus29 on October 28, 2003 10:34:00 PM]

Share this post


Link to post
Share on other sites