Archived

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

neurokaotix

Practical Game Engine Design: A discussion

Recommended Posts

Hello everyone, today I would like to discuss practical game engine design. To kick my discussion off I would like to state that the goal of this thread is to enlight myself and if possible, others on the practicality of certain design aspects... API-Independence: Is it even practical anymore? I feel as if this is sort of split down the middle. Many commercial engines that I see are not api-independent and are either hardcoded in Direct3D or OpenGL. I''ve heard it argued that the reason for this is because now-a-days the graphics cards that are in most systems have good enough driver support for your API of choice and that abstracting at the API is a waste of human resources. I personally feel as if I''d like my engine to be API-independent, simple because it allows for such flexibility with what your engine can be ported to (e.i., consoles). Now I realize that I''m almost certainly never going to port my engine to a console system but I would like the option to be there should I have that opportunity sometime. Another point I''ve heard made is that when companies are designing an engine they want to get it done; and not waste time trying to support multiple APIs when they could be using just one API to its fullest extent. I''ve noticed that with my project, I''m spending so much time working out how to get the abstraction just right that I''m getting nowhere visually. I would like to hear your opinions on the subject. Is it worth it to support multiple APIs? Should your engine be programmed using just Direct3D or OpenGL? If you think that just Direct3D is a good approach (like many commercial game developers), then what is your position on platform independence? Platform Independence: Another good thing to think about is whether you plan to have your game/engine ported to another operating system or platform. For most people, Win32 support is the given. But do you ever plan on porting to Linux? Apple? Perhaps a next-generation console? These are all things to factor into your design. Is it practical to try to code your engine to compile on operating systems such as Linux? If you''re coding your engine with Direct3D only then you''re alienating systems other than Windows and XBox. With my engine I''m trying for platform independence (not trying very hard, but it''s a goal). I guess that''s all I have to talk about for now, anyone have any input? James Simmons MindEngine Development http://medev.sourceforge.net

Share this post


Link to post
Share on other sites
First: I''m not a professional but I try to be :D

I''m not going for the API-Independence just because I would never have the opportunity to port it to a consol or another platform.

If I have a good engine which works only on windows I''m happy.. As you said if you try to get it api-independent you can''t focus on the remaining parts of your engine.

I''m currently working on a software engine but that''s just for learning.. I''ve learned OpenGL and DirectX but I don''t think its useful to mix them.. you can reach the most people by going for the Win32 platform so I try to make something really good for the win32 instead something ''not so good'' for win32/linux/..

But if you have the time to design such a system you could use it for all your games.. Just once investing the time and using it after that and as a learning experience it would be great

Share this post


Link to post
Share on other sites
Personally, I would ask yourself what you are creating the engine for. Are you just creating the engine for other people to use? If so, then maybe you should think about just making some sort of game. There are enough good engines out there. If you are doing something for personal use, then just code what you need for your project. If you see that you want something else down the road, then just add it on. It is pretty useless to go about coding in features that nobody is ever going to use.

Share this post


Link to post
Share on other sites
Another reason NOT to use API independence is that you can optimize your engine for a particular API. If your in-game data structures closely mirror the structure the API requires, then you don''t have to spend many extra cycles moving data around to reformat it. You can also customize your code to best take advantage of (and avoid the weaknesses of) the API.

If you are really working this angle, then you are going to have to revamp your 3D engine for each API - or create a conversion layer from one API to another, which means you''ll lose performance on your ports.

This assumes your engine is so high-performance that this actually makes a difference... and that your performance is CPU / bus bound.

Share this post


Link to post
Share on other sites
neurokaotix, I''m currently looking trough your MindEngine and I''ve got to say it''s great man

One of my dreams is to make a strategy game but I''ve got a lot to learn to come that far..

I find it difficult to start with an engine design. I know error and failure is a way but first I''m going to read trough your engine :D Hopefully it will save me from some errors

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
> Should your engine be programmed using just Direct3D or OpenGL?

a) How you will use the API within your engine?

You could have each renderable object call the API itself or you could have a renderer module call each objects'' parameters (vectors, tcoords & surface parameters, etc). In the first case you scatter the code across the engine; the second case centralizes the rendering code in a single module. If you get problems with a specific configuration or you want to extend the engine to support extensions then you don''t have to go around the entire code base to do it.

