Advertise Mobile SDKs Books Events Forum News Social Networking Support Us
Follow @iphonedevsdk on Twitter

Interface 2, Advanced iOS
Mockup & Code Gen
($9.99)

Make your own iPhone apps
and run them live!
(free)

Pic Frame Dynamo: Photo Editing
($0.99)

Abiliator
($1.99)

Want your application or service advertised on iPhone Dev SDK?

Go Back   iPhone Dev SDK Forum > iPhone SDK Development Forums > iPhone SDK Game Development

Reply
 
LinkBack Thread Tools Display Modes
Old 09-20-2009, 12:26 AM   #1 (permalink)
Registered Member
 
Join Date: May 2009
Posts: 190
jeonghyunhan is on a distinguished road
Default NSTimer game loop is choppy/jerky?

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.
__________________
Blockle:http://www.youtube.com/watch?v=vxEKDkpAfRU
jeonghyunhan is offline   Reply With Quote
Old 09-21-2009, 01:48 AM   #2 (permalink)
Registered Member
 
mobileben's Avatar
 
Join Date: Jul 2009
Location: Zgrunturos
Posts: 161
mobileben is on a distinguished road
Default

Quote:
Originally Posted by jeonghyunhan View Post
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.
mobileben is offline   Reply With Quote
Old 09-21-2009, 03:18 AM   #3 (permalink)
Registered Member
 
Join Date: May 2009
Posts: 190
jeonghyunhan is on a distinguished road
Default

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.
__________________
Blockle:http://www.youtube.com/watch?v=vxEKDkpAfRU
jeonghyunhan is offline   Reply With Quote
Old 09-22-2009, 01:29 PM   #4 (permalink)
Registered Member
 
mobileben's Avatar
 
Join Date: Jul 2009
Location: Zgrunturos
Posts: 161
mobileben is on a distinguished road
Default

Quote:
Originally Posted by jeonghyunhan View Post
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.
mobileben is offline   Reply With Quote
Old 09-22-2009, 02:29 PM   #5 (permalink)
Registered Member
 
Join Date: May 2009
Posts: 190
jeonghyunhan is on a distinguished road
Default

Great!
I was reading some stuff about this delta time.
I'll get back with results.
__________________
Blockle:http://www.youtube.com/watch?v=vxEKDkpAfRU
jeonghyunhan is offline   Reply With Quote
Old 09-22-2009, 03:22 PM   #6 (permalink)
Registered Member
iPhone Dev SDK Supporter
 
smasher's Avatar
 
Join Date: Jul 2008
Location: San Mateo, CA (San Fran)
Posts: 3,858
smasher will become famous soon enough
Default

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.
__________________

Free Games!
smasher is offline   Reply With Quote
Old 09-22-2009, 06:11 PM   #7 (permalink)
Registered Member
 
Join Date: May 2009
Posts: 190
jeonghyunhan is on a distinguished road
Default

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.
__________________
Blockle:http://www.youtube.com/watch?v=vxEKDkpAfRU
jeonghyunhan is offline   Reply With Quote
Old 09-22-2009, 06:26 PM   #8 (permalink)
Pro. Game Developer
iPhone Dev SDK Supporter
 
Join Date: Feb 2009
Location: żLa Islas Hermosas?
Posts: 2,176
Kalimba is on a distinguished road
Default

Quote:
Originally Posted by jeonghyunhan View Post
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.
__________________
~~ Word Flurry ~~ App Store / Website / Facebook
Kalimba is offline   Reply With Quote
Old 09-22-2009, 07:16 PM   #9 (permalink)
Registered Member
 
Join Date: May 2009
Posts: 190
jeonghyunhan is on a distinguished road
Default

EDIT: Further inspection leads me to think I am skipping logic every other 1/30 second.
So: skip draw, logic draw, skip draw, logic draw and so on.

Code:
- (void)gameLoop {
	
	CFTimeInterval time;
	time = CFAbsoluteTimeGetCurrent();
	float delta = (time - lastTime);
	
	if (count == 1) {
		
		[self updateLogic:delta];
		count = 0;
	}
	[self drawView];
	count++;
}

	
- (void)stopLoop {
	
	[timer invalidate];
}


- (void)startLoop {

	timer = [NSTimer scheduledTimerWithTimeInterval:1.0f / 30.0f target:self selector:@selector(gameLoop) userInfo:nil repeats:YES];
}


