Asynchronous screen update to the logic of the game, C ++

I am programming a game using Visual C ++ 2008 Express and Ogre3D sdk.

My main game logic is 100 times / second. For simplicity, I will say that this is a method called "gamelogic ()". This is not time-based, which means that if I want to "speed up" the game time by 1 second, I have to call "gamelogic ()" 100 times. "gamelogic ()" is easy compared to rendering a game screen.

Ogre has “listener” logic that informs your code when it is about to draw a frame and when it has finished drawing a frame. If I just call "gamelogic ()" just before rendering the frame, the game rendering speed will be greatly affected by the screen rendering speed, which can vary from 5 frames per second to 120 frames per second.

A simple solution that comes to mind is to calculate the time elapsed since the last frame and call "gamelogic ()" this many times before the next frame: 100 * timeElapsedInSeconds

However, I insist that the “right” way to do this is multithreading; have a separate thread that runs "gamelogic ()" 100 times / sec.

The question is how can I achieve this and what can be done when there is a conflict between two separate streams: a logical change in the contents of the screen (coordinates of a 3d object), while Ogre displays the screen at the same time.

Thank you very much in advance.

+4
source share
3 answers

If this is your first game application, using multithreading to achieve your results may be more work than you should do in the first game. Synchronizing the game cycle and the rendering cycle in different streams is not an easy task.

As you correctly indicate, rendering time can greatly affect the "speed" of your game. I would suggest that you do not make your game logic dependent on a given time slice (i.e., 1/100 second). Make it dependent on the current time of the loop (well, the last time, since you don’t know how long your current frame will take to render).

Normally I would write something like below (what I wrote is strongly ):

float Frametime = 1.0f / 30.0f; while(1) { game_loop(Frametime); // maniuplate objects, etc. render_loop(); // render the frame calculate_new_frametime(); } 

Where Frametime is the calculated cycle time that the current frame has received. When you process a game loop, you use the cycle time from the previous frame (so set the initial value to something reasonable, such as 1/30 or 1/15 of a second). Starting it at the previous cycle time is close enough to get the results you need. Start the game loop using this time interval, and then draw your stuff. You may need to change the logic in the game loop in order not to assume a fixed time interval, but in general these types of corrections are quite simple.

Asynchronous game / rendering cycles may be something that you ultimately need, but this is a complex problem. It includes shooting objects objects and their corresponding data, placing these images in a buffer, and then transferring the buffer to the rendering engine. This memory buffer must be correctly partitioned around critical sections to avoid writing a game loop to it while the rendering cycle is being read from it. You will need to make sure that you copy all the relevant data to the buffer before going into the rendering cycle. In addition, you will need to write logic to stop either loops of the game or rendering, waiting for one or the other to complete.

This complexity is why I suggest writing it in a more consistent way first (unless you have experience that you could). The reason is that in doing so, the “simple” way will first make you find out how your code works, how the rendering engine works, what data the rendering engine needs, etc. Considerable knowledge of multithreading is required in the complex development of the game these days, but knowledge of how to do this requires a deep knowledge of how game systems interact with each other.

+6
source

There is not much good in your core game logic to respond faster. About the only time when this is really useful is physical modeling, where working on a fast fixed time step can cause the sim to behave more consistently.

In addition, just refresh the game loop once per frame and pass a variable time delta instead of relying on a fixed one. The benefit you get from multithreading is minimal compared to the cost, especially if this is your first game.

+1
source

Double buffering rendering objects is an approach you could explore. Meaning, the rendering component uses 1 buffer, which is updated when all game actions have updated the corresponding object in the second buffer.

But personally, I don’t like it, I (and often do) use the Mark approach.

0
source

All Articles