b) What are the *critical* functionalities you need?

Whether it''s raw speed or specific texturing pipeline features or shader support, those impact which API you will end up with as not all of them degrade gracefully when some features are missing in the graphics card (or at least it would need non-trivial code to work around them).

c) What level of compatibility with 3rd party tools do you need?

Does your engine''s preferred modeller poops out only .x files? Are you using an image library only available on Linux? Does your targeted clientele''s art pipeline compatable with the file formats your engine requires? People want to work with the tools they''re comfy with and not having to intall/buy/learn another tool, even if it is the ''best''.

Share this post


Link to post
Share on other sites
Thank you for the feedback so far, I feel as if I''m leaning towards making my project utilize only one API. Back before I started this engine I had a DirectX engine and then later an OpenGL engine and they progressed very quickly because when you''re working directly with the API you can get a lot more done in a shorter amount of time. However, I''m then faced with the fact that once it''s all programmed in that API, that''s what it uses. Period. Unless later on I abstracted the API again, but that would be a very huge overhall.

James Simmons
MindEngine Development
http://medev.sourceforge.net

Share this post


Link to post
Share on other sites
Another point I would like to go over right now is game content. I have always wanted to have scripting a core part of my engine. Scripting not only for in-game sequences but also for scene setup. I got to thinking, would it be practical to make all content delivered by the engine come from script files rather than using internal C++ functions such as loadMesh and renderMesh (just examples)?

For instance, in the application layer there is a mandatory entry-point script that must be executed which loads primary resources such as the main menu graphics, or calls the scripts which setup the main menu and from there the menu scripts load the game scripts. I feel weary about making it to where you can only present content via scripts though. Just a brain dump *shrugs*

While I''m in writing mode, I noticed that the way my engine works and the way that say... the Quake engine works is different. The .exe is the engine, and the dlls contain the game content (if I''m not mistaken) and the way my engine works the .exe is the game content and the dlls contain the engine. Can anyone think of any obvious pros/cons about either of these methods?




James Simmons
MindEngine Development
http://medev.sourceforge.net

Share this post


Link to post
Share on other sites
In the current iteration of the Caffeine Engine (v3), I''m working to write everything in as abstract a way as possible. I guess the short answer is to create interfaces to your subsystems in the most general way possible, and write implementations as necessary. Of course, it may seem ridiculous to have an overgeneralized interface to a rendering core and a factory that only returns one type of implementation, but it really does allow for future expansion. This applies to platform and API independence alike.

Later,
ZE.

//email me.//zealouselixir software.//msdn.//n00biez.//
miscellaneous links

Share this post


Link to post
Share on other sites
quote:
Original post by Zefrieg
Personally, I would ask yourself what you are creating the engine for. Are you just creating the engine for other people to use? If so, then maybe you should think about just making some sort of game. There are enough good engines out there. If you are doing something for personal use, then just code what you need for your project. If you see that you want something else down the road, then just add it on. It is pretty useless to go about coding in features that nobody is ever going to use.


Damn skippy. Design applies to engines and code just as much as it does to gameplay and content.

API-Independence: As far as pro companies just wanting to ''get it done'' quickly are concerned, I''d guess that actually what they''d go for, in general, would be an API-independent design AND a single implementation; there is, after all, a difference between being *able* to use other APIs, and actually *doing* it. They''d want to keep their options open if possible, while still remaining fairly efficient (no point coding a second renderer when you''ve written no game code to use it).

Platform-Independence: I''m a big advocate of it, partly because I''ve been using Macs as long as (if not longer than) PCs, and thus I''m used to seeing each platform as it really is (i.e. roughly equivalent for most tasks). Macs in particular have untapped potential for the game industry; but I''ve got little in the way of evidence to back that up, I''m afraid.

Part of it is the ''virtual machine'' thing. A platform-independent or API-independent design will always establish a ''common platform'' upon which the game itself is built; from a teamwork point of view, seperation of code like that can be a godsend because two completely seperate teams could work fairly easily on each part, developing the whole in half the time. It also lends to reusability; the basic platform can be upgraded over time to include new functionality, and can be reused across projects fairly easily.