- (void)updateLogic:(float)delta {
	
	if (mapX > movementX + 0.1) {
		mapX -= 0.2 * delta;
	}
	
	if (mapX < movementX - 0.1) {
		mapX += 0.2 * delta;
	}
	
	if (mapZ < movementZ - 0.1) {
		mapZ += 0.2 * delta;
	}
	
	if (mapZ > movementZ + 0.1) {
		mapZ -= 0.2 * delta;
	}
}
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.
__________________
Blockle:http://www.youtube.com/watch?v=vxEKDkpAfRU

Last edited by jeonghyunhan; 09-22-2009 at 07:19 PM.
jeonghyunhan is offline   Reply With Quote
Old 09-22-2009, 07:28 PM   #10 (permalink)
Pro. Game Developer
iPhone Dev SDK Supporter
 
Join Date: Feb 2009
Location: żLa Islas Hermosas?
Posts: 2,176
Kalimba is on a distinguished road
Default

Quote:
Originally Posted by jeonghyunhan View Post
EDIT: Further inspection leads me to think I am skipping logic every other 1/30 second.
So: skip draw, logic draw, skip draw, logic draw and so on.

Code:
- (void)gameLoop {
	
	CFTimeInterval time;
	time = CFAbsoluteTimeGetCurrent();
	float delta = (time - lastTime);
	
	if (count == 1) {
		
		[self updateLogic:delta];
		count = 0;
	}
	[self drawView];
	count++;
}

	
- (void)stopLoop {
	
	[timer invalidate];
}


- (void)startLoop {

	timer = [NSTimer scheduledTimerWithTimeInterval:1.0f / 30.0f target:self selector:@selector(gameLoop) userInfo:nil repeats:YES];
}


- (void)updateLogic:(float)delta {
	
	if (mapX > movementX + 0.1) {
		mapX -= 0.2 * delta;
	}
	
	if (mapX < movementX - 0.1) {
		mapX += 0.2 * delta;
	}
	
	if (mapZ < movementZ - 0.1) {
		mapZ += 0.2 * delta;
	}
	
	if (mapZ > movementZ + 0.1) {
		mapZ -= 0.2 * delta;
	}
}
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.
__________________
~~ Word Flurry ~~ App Store / Website / Facebook
Kalimba is offline   Reply With Quote
Old 09-22-2009, 09:07 PM   #11 (permalink)
Registered Member
 
Join Date: May 2009
Posts: 190
jeonghyunhan is on a distinguished road
Default

It's just [seudo code, and lastTime is set in the initWithFrame method.
I was going with smasher's advice on drawing then updating.
__________________
Blockle:http://www.youtube.com/watch?v=vxEKDkpAfRU
jeonghyunhan is offline   Reply With Quote
Old 09-22-2009, 09:12 PM   #12 (permalink)
Pro. Game Developer
iPhone Dev SDK Supporter
 
Join Date: Feb 2009
Location: żLa Islas Hermosas?
Posts: 2,176
Kalimba is on a distinguished road
Default

Quote:
Originally Posted by jeonghyunhan View Post
It's just [seudo code, and lastTime is set in the initWithFrame method.
Yeah, but 'lastTime' also needs to be set/updated every timer tick. It should get set to the value in 'time' once the delta is determined.

Quote:
Originally Posted by jeonghyunhan View Post
I was going with smasher's advice on drawing then updating.
I believe he meant that during the tick, draw first, then do the update. You still do both in the tick, but you do them in "reverse" order.
__________________
~~ Word Flurry ~~ App Store / Website / Facebook
Kalimba is offline   Reply With Quote
Old 09-23-2009, 01:53 AM   #13 (permalink)
Registered Member
 
Join Date: May 2009
Posts: 190
jeonghyunhan is on a distinguished road
Default

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...

