Just as the title says, my game is running fine at 30FPS, even 60FPS but i see a bit of choppiness/jerking every few seconds or so randomly.
I've researched about Threads vs NSTimers at iDevGames and google, and I would prefer to keep using NSTimers (Threads are confusing to me).
Does anyone know why I am getting this behavior?
I read that it could be iphone OS 3.0 or something like that, but could not tell for sure.
I am just setting a timer in startLoop() which calls gameLoop() which contains two methods: drawView and updateLogic.
Just as the title says, my game is running fine at 30FPS, even 60FPS but i see a bit of choppiness/jerking every few seconds or so randomly.
I've researched about Threads vs NSTimers at iDevGames and google, and I would prefer to keep using NSTimers (Threads are confusing to me).
Does anyone know why I am getting this behavior?
I read that it could be iphone OS 3.0 or something like that, but could not tell for sure.
I am just setting a timer in startLoop() which calls gameLoop() which contains two methods: drawView and updateLogic.
Have you determined what the root of this variation is? As far as running, you are at the mercy of the OS. The bigger question is have you made your app be frame independent or not? Even with frame independent code, large frame bumps will have some effect, but not a gross as if you are running frame dependent code.
Our app oscillates between high 40s to mid 20s. But for the most part, you cannot see any issues.
I cannot seem to figure out the root of the problem myself.
I am trying to run the game FPS dependent.
I'm thinking it has to do with the NSTimer not being in sync with the VBL, and so there is a slight difference that i need to calculate and use it somehow to avoid the jerking?
Not quite entirely sure, but any help would be appreciated.
I cannot seem to figure out the root of the problem myself.
I am trying to run the game FPS dependent.
I'm thinking it has to do with the NSTimer not being in sync with the VBL, and so there is a slight difference that i need to calculate and use it somehow to avoid the jerking?
Not quite entirely sure, but any help would be appreciated.
So you're saying you are running the game frame rate dependent? This is a bad idea and is a classic problem people do because it is the easier way to go. To establish frame rate independence is straight forward and easy to implement, the rough process is:
For each frame, determine the time between frames. This is your dt (delta time). Use this dt then to drive all your values. You will need to establish your own basis for getting this time between frames. In other words, I am not giving you code for this. Just google this, there are plenty of references on line for all of this.
Let's now say you want to move an object to the right.
Frame dependent code:
obj.x += dx; // dx == the amount of distance to move per frame.
Frame independent code
obj.x += dx_per_sec * dt; // Here dx_per_sec is the rate to move X for 1 sec, dt is assumed to be the delta amount of time between frames in seconds, this would be float!
That's pretty much it. If you drive all your motion this way, your jerkiness will be minimized. Note I am not saying eliminated. You also should not have to be worrying about whether nor not you are in VBL or not. Frankly that is wasted efforts, since you cannot always control how the OS wants to sequence your code v. the display rate or any other system resource.
I've had good results with a NSTimer set to a reasonable framerate - 30FPS in my case. The only trick I had to do was to make sure I "draw then update" instead of "update then draw."
If you update your model before you draw, you're delaying your draw call by an unknown amount of time each frame, and your frame rate will not be smooth.
I saw many tips for threading, pumping the event queue, etc. but I wouldn't try them until you're sure you need them - premature optimization and all that.
Hmm, that seems like a clever idea.
But I am unsure of how to "update" then "draw".
The only way I can think of is at the moment, is to set a count 30FPS, and only "DRAW" when count is 1, which means it has updated, so count will not go up unless updated.
Something like that lol.
Hmm, that seems like a clever idea.
But I am unsure of how to "update" then "draw".
The only way I can think of is at the moment, is to set a count 30FPS, and only "DRAW" when count is 1, which means it has updated, so count will not go up unless updated.
Something like that lol.
The term "update then draw" probably only makes sense if you're doing your own rendering, e.g. via OpenGL. If you're using a higher-level API and just updating image coordinates or something like that, it probably doesn't make much sense.
The "update" is the phase where everything in the game that is logic-related is performed: processing user input, moving actors & projectiles, checking collisions, etc.
Once the game state has been updated, everything can be drawn in its current state, which is what the "draw" phase does.
This doesn't seem to help =[.
Implemented both, draw then update and delta time.
From my knowledge, I am drawing THEN updating logic and the delta doesn't seem to help.
This doesn't seem to help =[.
Implemented both, draw then update and delta time.
From my knowledge, I am drawing THEN updating logic and the delta doesn't seem to help.
Is this pseudo-code or the real deal? I don't see where 'lastTime' is being set... Also, I'm not sure I see the point of skipping the logic update. If your game state isn't updated, the draw phase will simply redraw the last frame again.
Hmm, could you possibly elaborate on what you mean by setting lastTime to 'time' once delta is determined?
I'm guessing I would set lastTime to 'time' once I have figured out the delta, but I do not understand how that would all work out.
I'll just play around and do a few google searches in the meantime...
It's working quite well, except for the fact that it's still not as smooth.
I am using mobileden's solution to increment the x/y by a certain amount multiplied by the delta.
I cannot seem to get this "smoothness" that I yearn for.
Is there something wrong with the way I am moving my camera?
I use gluLookAt, and increment movementX/movementZ by increments of 1 in a timer, and so those if statements check to see if they are true and starts moving the camera mapX/mapZ by 0.2 * delta.
Hmm, could you possibly elaborate on what you mean by setting lastTime to 'time' once delta is determined?
I'm guessing I would set lastTime to 'time' once I have figured out the delta, but I do not understand how that would all work out.
The smoothness you're looking for is achieved by synchronizing animations and movements to a timebase other than the NSTimer callback, which is unreliable from the standpoint of providing an accurate callback frequency. So, in your timer callback you need know how much real world time has passed since the last update, so you know how much "updating" you need to do. That's why you're using the CFAbsoluteTime... as a timing reference, and you're calculating how much time has elapsed since the last update -- the "delta". But when you get to the next frame, how do you know what the real world time was on the previous frame? If you said "by saving the time in my 'lastTime' variable", you're correct.
Quote:
Originally Posted by jeonghyunhan
I ... increment movementX/movementZ by increments of 1 in a timer, and so those if statements check to see if they are true and starts moving the camera mapX/mapZ by 0.2 * delta.
OK, I'm confused. What is this "timer" that's incrementing those movement variables? Is it another NSTimer callback?
I'm setting the fps initially to 30.0f, and in my timer it is set to 1.0f / fps.
I have 4 other timers that are fired 1.0f / 6.0f, but only one can be fired at a time.
This is my way of achieving an analog control.
Anyway, here is an example of what I do:
They 'y' moves the texCoords, the playerZ moves the players coords in the 2D array and movementZ moves the actually camera (well, to be precise, mapZ moves the camera but it is compared to movementZ to see whether or not to move the camera).
There is also a movementZClone, which is used to move the texCoords AFTER the camera has shifted. I build extra tiles to the left/right/top/and bottom so I can shift the camera and then rebuild the map. I use this complicated method so I can build big maps, practically unlimited and not limited to my previous 50x50 as max.
Sorry if the way I am explaining is confusing =[.
Holy crap, a whole day and half of trying to figure this out!
Can somebody just give a quick sample code of how they run their game loop with a NSTimer?
I cannot find what I am doing wrong.
Im building AND rendering 1800 triangles 30FPS and that COULD be a source of my problem.
Or maybe it's because I use multiple NSTimers or even because I have multiple gluLookAt functions being called to move the camera.
Holy crap, a whole day and half of trying to figure this out!
Can somebody just give a quick sample code of how they run their game loop with a NSTimer?
I cannot find what I am doing wrong.
Im building AND rendering 1800 triangles 30FPS and that COULD be a source of my problem.
Or maybe it's because I use multiple NSTimers or even because I have multiple gluLookAt functions being called to move the camera.
I'll be frank: I looked at your code and couldn't make head or tails out of what you're doing. But anyway... you already have the key rule, which is to use a reliable, external time base for calculating the elapsed time between NSTimer callbacks. The important nugget of information that should be gleaned from this discussion is that using NSTimer as a timebase is unreliable, so if you have other things in your application that are being updated via NSTimer, you're probably introducing timing errors in that code. If you're doing a crapload of rendering, you could be seeing low a FPS rate, which might make things appear choppy/jerky. Have you instrumented the app to determine what your average FPS is?
I've used the OPENGLES instrument and shows I get above 55FPS.
I bet my problem IS that i'm running frame dependent code.
There are a few resources I found out there that should help me achieve frame independent but there is one thing that i'm still confused about.
I saw a few examples that use frame independent code but they all use an NSTimer to fire first.
Huh?
Maybe I interpreted the code wrong or something?
I've used the OPENGLES instrument and shows I get above 55FPS.
I bet my problem IS that i'm running frame dependent code.
There are a few resources I found out there that should help me achieve frame independent but there is one thing that i'm still confused about.
I saw a few examples that use frame independent code but they all use an NSTimer to fire first.
Huh?
Maybe I interpreted the code wrong or something?
They use NSTimer to keep pumping the main game loop ... you still need to obtain the time interval from the last time your game loop was run and drive your animations using that value.
Some of this code might be a bit implementation dependent (the needs of the sprite I was using as test and what I was attempting, basically "animate the water drop falling from the top of the screen to the bottom of the screen by changing animation frame and moving the sprite's center) but it might be useful... I hope.
Also, since this thread was helpful to me, I wanted to post what I am doing with this thread's insights and be helpful to others hopefully.
2.) Wanted a 30 Hz run loop (30 FPS max refresh rate).
3.) The 128x128 sprite only has 25 frames so animating it at 30 FPS would be too fast... decoupling frame-time from animation time of an element drawn on screen.
Code:
#import "AnimationViewController.h"
#import "WapToolAppDelegate.h"
#import "SysTools.h"
#import <QuartzCore/QuartzCore.h>
@implementation AnimationViewController
@synthesize drop, fieldOffsetDrop, offsetDrop, vBlank, iDelegate, frameIndex, dropletXY, dropImageArray;
-(void) updateLogic {
float dyDroplet = (344.0f/11.0f); //watch out for the .0f, not to make it an integer division
if (frameIndex > 9 && frameIndex < 21) {
dropletXY.y = dropletXY.y + dyDroplet;
}
if ((dropletXY.y + 64) > (460 - 0.00001f) && frameIndex == 24) {
//equivalent to saying: has the object reached its target && should the animation be restarted?
frameIndex = 0;
dropletXY.y = 52;
drop.center = dropletXY;
drop.image = [self.dropImageArray objectAtIndex:frameIndex];
return;
}
drop.center = dropletXY;
if ((dropletXY.y + 64) > 450) CMLog (@"Droplet.PaB.y = %f", (dropletXY.y + 64));
if (frameIndex < 24) frameIndex++; //frameIndex = (frameIndex + 1)%(25);
}
-(void) runLoop {
//runLoop called roughly at a 30 FPS cadence
NSAutoreleasePool * gamePool = [[NSAutoreleasePool alloc] init];
static CFTimeInterval last_time = 0.0f;
static float cycles_left_over = 0.0f;
static float dt2 = 0.0f;
float dropAnimRate = (2.1f/25.0f);
CFTimeInterval current_time = CACurrentMediaTime();
float dt = current_time - last_time + cycles_left_over;
dt2 += dt;
[self drawScene];
if (dt > (MAX_CPF * FRAME_TIME)) {
dt = (MAX_CPF * FRAME_TIME);
}
while (dt > FRAME_TIME) {
if (dt2 > (dropAnimRate - aEPS)){
[self updateLogic];
dt2 = 0.0f;
}
dt -= FRAME_TIME;
}
cycles_left_over = dt;
last_time = current_time;
[gamePool release];
}
-(void) drawScene {
CMLog (@"frameIndex = %d", frameIndex);
drop.image = [self.dropImageArray objectAtIndex:frameIndex];
}