Replay system for cocos2d with FPS correction - c++

I'm building a replay system for my cocos2d-x game, it uses box2d too.
The game is nondeterministic so I can't store the user actions and replay them, so what I'm doing is storing position and angle of a sprite for each time step into a stream.
Now I have replay files that are in the following format
x,y,angle\r\n
Each line represents the state of the sprite at a given time step.
Now when I replay it back on the same device, it's all perfect, but of course life isn't this easy, so the problem arises if i want to play it back on different frame rates, how can this happen ?
is there a smart way to handle this issue ?
I don't have a fixed time step too, I'll implement this soon so you can consider a fixed time step in your answer :)
Thanks !

Ok, you record the delta time along with each recorded frame. Best to start recording the first frame with a delta time of 0 and assume the same for the first frame of the playback.
Then in your update method accumulate the current delta time:
-(void) update:(ccTime)delta
{
if (firstFrame)
{
totalTime = 0;
totalRecordedTime = 0;
firstFrame = NO;
}
else
{
totalTime += delta;
}
totalRecordedTime += [self getRecordedDeltaForFrameIndex:recordedFrameIndex];
if (totalTime > totalRecordedTime)
{
[self advanceRecordedFrameIndex];
}
// alternative:
id recordedFrameData = [self getRecordedFrameForDeltaTime:totalTime];
// apply recorded data ...
}
Alternative: create a method that returns or "applies" the recorded frame based on the current time delta. Pick the frame whose recorded total delta time is equal or lower the current total delta time.
To make searching for the frame faster, remember the most recent recorded frame's index and start searching from there (compare each frame's delta time), always including the most recent frame as well.
Occassionally this will display the same recorded frame multiple times, or it may skip recorded frames - depending on the actual device framerate and the framerate during recording.

Related

How to define how much CPU to use in SFML game?

I've made a game but I don't know if the game will work the same way in other devices. For example if the CPU of a computer is high will the player and enemies move faster? If so, is there a way to define CPU usage available in SFML? The way the player and enemies move in my program is to :
1-Check if the key is pressed
2-If so : move(x,y); Or is there a way to get the CPU to do some operations in the move function.
Thank you!
It sounds like you are worried about the physics of your game being affected by the game's framerate. Your intuition is serving you well! This is a significant problem, and one you'll want to address if you want your game to feel professional.
According to Glenn Fiedler in his Gaffer on Games article 'Fix Your Timestep!'
[A game loop that handles time improperly can make] the behavior of your physics simulation [depend] on the delta time you pass in. The effect could be subtle as your game having a slightly different “feel” depending on framerate or it could be as extreme as your spring simulation exploding to infinity, fast moving objects tunneling through walls and the player falling through the floor!
Logic dictates that you must detach the dependencies of your update from the time it takes to draw a frame. A simple solution is to:
Pick an amount of time which can be safely processed (your timestep)
Add the time passed every frame into an accumulated pool of time
Process the time passed in safe chunks
In pseudocode:
time_pool = 0;
timestep = 0.01; //or whatever is safe for you!
old_time = get_current_time();
while (!closed) {
new_time = get_current_time();
time_pool += new_time - old_time;
old_time = new_time;
handle_input();
while (time_pool > timestep)
{
consume_time(timestep); //update your gamestate
time_pool -= timestep;
}
//note: leftover time is not lost, and will be left in time_pool
render();
}
It is worth noting that this method has its own problem: future frames have to consume the time produced by calls to consume_time. If a call to consume_time takes too long, the time produced might require two calls be made next frame - then four - then eight - and so on. If you use this method, you will have to make sure consume_time is very efficient, and even then it would be best to have a contingency plan.
For a more thorough treatment I encourage you to read the linked article.

How to reduce OpenGL CPU usage and/or how to use OpenGL properly