EDIT:
This is what I have come up with:
Code:
- (void)gameLoop {
	
	CFTimeInterval time;
	time = CFAbsoluteTimeGetCurrent();
	float delta = (time - lastTime) * 30;
	lastTime = time;
	
	[self drawView];
	[self updateLogic:delta];
}
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.
Code:
- (void)updateLogic:(float)delta {
	
	if (mapX > movementX + 0.1) {
		mapX -= 0.2 * delta;
	}
	
	if (mapX < movementX - 0.1) {
		mapX += 0.2 * delta;
	}
	
	if (mapZ < movementZ - 0.1) {
		mapZ += 0.2 * delta;
	}
	
	if (mapZ > movementZ + 0.1) {
		mapZ -= 0.2 * 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.
__________________
Blockle:http://www.youtube.com/watch?v=vxEKDkpAfRU

Last edited by jeonghyunhan; 09-23-2009 at 02:08 AM.
jeonghyunhan is offline   Reply With Quote
Old 09-23-2009, 02:26 AM   #14 (permalink)
Pro. Game Developer
iPhone Dev SDK Supporter
 
Join Date: Feb 2009
Location: żLa Islas Hermosas?
Posts: 2,176
Kalimba is on a distinguished road
Default

Quote:
Originally Posted by jeonghyunhan View Post
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 View Post
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?
__________________
~~ Word Flurry ~~ App Store / Website / Facebook
Kalimba is offline   Reply With Quote
Old 09-23-2009, 03:09 AM   #15 (permalink)
Registered Member
 
Join Date: May 2009
Posts: 190
jeonghyunhan is on a distinguished road
Default

First, here's an update in my gameLoop:
Code:
- (void)gameLoop {
	
	CFTimeInterval time;
	time = CFAbsoluteTimeGetCurrent();
	float delta = (time - lastTime) * fps;
	
	[self updateLogic:delta];
	[self drawView];
	
	fpsCount += delta;
	if(fpsCount > 30.0f) {
		fpsCount = 0;
		fps = (1.0f / (time - lastTime));
	}
	
	lastTime = time;
}
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:
Code:
- (void)animatePlayerDown:(id)sender {
	
	startUpAnimation = YES;
	if (gameMapLayer4[playerZ - 1][playerX] == 0 ||
		gameMapLayer4[playerZ - 1][playerX] == 2 ||
		gameMapLayer4[playerZ - 1][playerX] == 3) {
		if (movementZClone == (movementZ + 1)) {
			y -= 1;
			movementZClone -= 1;
		}
		playerZ -= 1;
		movementZ -= 1;
	}
}


- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	
	UITouch *touch = [[event allTouches] anyObject];
	CGPoint location = [touch locationInView:self];
	
	if (location.x <= 120 && location.y <= 120) {
		
		analog.center = location;
	}
	if (CGRectContainsPoint(left.frame, location)) {
		
		movementTouch = YES;
		leftTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 6.0 target:self selector:@selector(animatePlayerLeft:) userInfo:nil repeats:YES];
	}
	if (CGRectContainsPoint(right.frame, location)) {
		
		movementTouch = YES;
		rightTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 6.0 target:self selector:@selector(animatePlayerRight:) userInfo:nil repeats:YES];
	}
	if (CGRectContainsPoint(up.frame, location)) {
		
		movementTouch = YES;
		//testText = NO;
		upTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 6.0 target:self selector:@selector(animatePlayerUp:) userInfo:nil repeats:YES];
	}
	if (CGRectContainsPoint(down.frame, location)) {
		
		movementTouch = YES;
		//testText = YES;
		downTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 / 6.0 target:self selector:@selector(animatePlayerDown:) userInfo:nil repeats:YES];
	}
}
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 =[.
__________________
Blockle:http://www.youtube.com/watch?v=vxEKDkpAfRU

Last edited by jeonghyunhan; 09-23-2009 at 08:40 AM.
jeonghyunhan is offline   Reply With Quote
Old 09-23-2009, 07:45 PM   #16 (permalink)
Registered Member
 
Join Date: May 2009
Posts: 190
jeonghyunhan is on a distinguished road
Default

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.
__________________
Blockle:http://www.youtube.com/watch?v=vxEKDkpAfRU
jeonghyunhan is offline   Reply With Quote
Old 09-23-2009, 08:17 PM   #17 (permalink)
Pro. Game Developer
iPhone Dev SDK Supporter
 
Join Date: Feb 2009
Location: żLa Islas Hermosas?
Posts: 2,176
Kalimba is on a distinguished road
Default

Quote:
Originally Posted by jeonghyunhan View Post
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?
__________________
~~ Word Flurry ~~ App Store / Website / Facebook
Kalimba is offline   Reply With Quote
Old 09-23-2009, 10:20 PM   #18 (permalink)
Registered Member
 
Join Date: May 2009
Posts: 190
jeonghyunhan is on a distinguished road
Default

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?
__________________
Blockle:http://www.youtube.com/watch?v=vxEKDkpAfRU
jeonghyunhan is offline   Reply With Quote
Old 09-24-2009, 09:13 AM   #19 (permalink)
Registered Member
 
Join Date: Nov 2008
Posts: 234
warmi is on a distinguished road
Default

Quote:
Originally Posted by jeonghyunhan View Post
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.
warmi is offline   Reply With Quote
Old 09-24-2009, 01:47 PM   #20 (permalink)
Registered Member
 
Join Date: May 2009
Posts: 190
jeonghyunhan is on a distinguished road
Default

Well, now I have managed to implement a Fixed interval time based game loop but now it is even more coarse and rough.
Code:
#define MAXIMUM_FRAME_RATE 60
#define MINIMUM_FRAME_RATE 30
#define UPDATE_INTERVAL (1.0 / MAXIMUM_FRAME_RATE)
#define MAX_CYCLES_PER_FRAME (MAXIMUM_FRAME_RATE / MINIMUM_FRAME_RATE)


- (void)gameLoop {
	
	NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
	float cyclesLeftOver;
	CFTimeInterval time = CFAbsoluteTimeGetCurrent();
	float delta = (time - lastTime) + cyclesLeftOver;
	
	if (delta > (MAX_CYCLES_PER_FRAME * UPDATE_INTERVAL)) {
		delta = (MAX_CYCLES_PER_FRAME * UPDATE_INTERVAL);
	}
	
	while (delta > UPDATE_INTERVAL) {
		delta -= UPDATE_INTERVAL;
		
		[self updateLogic:delta];
	}
	
	cyclesLeftOver = delta;
	lastTime = time;
	
	[self drawView];
	
	[pool release];
}
__________________
Blockle:http://www.youtube.com/watch?v=vxEKDkpAfRU
jeonghyunhan is offline   Reply With Quote
Old 02-17-2010, 04:58 PM   #21 (permalink)
Registered Member
 
Join Date: Feb 2010
Posts: 4
Panajev is on a distinguished road
Default

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.

Considerations I had while writing this code:
1.) Wanted frame-rate independent animation (followed this already posted link for inspiration... http://www.sacredsoftware.net/tutori...nimation.xhtml).

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];
}
Code:
#define MAX_FPS (30.0)
#define MIN_FPS (MAX_FPS/2.0)
#define FRAME_TIME (1.0 / MAX_FPS)
#define MAX_CPF (MAX_FPS / MIN_FPS)

