Hmm I'm not sure if that's a suitable title for this topic, but here goes...
I'm coding a Game Engine and there's various parts of it that I come up with doubts and questions if I'm doing the right thing, and I'd like to ask for opinions and suggestions for these.
I'll post the problems I have, the solutions I've thought of, and I'd like to discuss them if there's a better way or something like that. So I'd like to ask how you would do it and why.
1. The Scene Draw and Object Hierarchy
Explanation: I have a Scene class that has various vectors for all the types of objects in my game, I separated them to make it faster for iterating and to avoid using interfaces in my objects.
class Scene
{
public:
void Draw();
private:
vector<Image*> _images;
vector<Model*> _models;
vector<Text*> _texts;
};
All objects have two Orientation classes that holds it's current position/rotation/etc and it's previous. At each Draw() call, I interpolate with these.
To support hierarchy, I have this in my objects:
class Model
{
public:
SceneObject* parentObject;
private:
Orientation currentOrientation;
Orientation previousOrientation;
};
Here, SceneObject is a struct that holds pointers to an object's Orientation (both of them, current and previous), just so I could do this:
void Scene::Draw(float& interpolation)
{
//Calculate each object's matrix using a recursive function to calculate it's parent's first.
//Set a flag to define it's been calculated already so it doesn't calculate again in case of multiple children
for(unsigned int i = 0; i < _images.size(); i++)
{
if(_images[i]->isOrientationCalculated == false)
{
CalculateOrientation(_images[i], interpolation);
}
}
//Draw each one of them and reset the flag for the next frame
for(unsigned int i = 0; i < _images.size(); i++)
{
_images[i]->Draw();
_images[i]->isOrientationCalculated = false;
}
}
Matrix4x4 CalculateOrientation(Image* image, float& interpolation)
{
if(image->parentObject != 0)
{
return CalculateOrientation(image->parentObject, interpolation) * Interpolate(image->currentOrientation, image->previousOrientation, interpolation);
}
if(image->isOrientationCalculated == true)
{
return image->objectMatrix;
}
else
{
image->isOrientationCalculated = true;
return image->objectMatrix = Interpolate(image->currentOrientation, image->previousOrientation, interpolation);
}
}
Problem: Only children keeps tracks of their parents so parents don't know if they have children or not. I've thought of making it the other way around, of having parents keeping track of their children, but after coding it I noticed the code was nearly the same, since they're all in a single vector I'd have to keep a flag for each object to set if they've been calculated already or not so I don't calculate children's matrices twice.
Because of this, or rather, any way I'd choose to do (parent->children or children->parent) I would need to add the code above and it's making my Draw() function much slower, and I was trying to leave this as clean as possible.
Do you think this could be done in a better way? How?
2. Text Rendering and Effects
Explanation: I have a Text class that I use Bitmap Fonts with, and I have to use a function SetText(string) to set it's text value.
At first I would save buffer all the characters, and draw them with different positions depending on the text (moving a certain width/height every character/line break).
I thought it was too slow, so I made the SetText(string) function and what it does is, I count the characters, create a new buffer and a single object with all the vertex/uv data for that string, and draw it. It was much (very much!) faster than before.
Problem: Now with this new way of rendering the text, I can't use a basic effect I had before on texts, the one that displays text as if it's been typing (like a character per second). With all the characters in different buffers, I just had to count the string and display until a currentCharacter variable, which increased by 1 per second/timing.
Now since I have the entire string in a single object, I'm having to recreate the object, calculate all the positions/vertex/uv data again, and display, and then this isn't really all that fast as before. Still faster than having multiple buffers though.
Is there a better way to do this?
3. Input Class and Game Commands
Explanation: I don't have an Input class yet, for now, I'm coding on Windows only and I know how to get keyboard and mouse input. I want the Input class to be oblivious of the input or system, so I can make it cross platform and depending on the system, I only point/fill the Input class variables for the game to use.
________ _______ ________
| System |---(unique input code/message)---| Input |---| Engine |
|________| |_______| |________|
\
\ (configures/add it's specific game commands)
\ ______
| Game |
|______|
So a game A could add a specific command for Directional Keys and give it the type of float or bool.
It's game code would only worry about checking these specific commands:
if(_input.IsPressed("MOVE_LEFT")) //MOVE_LEFT command created
{
character.MoveLeft();
}
So far this is simple to do...
Problem: Can I make a code to change the state of the Game's commands with it being unaware of the actual input? Like as if it doesn't care if it's keyboard, joystick, mouse or even touchscreen?
Seeing as how I check for an input on Windows:
LRESULT CALLBACK MessageProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_KEYDOWN:
{
myGame->inputClass.Pressed(wParam, true);
break;
}
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
I'm "locked" in the sense that I must have wParam defined to a command, and I don't want to have a game command locked to a specific charCode like that if possible.
I've thought of making a Keyboard, Mouse, Joystick class and look for a way to make they work in every platform I'd want to code in, but that wouldn't change much since I would still be locking the commands for the specific codes... but at least I would be sure to work in any platform.
Is there any way to do this? If not I'll probably stick to creating and setting codes for every platform/input type, though it's not much work, but I'd like to achieve something more... automatic.
Hmm typing this last one made me realize that it seems something stupid to ask... it doesn't seem possible to have an input like that, I'll leave it like this though since I'd like to discuss how input classes are made.