Scripting: As far as providing functionality *only* through scripting, that''s asking for trouble. The best approach would be to establish a load of publicly available methods within your code - LoadTexture/LoadSound, etc - and then ''mirror'' them in the scripting vocabulary. You could even get it set up to work semi-automatically - new methods added to class objects automatically are mirrored in the scripting vocab (though you might need to write some custom compile tools or wikkid macros for it).

DLLs and Exes: One disadvantage of keeping the game in the EXE and the engine in the DLL is that it''s not quite so great for modding; sure, you can still load in other DLLs for mods but then you''re dealing with two DLLs instead of only one.


Superpig
- saving pigs from untimely fates, and when he''s not doing that, runs The Binary Refinery.
Enginuity1 | Enginuity2 | Enginuity3 | Enginuity4
ry. .ibu cy. .abu ry. dy. "sy. .ubu py. .ebu ry. py. .ibu gy." fy. .ibu ny. .ebu

Share this post


Link to post
Share on other sites
At the last company I was at we were doing games on the consoles(PS2, GameCube, XBox) and our core engine was set up to be cross-platform across all three consoles. At the company I''m at now, I''m working on a game for the PC and our engine here is set up specifically for PC/Windows/DX.

So, I guess my take is that if you think you can, or will at some point, want to port to a different platform/OS/API then write it to do that. It''ll save you time in the long run. However, if you never intend to port it to anything else, then I''d say don''t bother.

As an aside, even if you are writing an engine that is soley focused on a single platform, I''d still write as much of it as abstractly as you possibly can without requiring extra work. If you do that then later on, if you decide to port your engine or even create a bran new engine on another platfor, it''ll make harvesting useful bits out of your current engine a whole lot easier

-John

Share this post


Link to post
Share on other sites
Let me set you in a direction that will be very beneficial, and it won''t be very time-consuming to implement.

When it comes to loading resources from files, direct ALL of it from outside of the code. Create manager classes that allow you to read from a certain text/binary file and store the objects in one location. Here is what I do to load resources:


// ImageManager.h

#include "Image.h"

class ImageManager : public lib::Array<Image>
{
public:
// Read/Write

void Read(std::istream& _in);
void Write(std::ostream& _out);

// Constructor/Destructor

ImageManager();
virtual ~ImageManager();
};

// AnimationManager.h

#include "Animation.h"
#include "ImageManager.h"

class AnimationManager : public lib::Array<Animation>
{
public:
// Read/Write

void Read(std::istream& _in, ImageManager& _imageManager);
void Write(std::ostream& _out);

// Constructor/Destructor

AnimationManager();
virtual ~AnimationManager();
};



Basically I just inherited all the interfaces from my Array class, and I added some io functions. It took me about 10 min to do, but I can now do this:


// Images.txt

::Number Images
10
::Image reference and file name
0 image1.bmp
1 image2.bmp
2 image3.bmp
3 image4.bmp
4 image5.bmp
5 image6.bmp
6 image7.bmp
7 image8.bmp
8 image9.bmp
9 image10.bmp

// Animations.txt

::Number Animations
3
::Animation reference and file name
0 animation1.anm
1 animation2.anm
2 animation3.anm

// animation1.anm

::Number Frames
4
::Image reference associated with frame
7
6
5
4


This makes it so easy to load new images for use and create animations from them. Also I overload the operator[] so I can do this to images:

ImageManager imageManager;
imageManager.Read(fin);
imageManager[4].Blit();

What you should basically do is use manager classes to manage all your resources and provide a central location to load anything from whether it be graphic, sound, or even game resources like a creature and its'' stats.

You can add alot of things to the file loading and do something like this:

// Creatures.txt
::Number Creatures
1

::Creature Stats

::Reference
0
::Name
Big Bat
::Creature Image Reference
4
::HP
402
::ATK
11
::DEF
2
::SPD
20
::Number Attacks
2
::Attack 0
BITE001
::Attack 1
WINDSLASH002
::Number Attacks in Pattern
3
:attern
0
0
1

This way you can create new creatures or whatever else with EASE. Also, it allows people to alter your game the way they want. In fact, doing this makes it easy to make different games from the same game implementation. Artists can easily update images, models, and see the replacement in the game right then. It also allows designers to create things for the game without your assistance.

All this WITHOUT a complex scripting system, and only taking 10 minutes to implement.

Share this post