I'm working a on a Micromouse simulation application built with OpenGL, and I have a hunch that I'm not doing things properly. In particular, I'm suspicious about the way I am getting my (mostly static) graphics to refresh at a close-to-constant framerate (60 FPS). My approach is as follows:
1) Start a timer
2) Draw my shapes and text (about a thousand of them):
glBegin(GL_POLYGON);
for (Cartesian vertex : polygon.getVertices()) {
std::pair<float, float> coordinates = getOpenGlCoordinates(vertex);
glVertex2f(coordinates.first, coordinates.second);
}
glEnd();
and
glPushMatrix();
glScalef(scaleX, scaleY, 0);
glTranslatef(coordinates.first * 1.0/scaleX, coordinates.second * 1.0/scaleY, 0);
for (int i = 0; i < text.size(); i += 1) {
glutStrokeCharacter(GLUT_STROKE_MONO_ROMAN, text.at(i));
}
glPopMatrix();
3) Call
glFlush();
4) Stop the timer
5) Sleep for (1/FPS - duration) seconds
6) Call
glutPostRedisplay();
The "problem" is that the above approach really hogs my CPU - the process is using something like 96-100%. I know that there isn't anything inherently wrong with using lots of CPU, but I feel like I shouldn't be using that much all of the time.
The kicker is that most of the graphics don't change from frame to frame. It's really just a single polygon moving over (and covering up) some static shapes. Is there any way to tell OpenGL to only redraw what has changed since the previous frame (with the hope it would reduce the number of glxxx calls, which I've deemed to be the source of the "problem")? Or, better yet, is my approach to getting my graphics to refresh even correct?
First and foremost the biggest CPU hog with OpenGL is immediate mode… and you're using it (glBegin, glEnd). The problem with IM is, that every single vertex requires a whole couple of OpenGL calls being made; and because OpenGL uses a thread local state this means that each and every OpenGL call must go through some indirection. So the first step would be getting rid of that.
The next issue is with how you're timing your display. If low latency between user input and display is not your ultimate goal the standard approach would setting up the window for double buffering, enabling V-Sync, set a swap interval of 1 and do a buffer swap (glutSwapBuffers) once the frame is rendered. The exact timings what and where things will block are implementation dependent (unfortunately), but you're more or less guaranteed to exactly hit your screen refresh frequency, as long as your renderer is able to keep up (i.e. rendering a frame takes less time that a screen refresh interval).
glutPostRedisplay merely sets a flag for the main loop to call the display function if no further events are pending, so timing a frame redraw through that is not very accurate.
Last but not least you may be simply mocked by the way Windows does account CPU time (time spent in driver context, which includes blocking, waiting for V-Sync) will be accouted to the consumed CPU time, while it's in fact interruptible sleep. However you wrote, that you already do a sleep in your code, which would rule that out, because the go-to approach to get a more reasonable accounting would be adding a Sleep(1) before or after the buffer swap.
I found that by putting render thread to sleep helps reducing cpu usage from (my case) 26% to around 8%
#include <chrono>
#include <thread>
void render_loop(){
...
auto const start_time = std::chrono::steady_clock::now();
auto const wait_time = std::chrono::milliseconds{ 17 };
auto next_time = start_time + wait_time;
while(true){
...
// execute once after thread wakes up every 17ms which is theoretically 60 frames per
// second
auto then = std::chrono::high_resolution_clock::now();
std::this_thread::sleep_until(next_time);
...rendering jobs
auto elasped_time =
std::chrono::duration_cast<std::chrono::milliseconds> (std::chrono::high_resolution_clock::now() - then);
std::cout << "ms: " << elasped_time.count() << '\n';
next_time += wait_time;
}
}
I thought about attempting to measure the frame rate while the thread is asleep but there isn't any reason for my use case to attempt that. The result was averaging around 16ms so I thought it was good enough
Inspired by this post

Fixed timestep stuttering with VSync on

In a 2D OpenGL engine I implemented I have a fixed timestep as described in the famous fix your timestep article, along with blending.
I have a test object that moves vertically (y axis). There is stuttering in the movement (preprogrammed movement, not from user input). This means the object does not move smoothly across the screen.
Please see the uncompressed video I am linking: LINK
The game framerate stays at 60fps (Vsync turned on from Nvidia driver)
The game logic updates at a fixed 20 updates/ticks per second, set by me. This is normal. The object moves 50 pixels per update.
However the movement on the screen is severely stuttering.
EDIT: I noticed by stepping in the recorded video above frame by frame that the stuttering is caused by a frame being shown twice.
EDIT2: Setting the application priority to Realtime in the task manager completely eliminates the stutter! However this obviously isn't a solution.
Below is the object y movement delta at different times, with VSync turned off
First column is the elapsed time since last frame, in microseconds (ex 4403 )
Second column is movement on the y axis of an object since last frame.
Effectively, the object moves 1000 pixels per second, and the log below confirms it.
time since last frame: 4403 ypos delta since last frame: 4.403015
time since last frame: 3807 ypos delta since last frame: 3.806976
time since last frame: 3716 ypos delta since last frame: 3.716003
time since last frame: 3859 ypos delta since last frame: 3.859009
time since last frame: 4398 ypos delta since last frame: 4.398010
time since last frame: 8961 ypos delta since last frame: 8.960999
time since last frame: 7871 ypos delta since last frame: 7.871002
time since last frame: 3985 ypos delta since last frame: 3.984985
time since last frame: 3684 ypos delta since last frame: 3.684021
Now with VSync turned on
time since last frame: 17629 ypos delta since last frame: 17.628906
time since last frame: 15688 ypos delta since last frame: 15.687988
time since last frame: 16641 ypos delta since last frame: 16.641113
time since last frame: 16657 ypos delta since last frame: 16.656738
time since last frame: 16715 ypos delta since last frame: 16.715332
time since last frame: 16663 ypos delta since last frame: 16.663086
time since last frame: 16666 ypos delta since last frame: 16.665771
time since last frame: 16704 ypos delta since last frame: 16.704102
time since last frame: 16626 ypos delta since last frame: 16.625732
I would say they look ok.
This has been driving me bonkers for days, what am I missing?
Below is my Frame function which is called in a loop:
void Frame()
{
static sf::Time t;
static const double ticksPerSecond = 20;
static uint64_t stepSizeMicro = 1000000 / ticksPerSecond; // microseconds
static sf::Time accumulator = sf::seconds(0);
gElapsedTotal = gClock.getElapsedTime();
sf::Time elapsedSinceLastFrame = gElapsedTotal - gLastFrameTime;
gLastFrameTime = gElapsedTotal;
if (elapsedSinceLastFrame.asMicroseconds() > 250000 )
elapsedSinceLastFrame = sf::microseconds(250000);
accumulator += elapsedSinceLastFrame;
while (accumulator.asMicroseconds() >= stepSizeMicro)
{
Update(stepSizeMicro / 1000000.f);
gGameTime += sf::microseconds(stepSizeMicro);
accumulator -= sf::microseconds(stepSizeMicro);
}
uint64_t blendMicro = accumulator.asMicroseconds() / stepSizeMicro;
float blend = accumulator.asMicroseconds() / (float) stepSizeMicro;
if (rand() % 200 == 0) Trace("blend: %f", blend);
CWorld::GetInstance()->Draw(blend);
}
More info as requested in the comments:
stuttering occurs both while in fullscreen 1920x1080 and in window mode 1600x900
the setup is a simple SFML project. I'm not aware if it uses VBO/VAO internally when rendering textured rectangles
not doing anything else on my computer. Keep in mind this issue occurs on other computers as well, it's not just my rig
am running on primary display. The display doesn't really make a difference. The issue occurs both in fullscreen and window mode.
I have profiled my own code. The issue was there was an area of my code that occasionally had performance spikes due to cache misses. This caused my loop to take longer than 16.6666 milliseconds, the max time it should take to display smoothly at 60Hz. This was only one frame, once in a while. That frame caused the stuttering. The code logic itself was correct, this proved to be a performance issue.
For future reference in hopes that this will help other people, how I debugged this was I put an
if ( timeSinceLastFrame > 16000 ) // microseconds
{
Trace("Slow frame detected");
DisplayProfilingInformation();
}
in my frame code. When the if is triggered, it displays profiling stats for the functions in the last frame, to see which function took the longest in the previous frame. I was thus able to pinpoint the performance bug to a structure that was not suitable for its usage. A big, nasty map of maps that generated a lot of cache misses and occasionally spiked in performance.
I hope this helps future unfortunate souls.
It seems like you're not synchronizing your 60Hz frame loop with the GPU's 60Hz VSync. Yes, you have enabled Vsync in Nvidia but that only causes Nvidia to use a back-buffer which is swapped on the Vsync.
You need to set the swap interval to 1 and perform a glFinish() to wait for the Vsync.
A tricky one, but from the above it seems to me this is not a 'frame rate' problem, but rather somewhere in your 'animate' code. Another observation is the line "Update(stepSizeMicro / 1000000.f);". the divide by 1000000.f could mean you are losing resolution due to the limitations of floating point numbers bit resolution, so rounding could be your killer?

Cocos2D Moving sprite sometimes jerky

Here I want to move some cocos2D sprite object from top to bottom. Sprites r generated at random position in screen. Some time all sprite's movement s jerky..I can't use CCMove as I want to maintain equal distance between sprite.
[self schedule: #selector(updateObjects:)];
-(void)updateObjects:(ccTime) dt
{
//when I print dt, it gives different value..
//jerk comes when this value s larger than ideal value..
for(Obstacles *Obs in ObsArray)
{
CGPoint pos = Obs.position;
pos.y -= gameSpeed;
Obs.position = pos;
}
}
How can I solve this problem.
Cocos2d uses variable time step: dt is time in seconds since last call of this scheduled selector. If your gameSpeed is distance the object has to move by per second (in points), then you must change your object position by gameSpeed * dt.
Resolved problem by
1. Removed all printf and cocos2D logs
2. Added separate thread for image loading.
3. Used multiple 1024x1024 sprite sheet in place of 2048x2048 in HD mode.
I had the same issue i tried lots of thing, at the end i found that it will jerk more on android devices then ios devices.. the frame-rate they rendered should be updated on constant interval .. if you use update method then set the constant delta time
For example i have used update method
void MyClass::update(float dt) {
int positioniteration=8;
int valocityiteration=8;
world->Step(1/60.0,valocityiteration,positioniteration);//60 FPS }
and also i have added these lines in appdelegate
director->setDepthTest(false);
director->setProjection(Director::Projection::_2D);// MY GAME IS 2D SO USED 2D PROJECTION .. IT HELPED ME
Hope this helps.:)

How to pause an animation with OpenGL / glut

To achieve an animation, i am just redrawing things on a loop.
However, I need to be able to pause when a key is pressed. I know the way i'm doing it now its wrong because it eats all of my cycles when the loop is going on.
Which way is better, and will allow for a key pause and resume?
I tried using a bool flag but obviously it didnt change the flag until the loop was done.
You have the correct very basic architecture sorted in that the everything needs to be updated in a loop, but you need to make your loop a lot smarter for a game (or other application requiring OpenGL animations).
However, I need to be able to pause when a key is pressed.
A basic way of doing this is to have a boolean value paused and to wrap the game into a loop.
while(!finished) {
while(!paused) {
update();
render();
}
}
Typically however you still want to do things such as look at your inventory, craft things, etc. while your game is paused, and many games still run their main loop while the game's paused, they just don't let the actors know any time has passed. For instance, it sounds like your animation frames simply have a number of game-frames to be visible for. This is a bad idea because if the animation speed increases or decreases on a different computer, the animation speed will look wrong on those computers. You can consider my answer here, and the linked samples to see how you can achieve framerate-independent animation by specifying animation frames in terms of millisecond duration and passing in the frame time in the update loop. For instance, your main game then changes to look like this:
float previousTime = 0.0f;
float thisTime = 0.0f;
float framePeriod = 0.0f;
while(!finished) {
thisTime = getTimeInMilliseconds();
framePeriod = previousTime - thisTime;
update(framePeriod);
render();
previousTime = thisTime;
}
Now, everything in the game that gets updated will know how much time has passed since the previous frame. This is helpful for all your physics calculations as all of our physical formulae are in terms of time + starting factors + decay factors (for instance, the SUVAT equations). The same information can be used for your animations to make them framerate independent as I have described with some links to examples here.
To answer the next part of the question:
it eats all of my cycles when the loop is going on.
This is because you're using 100% of the CPU and never going to sleep. If we consider that we want for instance 30fps on the target device (and we know that this is possible) then we know the period of one frame is 1/30th of a second. We've just calculated the time it takes to update and render our game, so we can sleep for any of the spare time:
float previousTime = 0.0f;
float thisTime = 0.0f;
float framePeriod = 0.0f;
float availablePeriod = 1 / 30.0f;
while (!finished) {
thisTime = getTimeInMilliseconds();
framePeriod = previousTime - thisTime;
update(framePeriod);
render();
previousTime = thisTime;
if (framePeriod < availablePeriod)
sleep(availablePeriod - framePeriod);
}
This technique is called framerate governance as you are manually controlling the rate at which you are rendering and updating.