Game Engine Dilemma

Started by
15 comments, last by Kitt3n 16 years, 8 months ago
Hello everyone, this is my first post :D. I am having a dilemma about a game engine I am building. Its my first attempt at a full engine, its written in c++ and uses DirectX. I keep changing the structure back and forth, but I have to choose one way and stick to it. Okay here it is: My engine is divided into devices and objects. For example: Devices: Graphics, Input, SoundManager etc. Objects: Images, Sprite, Sound etc. Now, here is the dilemma A) Should I have functionality in the actual objects or the devices? Ex. When I create an image or a sprite, should that object have functions for loading and drawing? Or should the Graphics device hold those functions? If the functionality is in the image object, it would look like this. Image.Initialize( GraphicsDevice, filepath, x, y); etc. Image.Draw( x, y); If its done like this than any object that needs a device to perform its operation will have to hold a pointer to the device as a member of the class, or it could be passed into parameters like this: Image.Draw( GraphicsDevice, x, y); ...because the image needs access to the device to draw. B) OR.......Should I percolate functionality upwards into the actual device? Ex. The device controls the operations of the object which need the device.. Image image = Graphics.CreateImage( filepath, useMask) .....etc. That eliminates the need to have a pointer to the device in every single object that needs it, or passing it in as a parameter all the time. Also.... Graphics.Draw( Image imgName); ** no need to pass in the device However, functions that do not require the device like: Image.GetHeight(); ....should maybe stay within the object itself? ********************** This is the dilemma. Keep functionality with the objects? Or move it up into the devices? The goal of this engine is simplicity. The user should have easy access to functions, thats why I like to keep them in devices. Currently, I have functionality in the objects, but I am tempted to move it into the devices. I am leaning towards the device functionality because it makes it "easier" I think to access the Graphics object for everything related to graphics. Please let me know your opinions, I have never made a full engine before. Oh...and one more thing. Should my functions return 0 if they fail and let the user check for errors in their code? Or should there be an error message box in the actual engine function? Ex: int Draw( Image, x, y) { if ( Graphics->Draw( Image) == 0) return 0; return 1; } and in the users code: int temp = Draw( image, x, y) if ( temp == 0) MessageBox( NULL, "Could not draw image", "Error!", MB_ICONEXCLAMATION | MB_OK); OR **************************** void Draw( Image, x, y) { if ( Graphics->Draw( Image) == 0) MessageBox( NULL, "Could not draw image", "Error!", MB_ICONEXCLAMATION | MB_OK); } Thanks for all your help, XSlinger
Advertisement
The semantics of "Device" sort of imply that there could be multiple devices, and if that's the case then you may want your "objects" to be reusable.

Why not something along the lines of:

image.Initialize(filepath, x, y);
GraphicsDevice.Draw(image);
OtherGraphicsDevice.Draw(image);

Actually, that's how it works in the Java and .NET drawing libraries, now that I think about it.

If there is any state information that is specific to a particular device, then that device can cache any data it needs internally... I'm thinking vertex buffers, etc.
Hmm....

But even the initialize requires use of a graphics device. Therefore it might have to be specific to a single device.

So it would have to be:

Image.Initialize( Graphics, x, y)

or

Image = Graphics->Initialize( x, y);


I think...
I agree with smitty, the objects (like "Image") should be reusable. It seems to me like they are both somewhat dependant of each other. Why does initialization of an Image Object require a Graphics Device?
@popsoftheyear

The image initialization needs a Graphics device because the graphics device holds the IDirect3DDevice9* object and the function to load a Direct3D texture takes in this device as a parameter.

**EDIT in the above post I just put Image.Initialize( Graphics, x, y)
I meant to put a filepath in there. (Graphics, filePath, x, y)

The image object hoolds the Direct3D texture and Initialize uses the filePath to load the texture.
I'm only vaguely familiar with DirectX...but it seems to me that your image object will only be useable by the graphics device that it is initialized with? If this is OK, I would probably stick with the "Image = Graphics->Initialize(path, x, y);" version, or even "Image = Graphics->Load(path)"... (why do you need x and y in the initialize parameter if you're loading anyway??)

Unless someone knows of some way that XSlinger doesn't have to depend on the direct3d interface to load his 3d textures...

Cheers
-Scott
The way I see it:
Sprites use the device, the device doesn't use the sprites;
So the sprites should know the device, not other way.

(I may be wrong because I don't know exactly the features and responsibilities of your classes)

You can know which device you are using hard-coded (possibly after inheriting from more abstract class, or with a template), or by global pointer (singleton?) or by holding a pointer member (and there are more ways...).
The most flexible way is holding a pointer member, but since device is such a central part of the game engine (ie. many objects and classes will need it) and you put simplicity as a top goal, it may be acceptable to have some global pointer to the device. Same way if you want to have a log file, it may be acceptable to have a global variable of a Logger class.

Just be careful not to make a habit of using globals... in the example of the logger if you later decide to have a separate log file for the red sprites you may find it difficult when you are using just one global pointer across your classes.
I stand by my original opinion. It shouldn't matter that the Device has the IDirect3DDevice9*, because the Image object shouldn't be creating texture objects and should not even know what an IDirect3DDevice9 is. Those are in the API/device realm. An Image should only hold pixel information read from a file and other imformation that the device needs to create a texture.

When you draw the image using...

myDevice.Draw(myImage)

...then the Device should internally create a texture from the supplied image.

There is no reason whatsoever for the image to have knowledge of the Device. Then, later, you could even reimplement the "Device" to use OpenGL or something else, if you want to. The "objects" should be completely uninterested in the implementation details of the "Device".

In my opinion, of course.
I completely agree with smitty still...forcing something that should be flexible like your Image object to be dependant on an very specific API is bad design. Granted sometimes there is nothing you can do about it...but for all intents and purposes this shouldn't be one of those times.

Ideally, I would think that it should be something more along the lines of

Image->Load(Path); // Assume X and Y are described in the file
Graphics->LoadTexture(Image);

On the other hand, I did a quick google search and came up with this function, D3DXCreateTextureFromFile. I assume you're using something like this to easily load images and not have to worry about that file formats etc yourself? If you are using a directx dependant function to load images, I'm not sure how many other choices you really have!

And to answer your other question...I would probably just have a return value. There may very well be cases where if image drawing fails, it is NOT necessary for the end-user to know...ya know?
Thanks for all your help and the speedy replies. Now I understand that objects should be independent of the device.

I will do something like the following:

Image = Graphics->CreateImage( filePath);
Graphics->DrawImage( Image);

XSlinger

This topic is closed to new replies.

Advertisement