Link to post
Share on other sites
Not to be noisy or anything, but I''m new at this and like the idea of a resource manager, but Zefrieg, would you mind posting what is in your Animation.h? That would fill in all the pieces for me.

theclaytster

Share this post


Link to post
Share on other sites
I might post my animation class on here, but I'm at college right now and don't have access to my files. This is about what it looks like:


// Animation.h

#include "Image.h"

class Animation
{
protected:
lib::Vector<Image*> m_frames;
int m_x;
int m_y;
int m_numberFrames;
int m_currentFrame;
public:
// Mutators

void SetPosition(int _x, int _y);
void AddFrame(const Image& _image);
void SetFrame(int _frameNumber);
void NextFrame();
void PrevFrame();

// Accessors

int GetNumberFrames() const;
int GetCurrentFrame() const;

// Rendering

void Blit();

// File IO

int LoadFile(char* _filename);
int WriteFile(char* _filename) const;
std::istream& Read(std::istream& _in);
std::ostream& Write(std::ostream& _out) const;

// Constructor/Destructor

Animation();
virtual ~Animation();
};



Pretty simple really. Pointers to image objects are stored in m_frames. The position of the animation and image used would be determined from another class like a sprite class. You would only need to set the position where you want to blit the current frame before calling blit. You cycle through the animation by using the NextFrame() and PrevFrame() functions. The only thing that happens when you do this is the m_currentFrame is either incremented or decremented. If m_currentFrame is below 0, it is set to m_numberFrames -1, and if it is m_numberFrames, it is set to 0. Its' a very effecient way to do it in terms of both processing and memory.

You see, an image should be loaded and stored in the Image class that it was loaded with. If you want to use that image for a tile, sprite, or texture, then you just use a pointer to that image class. That way, you keep all your images in one place, but at the same time are able to use them throughout your engine. All of my classes dealing with images do it in this fashion.

One thing I should note is how to include animations in other class objects. You cannot use pointers, you just have to store the class in the class you are using them with. Since Animation only points to images, it doesn't take up much space. If you were to just point to animations, then when you called NextFrame(), it would change the frame for all objects using that animation. That is probably something you do not want to do.



[edited by - Zefrieg on October 8, 2003 1:24:37 PM]

Share this post


Link to post
Share on other sites
quote:
The position of the animation and image used would be determined from another class like a sprite class. You would only need to set the position where you want to blit the current frame before calling blit.


I do this in the exact opposite way; I have an animation class in my sprite (gameobject class) class set up so I can loop the frames I want; walking-left, walking-right, kick-left, kick-right, or jump and fall by calling the appropriate function in the animation class; your method looks like a good way to centralize the drawing code however (each sprite doesn''t actually draw itself) whereas each gameobject in my game draws itself.

Share this post


Link to post
Share on other sites
Yeah, instead of loading the image into your animation class, just point to it from another location. That way you don''t waste memory loading the same images into each individual animation class.

Share this post


Link to post
Share on other sites
Yes, his code is more coupled than yours. High coupled code leads to maintanence problems and code that is difficult to change. Low coupled system leads to bloated classes that do too much and break the single responsibility principle. The idea is to write low coupled code as much as you can. I did both ways and high coupled code was a nightmare on largish project. I had to search for all the clients and also change each one internally.

Share this post


Link to post
Share on other sites
I''m currently working on an engine which is aimed for all sorts of flexibility. Someone mentioned that the downside to API-independence is that files must be converted.

This much is true, but so far that is the only down side I have seen. And even then, the conversion takes next to no time at all. Most APIs use the same format for their data. If the file format is close to what the API uses, you are very unlikely to even notice the conversion cost.

I have also noticed that taking the API-independence route has forced me to take seperation of concerns very seriously. In all reality, a solid engine''s design is very similar to the design of an API-independent engine.

One of the most solid benefits I can think of for API-independence is the ease of porting. An engine which has too much coupling between a file being loaded and the API and blah blah...will be more difficult to port to other systems. Even if you use OpenGL, you are making it difficult to port to PS2 and GameCube. If your engine is based around API-indpenedence then the port only involves writing a new renderer.

SuperPig''s suggestion is a very practicle one. You can design an engine to be API-independent, but only program one renderer. That will help keep the time taken down, and still allow the benefits.

Share this post


Link to post
Share on other sites