I have a program in which I am drawing images on the screen. The draw function here is called per frame inside in which I have all my drawing code.
I have written an image sequencer that return the respective image from an index of images.
void draw()
{
sequence.getFrameForTime(getCurrentElapsedTime()).draw(0,0); //get current time returns time in float and startson application start
}
On key press, I have start the sequences from the first image [0] and then go on further. So, everytime I press a key, it has to start from [0] unlike the above code where it basically uses the currentTime%numImages to get the frame (which is not the start 0 position of image).
I was thinking to write a timer of own that basically can be triggered everytime I press the key so that the time always starts from 0. But before doing that, I wanted to ask if anybody had better/easier implementation ideas for this?
EDIT
Why I didn't use just a counter?
I have framerate adjustments in my ImageSequence as well.
Image getFrameAtPercent(float rate)
{
float totalTime = sequence.size() / frameRate;
float percent = time / totalTime;
return setFrameAtPercent(percent);
}
int getFrameIndexAtPercent(float percent){
if (percent < 0.0 || percent > 1.0) percent -= floor(percent);
return MIN((int)(percent*sequence.size()), sequence.size()-1);
}
void draw()
{
sequence.getFrameForTime(counter++).draw(0,0);
}
void OnKeyPress(){ counter = 0; }
Is there a reason this wont suffice?
What you should do is increase a "currentFrame" as a float and convert it to an int to index your frame:
void draw()
{
currentFrame += deltaTime * framesPerSecond; // delta time being the time between the current frame and your last frame
if(currentFrame >= numImages)
currentFrame -= numImages;
sequence.getFrameAt((int)currentFrame).draw(0,0);
}
void OnKeyPress() { currentFrame = 0; }
This should gracefully handle machines with different framerates and even changes of framerates on a single machine.
Also, you won't be skipping part of a frame when you loop over as the remainder of the substraction is kept.
Related
I am trying to write simple loop with fixed delta time used for physics and interpolation before rendering the state. I am using Gaffer on games tutorial on fixed timesteps and I tried to understand it and make it work.
float timeStep = 0.01;
float alpha = 1.0;
while (isOpen()) {
processInput();
deltaTime = clock.restart(); // get elapsed time
if (deltaTime > 0.25) { deltaTime = 0.25; } // drop frame guard
accumulator += deltaTime;
while (accumulator >= timeStep) {
// spritePosBefore = sprite.getPosition();
accumulator -= timeStep;
// sprite.move(velocity * timeStep, 0);
// spritePosAfter = sprite.getPosition();
}
if (accumulator > timeStep) { alpha = accumulator / timeStep; } else { alpha = 1.0; }
// sprite.setPosition(Vector2f(spritePosBefore * (1 - alpha) + spritePosAfter * alpha));
clear();
draw(sprite);
display();
}
Now, everything looks good. I have fixed timestep for physics, draw whenever I can after physics are updated and interpolate between two positions. It should work flawless but I can still see sprite stuttering or even going back by one pixel once in a while. Why does it happen? Is there any problem with my code? I spent last two days trying to understand game loop which would ensure me flawless motions but it seems like it doesn't work as I thought it will. Any idea what could be improved?
You should remove the if statement and always calculate alpha; the if statement will never be executed as the condition is always false after the while loop is exited!
After the loop the accumulator will be between 0 and timeStep so you just end up drawing the latest position instead of interpolating.
I don't think the way you do it is necessarily wrong but it looks a bit overcomplicated. I don't understand exactly what you're trying to do so I'm just going to share the way I implement a "fixed time step" in my SFML applications.
The following is the simplest way and will be "good enough" for most applications. It's not the most precise though (the can be a little error between the measured time and the real time) :
sf::Clock clock;
sf::Event event;
while (window_.isOpen()) {
while (window_.pollEvent(event)) {}
if (clock.getElapsedTime().asSeconds() > FLT_FIXED_TIME_STEP) {
clock.restart();
update(FLT_FIXED_TIME_STEP);
}
render();
}
And if you really need precision, you can add a float variable that will act as a "buffer" :
sf::Clock clock;
sf::Event event;
float timeBeforeNextStep = 0.f; // "buffer"
float timeDilation = 1.f; // Useful if you want to slow or speed up time ( <1 for slowmo, >1 for speedup)
while (window_.isOpen()) {
while (window_.pollEvent(event)) {}
timeBeforeNextStep -= clock.restart().asSeconds() * timeDilation;
if (timeBeforeNextStep < FLT_FIXED_TIME_STEP) {
timeBeforeNextStep += FLT_FIXED_TIME_STEP; // '+=', not '=' to make sure we don't lose any time.
update(FLT_FIXED_TIME_STEP);
// Rendering every time you update is not always the best solution, especially if you have a very small time step.
render();
}
}
You might want to use another buffer for rendering (if you want to run at exactly 60 FPS for example).
I have a thread that waits on a std::condition_variable then loops till it is done.
Im trying to slide my rect that is drawn in opengl.
Everything works fine without using a delta, But i would like my rect to slide at the same speed no matter what computer it is ran on.
At the moment it jumps about half way then slides really slow.
If i dont use my delta it does not run at the same speed if ran on slower computers.
Im not sure if i should ihave a if statement and check if time has passed then do the sliding, an not use a delta?
auto toolbarGL::Slide() -> void
{
LARGE_INTEGER then, now, freq;
QueryPerformanceFrequency(&freq);
QueryPerformanceCounter(&then);
while (true)
{
// Waits to be ready to slide
// Keeps looping till stopped then starts to wait again
SlideEvent.wait();
QueryPerformanceCounter(&now);
float delta_time_sec = (float)(now.QuadPart - then.QuadPart) / freq.QuadPart;
if (slideDir == SlideFlag::Right)
{
if (this->x < 0)
{
this->x += 10 * delta_time_sec;
this->controller->Paint();
}
else
SlideEvent.stop();
}
else if (slideDir == SlideFlag::Left)
{
if (this->x > -90)
{
this->x -= 10 * delta_time_sec;
this->controller->Paint();
}
else
SlideEvent.stop();
}
else
SlideEvent.stop();
then = now;
}
}
If you want your rectangle to move at a steady speed no matter what, I suggest a different approach -- instead of relying on your code executing at a particular time and causing a side effect (like x += 10) each time, come up with a function that will tell you what the rectangle's location should be at any given time. That way, no matter when your Paint() method is called, it will always draw the rectangle at the location that corresponds to that time.
For example:
// Returns the current time, in microseconds-since-some-arbitrary-time-zero
unsigned long long GetCurrentTimeMicroseconds()
{
static unsigned long long _ticksPerSecond = 0;
if (_ticksPerSecond == 0) _ticksPerSecond = (QueryPerformanceFrequency(&tps)) ? tps.QuadPart : 0;
LARGE_INTEGER curTicks;
if ((_ticksPerSecond > 0)&&(QueryPerformanceCounter(&curTicks)))
{
return (curTicks.QuadPart*1000000)/_ticksPerSecond;
}
else
{
printf("GetCurrentTimeMicroseconds() failed, oh dear\n");
return 0;
}
}
[...]
// A particular location on the screen
int startPositionX = 0;
// A clock-value at which the rectangle was known to be at that location
unsigned long long timeStampAtStartPosition = GetCurrentTimeInMicroseconds();
// The rectangle's current velocity, in pixels-per-second
int speedInPixelsPerSecond = 10;
// Given any clock-value (in microseconds), returns the expected position of the rectangle at that time
int GetXAtTime(unsigned long long currentTimeInMicroseconds)
{
const long long timeSinceMicroseconds = currentTimeInMicroseconds-timeStampAtStartPosition;
return startPositionX + ((speedInPixelsPerSecond*timeSinceMicroseconds)/1000000);
}
void PaintScene()
{
const int rectX = GetXAtTime(GetCurrentTimeMicroseconds());
// code to paint the rectangle at position (rectX) goes here...
}
Given the above, your program can call PaintScene() as seldom or as often as it wants, and your rectangle's on-screen speed will not change (although the animation will look more or less smooth, depending on how often you call it).
Then if you want the rectangle to change its direction of motion, you can just do something like this:
const unsigned long long now = GetCurrentTimeInMicroseconds();
startPositionX = GetXAtTime(now);
speedInPixelsPerSecond = -speedInPixelsPerSecond; // reverse course!
The above example uses a simple y=mx+b-style equation that provides linear motion, but you can get many different types of motion, by using different parametric equations that take a time-value argument and return a corresponding position-value.
Ok, so i am making this little 'program' and would like to be able to calculate FPS. I had an idea that if i hook a function that is called each frame i could possibly calculate the FPS?
Here's a complete fail, now that i look at it this code again i see how stupid i was to think this would work:
int FPS = 0;
void myHook()
{
if(FPS<60) FPS++;
else FPS = 0;
}
Obviously this is an idiotic attempt, though not sure why i even logically thought it might work in the first place...
But yeah, IS it possible to calculate FPS via hooking a function that is called each frame?
I sat down and was thinking of possible ways to do this but i just couldn't come up with anything. Any info or anything would be helpful, thanks for reading :)
This should do the trick:
int fps = 0;
int lastKnownFps = 0;
void myHook(){ //CALL THIS FUNCTION EVERY TIME A FRAME IS RENDERED
fps++;
}
void fpsUpdater(){ //CALL THIS FUNCTION EVERY SECOND
lastKnownFps = fps;
fps = 0;
}
int getFps(){ //CALL THIS FUNCTION TO GET FPS
return lastKnownFps;
}
You can call your hook function to do the fps calculation but before being able to do that you should:
Keep track of the frames by incrementing a counter each time a redraw is performed
Keep track of how much time has passed since last update (get the current time in your hook function)
Calculate the following
frames / time
Use a high resolution timer. Use a reasonable update rate (1/4 sec or the like).
You can find the time difference between succussive frames. The inverse of this time will give you frame rate. You need to implement a finction getTime_ms() which returns current time in ms.
unsigned int prevTime_ms = 0;
unsigned char firstFrame = 1;
int FPS = 0;
void myHook()
{
unsigned int timeDiff_ms = 0;
unsigned int currTime_ms = getTime_ms(); //Get the current time.
/* You need at least two frames to find the time difference. */
if(0 == firstFrame)
{
//Find the time difference with respect to previous time.
if(currTime_ms >= prevTime_ms)
{
timeDiff_ms = currTime_ms-prevTime_ms;
}
else
{
/* Clock wraparound. */
timeDiff_ms = ((unsigned int) -1) - prevTime_ms;
timeDiff_ms += (currTime_ms + 1);
}
//1 Frame:timeDiff_ms::FPS:1000ms. Find FPS.
if(0 < timeDiff_ms) //timeDiff_ms should never be zero. But additional check.
FPS = 1000/timeDiff_ms;
}
else
{
firstFrame = 0;
}
//Save current time for next calculation.
prevTime_ms = currTime_ms;
}
I am attempting to insert a delay in Processing sketch. I tried Thread.sleep() but I guess it will not work because, as in Java, it prevents rendering of the drawings.
Basically, I have to draw a triangle with delays in drawing three sides.
How do I do that?
Processing programs can read the value of computer’s clock. The current second is read with the second() function, which returns values from 0 to 59. The current minute is read with the minute() function, which also returns values from 0 to 59. - Processing: A Programming Handbook
Other clock related functions : millis(), day(), month(), year().
Those numbers can be used to trigger events and calculate the passage of time, as in the following Processing sketch quoted from the aforementioned book:
// Uses millis() to start a line in motion three seconds
// after the program starts
int x = 0;
void setup() {
size(100, 100);
}
void draw() {
if (millis() > 3000) {
x++;
line(x, 0, x, 100);
}
}
Here's an example of a triangle whose sides are drawn each one after 3 seconds (the triangle is reset every minute):
int i = second();
void draw () {
background(255);
beginShape();
if (second()-i>=3) {
vertex(50,0);
vertex(99,99);
}
if (second()-i>=6) vertex(0,99);
if (second()-i>=9) vertex(50,0);
endShape();
}
As #user2468700 suggests, use a time keeping function. I like millis().
If you have a value to keep track of the time at certain intervals and the current time (continuously updated) you can check if one timer(manually updated one) falls behind the other(continuous one) based on a delay/wait value. If it does, update your data (number of points to draw in this case) and finally the local stop-watch like value.
Here's a basic commented example.
Rendering is separated from data updates to make it easier to understand.
//render related
PVector[] points = new PVector[]{new PVector(10,10),//a list of points
new PVector(90,10),
new PVector(90,90)};
int pointsToDraw = 0;//the number of points to draw on the screen
//time keeping related
int now;//keeps track of time only when we update, not continuously
int wait = 1000;//a delay value to check against
void setup(){
now = millis();//update the 'stop-watch'
}
void draw(){
//update
if(millis()-now >= wait){//if the difference between the last 'stop-watch' update and the current time in millis is greater than the wait time
if(pointsToDraw < points.length) pointsToDraw++;//if there are points to render, increment that
now = millis();//update the 'stop-watch'
}
//render
background(255);
beginShape();
for(int i = 0 ; i < pointsToDraw; i++) {
vertex(points[i].x,points[i].y);
}
endShape(CLOSE);
}
Lets say I have 4 images and I want to use these 4 images to animate a character. The 4 images represent the character walking. I want the animation to repeat itself as long as I press the key to move but to stop right when I unpress it. It doesn't need to be SFML specific if you don't know it, just basic theory would really help me.
Thank you.
You may want some simple kind of state machine. When the key is down (see sf::Input's IsKeyDown method), have the character in the "animated" state. When the key is not down, have the character in "not animated" state. Of course, you could always skip having this "state" and just do what I mention below (depending on exactly what you're doing).
Then, if the character is in the "animated" state, get the next "image" (see the next paragraph for more details on that). For example, if you have your images stored in a simple 4 element array, the next image would be at (currentIndex + 1) % ARRAY_SIZE. Depending on what you are doing, you may want to store your image frames in a more sophisticated data structure. If the character is not in the "animated" state, then you wouldn't do any updating here.
If your "4 images" are within the same image file, you can use the sf::Sprite's SetSubRect method to change the portion of the image displayed. If you actually have 4 different images, then you probably would need to use the sf::Sprite's SetImage method to switch the images out.
How would you enforce a framerate so that the animation doesn't happen too quickly?
Hello please see my answer here and accept this post as the best solution.
https://stackoverflow.com/a/52656103/3624674
You need to supply duration per frame and have the total progress be used to step through to the frame.
In the Animation source file do
class Animation {
std::vector<Frame> frames;
double totalLength;
double totalProgress;
sf::Sprite *target;
public:
Animation(sf::Sprite& target) {
this->target = ⌖
totalProgress = 0.0;
}
void addFrame(Frame& frame) {
frames.push_back(std::move(frame));
totalLength += frame.duration;
}
void update(double elapsed) {
// increase the total progress of the animation
totalProgress += elapsed;
// use this progress as a counter. Final frame at progress <= 0
double progress = totalProgress;
for(auto frame : frames) {
progress -= (*frame).duration;
// When progress is <= 0 or we are on the last frame in the list, stop
if (progress <= 0.0 || &(*frame) == &frames.back())
{
target->setTextureRect((*frame).rect);
break; // we found our frame
}
}
};
To stop when you unpress, simply only animate when the key is held
if(isKeyPressed) {
animation.update(elapsed);
}
To support multiple animations for different situations have a boolean for each state
bool isWalking, isJumping, isAttacking;
...
if(isJumping && !isWalking && !isAttacking) {
jumpAnimation.update(elapsed);
} else if(isWalking && !isAttacking) {
walkAnimation.update(elapsed);
} else if(isAttacking) {
attackAnimation.update(elapsed);
}
...
// now check for keyboard presses
if(jumpkeyPressed) { isJumping = true; } else { isJumping false; }