In this blog, we will discuss how to create a game object representation for our engine and how to include them in the simulation and add movement to them.
So far we are creating meshes and submitting them to the graphics and the render thread renders using the submitted data. But when we think about using our engine the gameplay programmer or other users they just don't add meshes and draw them on screen they would like to do much more like to program a specific behavior or view the world. So we have to provide ways to do that using our engine and for that, we need some representations.
The first thing we would like to have is some kind of representation of a game object that the player interacts with. But before creating the game object lets understand what is this game object? It is a representation of data of an object in the real or imaginary world that you would like to simulate. The examples would be any real-world objects like lights, trees, etc, and any imaginary things like effects, etc. The above definition is not an exact explanation of a game object but it helps you in identifying what a game object could be which is really helpful when designing the representation for it. So do we have only game objects in the engine? Not entirely there might be objects in your engine which are not game objects they might be objects used in your editor or some other place in the engine and there might be some common data in both game objects and non-game objects. So I think it is a good idea to consider these things while designing your representations.
In my engine, I created a FObject which is a representation for any object type(game, non-game) this will be the base of any object that you create in the future and contains some basic information like a Tag. Then I have FWorldObject which represents any object in the world(space where things can be moved) which inherits from FObject. FWorldObject contains position & orientation information.
As we discussed we will have game objects and other non-game objects in our engine and one example of a non-game object would be an editor camera. An Editor camera need not be a game object because it is not meant to be used in the game. It is specifically designed to view the world and its behavior cannot be changed. Sure there can be game objects which are cameras in the game but an editor camera is different.
So I wanted to create something similar so I created 2 classes one for GameObject and one for Camera both are inherited from FWorldObject as both have a position and orientation in the world.
Following is the representation of the GameObject in my Engine
The GameObject stores a pointer to mesh & effect and the required physics data is already stored in FWorldObject. There is also a bool to represent the active state of the object which can be used by the gameplay programmer to program a specific behavior. There is also a Damping Coefficient which is used in calculating the damping. If you don't want the damping coefficient to be different for every object then it is not required for now I choose to keep it.
The physics data contains the position, orientation, velocity & acceleration, and few other things which allow the gameplay programmer to program a movement to the game object.
Following is the interface that submits data of game objects to be rendered
s_GameObject1.Render(i_elapsedSecondCount_sinceLastSimulationUpdate);
I tried to keep it simple It might not be necessary for the gameplay programmer to know what is going on under the hood so I went with a name that is simple and clear. Render will call the necessary graphics interface to submit the data.
Camera Object is similar to game object but all the movement logic is defined in the class inside void MoveCamera(), unlike the game object for which the gameplay programmer defines it in his game.
As we are allowing movement of game objects now the graphics system should be aware of the position and orientation information of the game object to draw the mesh. The graphics system need not know all the details that a game object stores regarding the physics state of the object all it needs to know is where the object should be drawn on the screen. So we add more information to sDataRequiredToRenderAFrame struct to represent the transform of each object to be rendered. So after adding the new transform the size of sDataRequiredToRenderAFrame in D3D is 328 bytes and in OpenGL, it is 308 bytes (this for two mesh objects). So the total memory would be 656 bytes in D3D and 616 bytes in OpenGL as we have 2 instances of the struct.
Extrapolation/Prediction
One other important thing to understand is currently in our engine, rendering does not happen the same amount of times as the number of times the application updates. Updates happen as fast as the application thread can run but the rendering is done at a particular rate 15 times a second to be specific. So why do we do this way why not render every frame. We can do it every frame but the question is it necessary? Game engines are a complex piece of software and as the number of systems in a game engine increases the processing power required also increases and we always have a limited budget when coming to processing power. So we have to be aware of how much budget we have and how are we using it. So we render only at a specific rate to keep the processing power within the budget. But this creates a problem as both updates and drawing is happening at different rates the movement of objects might look choppy as it as just rendering at 15fps. But we need a smoother movement and the way we do this is we predict the movement of the object based on the elapsed simulation time since the last update. This prediction helps us in determining the in-between positions of the objects giving a smoother movement. An Object can be moved either by changing the velocity or acceleration. I currently use acceleration to move objects and there is also damping which stops the object slowly similar to the real world.
Controls:
ESC – exit.
Up/Down/Left/Right - Move Triangle Object
W/A/S/D/Q/E - Move Camera Up/Left/Down/Right/Front/Back
ENTER - Changes the mesh to square and effect to the animating color of the object.
Space - Toggle between main and secondary camera. Note: the secondary camera does not support the movement.
Comments