#define aEPS (0.0001f)

Last edited by Panajev; 02-17-2010 at 04:59 PM. Reason: Edit
Panajev is offline   Reply With Quote
Old 02-17-2010, 05:24 PM   #22 (permalink)
Obj-C Learner
 
Join Date: Apr 2009
Location: Manchester, UK
Posts: 1,030
ZunePod is on a distinguished road
Send a message via MSN to ZunePod Send a message via Yahoo to ZunePod
Default

I've had 100FPS, but that's in the simulator.
ZunePod is offline   Reply With Quote
Old 02-18-2010, 04:37 AM   #23 (permalink)
Registered Member
 
Join Date: Feb 2010
Posts: 4
Panajev is on a distinguished road
Default

Minor change to the runLoop:

Code:
-(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;
	//float d_time = 0.0f;
	static float dt_drop = 0.0f;
	
	float dropAnimRate = (2.5f/25.0f); //10 FPS, 1 frame = 0.1 s = 100 ms;
	
	CFTimeInterval current_time = CACurrentMediaTime();
	float dt = current_time - last_time + cycles_left_over;
	
	[self drawScene];
	
	if (dt > (MAX_CPF * FRAME_TIME)) {
		dt = (MAX_CPF * FRAME_TIME); 
		//MAX_CPF = (MAX_FPS/MIN_FPS); FRAME_TIME = (1.0f / MAX_FPS); dt <= (1.0f/ MIN_FPS);
	}
	//d_time = dt;
	dt_drop += dt;
	while (dt > FRAME_TIME) { 
		dt -= FRAME_TIME;
		while (dt_drop > (dropAnimRate - aEPS)){ 
			//I do not want the animation of the droplet to run either faster than dropAnimRate or slower than that.
			[self updateLogic];
			dt_drop = 0.0f;
		}
	}
	
	cycles_left_over = dt;
	last_time = current_time;
	
	[gamePool release];
}

Last edited by Panajev; 02-18-2010 at 05:28 AM.
Panajev is offline   Reply With Quote
Reply

Bookmarks

Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On



» Advertisements
» Online Users: 401
7 members and 394 guests
13dario13, ChrisYates, fredidf, iOS.Lover, Leslie80, Wikiboo, Yosh_K
Most users ever online was 1,387, 04-10-2012 at 04:21 AM.
» Stats
Members: 175,670
Threads: 94,121
Posts: 402,903
Top Poster: BrianSlick (7,990)
Welcome to our newest member, Yosh_K
Powered by vBadvanced CMPS v3.1.0

All times are GMT -5. The time now is 04:39 AM.
Powered by vBulletin® Version 3.8.0
Copyright ©2000 - 2012, Jelsoft Enterprises Ltd.
Search Engine Friendly URLs by vBSEO 3.3.0