n00b question about fixed timestep in Chipmunk

Official forum for the Chipmunk2D Physics Library.
shoggoth
Posts: 4
Joined: Sat Aug 13, 2011 6:56 am
Contact:

n00b question about fixed timestep in Chipmunk

Post by shoggoth »

Hi there

I'm just starting to use Chipmunk and it looks great, nice work :)

Possibly missing something obvious here but other physics engines that I've used that prefer a fixed timestep take a call like step() with no parameters. I Notice that Chipmunk requires a parameter for its step such as step(1/60.0).

Is there an optimal value that I can pass as a parameter here? I've decoupled from the frame rate so I can tune the step to the physics engine. I'm currently stepping at 50Hz. How does Chipmunk know that the timestep is fixed? Does it compare to the previous value?

Thanks!
gnasen
Posts: 24
Joined: Wed Mar 16, 2011 12:17 pm
Contact:

Re: n00b question about fixed timestep in Chipmunk

Post by gnasen »

If you use a fixed framerate like 30fps, you could pass 1/30 to chipmunk, because it makes sense to use the "standard physic values" . you could also pass any other value, but it may be much more difficult to do your calculations.
It is possible to use a dynamic timestep, but in this case your simulation is much more unstable.

so chipmunk doesnt know anything about your timings. Its just you to take care of it!
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: n00b question about fixed timestep in Chipmunk

Post by slembcke »

Chipmunk 6 does store the most recent timestep, you can get it using cpSpaceGetCurrentTimeStep() if you want. It's useful inside callbacks and such if you aren't using a strict fixed timestep. It uses this to attempt to retune the simulation if you use a dynamic timestep as well, but it's still recommended to avoid it.

The reason why Chipmunk recommends using a fixed timestep is because it caches the physics solution from the previous frame and uses that as the initial guess for the solution on the current frame instead of starting from 0. This allows the physics to be higher quality using less CPU. When you change the timestep each frame, the cached solution doesn't work as well and you will either have a less stable simulation or need to use more iterations (and CPU time) to make it stable.

By passing the timestep in each frame, it allows you to use a semi-dynamic timestep fairly easily when you want to do something like bullet time. Normally you'd be passing in something like 1/60 (or whatever your fixed timestep is), but when the game slows down you could pass in speedFactor/60.0 instead.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
shoggoth
Posts: 4
Joined: Sat Aug 13, 2011 6:56 am
Contact:

Re: n00b question about fixed timestep in Chipmunk

Post by shoggoth »

Thanks both for your replies, I understand now.
jcmeyer5
Posts: 89
Joined: Thu Dec 15, 2011 9:18 am
Contact:

Re: n00b question about fixed timestep in Chipmunk

Post by jcmeyer5 »

Okay, I am necro-ing this thread.

Up until today I have just updated physics in the game loop. I decided to go ahead and implement a separate scheduled method to update physics on a fixed 1/60 step. Now my shape and my sprite are out of sync... meaning the shape is leading the sprite when moving (all directions). It is slight, but definitely noticeable when debugDraw is on. If I leave the step in the main loop, the shape and the sprite sync perfectly. Both simulator and device.

Any ideas?
Chipmunk Pro and cocos2D 2.x branch for iOS development
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: n00b question about fixed timestep in Chipmunk

Post by slembcke »

Sounds like you are copying the transform to the sprite before updating the physics. Could you post some code?

Usually you do it something like this:

Code: Select all

update(){
  while(needs_fixed_update){
    fixed_update()
  }
  
  // do your regular update sort of things
}
Maybe work in some interpolation or extrapolation too.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
jcmeyer5
Posts: 89
Joined: Thu Dec 15, 2011 9:18 am
Contact:

Re: n00b question about fixed timestep in Chipmunk

Post by jcmeyer5 »

Sure. I will say I tend to use Angry Chipmunks as a reference, and I thought I had adopted the physics update methodology there.

Here is the physics update. This is in my gameLayer.

Code: Select all

// scheduling of physics update ONLY
-(void)step:(ccTime)dt {
	[space step:FIXED_TIMESTEP];
}
Here is my loop update. This loop calls the update method that updates sprite position to body:

Code: Select all

// game update loop
-(void)update:(ccTime)dt {
	for (Object* object in self.objArray) {
		[object updateStateWithDeltaTime:dt];
	}
}
In the Player class, I have the updateStateWithDeltaTime: method:

Code: Select all

-(void)updateStateWithDeltaTime:(ccTime)dt {
	
	jumpTimer += dt;
	pushTimer += dt;

	self.objPos = body.pos;
	self.objNode.position = body.pos;
	self.objNode.rotation = CC_RADIANS_TO_DEGREES(-body.angle);
	
	if (grounded) { 
		if (jumpButton.active) {
			[self changeState:kStateJump];
		} else if ((rightButton.active) && (!leftButton.active) && (!jumpButton.active)){
			[self changeState:kStateRunR];
		} else if ((!rightButton.active) && (leftButton.active) && (!jumpButton.active)){
			[self changeState:kStateRunL];
		} else {
			[self changeState:kStateIdle];
		}
	} else if (!grounded) {
		if ((jumpButton.active) && (jumpTimer <= 0.16)){
			[self changeState:kStateJump];
		} else if (rightButton.active) {
			[self changeState:kStatePushR];
		} else if (leftButton.active) {
			[self changeState:kStatePushL];
		} else {
			[self changeState:kStateFalling];
		}
	}
}
My changeState: method:

Code: Select all

-(void)changeState:(ObjectState)newState {
	[self setObjState:newState];
	
	switch (newState) {
		case kStateIdle:
			CCLOG(@"kStateIdle");
			[foot setSurfaceVel:cpvzero];
			if (![self.objNode.curAnimation.name isEqualToString:@"idle"]) {
				[self.objNode runAnimation:@"idle" atSpeed:1.0];
			}
			break;
			
		case kStateRunL:
			CCLOG(@"kStateRunL");
			[foot setSurfaceVel:cpv(-300,0)];
			[self.objNode setScaleX:-1.0 ];
			if (![self.objNode.curAnimation.name isEqualToString:@"runWalk"]) {
				[self.objNode runAnimation:@"runWalk" atSpeed:fabsf(foot.surfaceVel.x/150)];
			}
			break;
			
		case kStateRunR:
			CCLOG(@"kStateRunR");
			[foot setSurfaceVel:cpv(300,0)];
			[self.objNode setScaleX:1.0];
			if (![self.objNode.curAnimation.name isEqualToString:@"runWalk"]) {
				[self.objNode runAnimation:@"runWalk" atSpeed:fabsf(foot.surfaceVel.x/150)];
			}
			break;
			
		case kStateJump:
			CCLOG(@"kStateJump");
			[body applyImpulse:cpv(0,1000) offset:cpvzero];
			if (![self.objNode.curAnimation.name isEqualToString:@"jump"]) {
				[self.objNode runAnimation:@"jump" atSpeed:1.0];
			}
			break;
			
		case kStatePushL:
			CCLOG(@"kStatePushL");
			[self.objNode setScaleX:-1.0];
			if (body.vel.x >= -300.0) {
				[body applyImpulse:cpv(-150,0) offset:cpvzero];
			}
			if (body.vel.y <= 0) {
				if (![self.objNode.curAnimation.name isEqualToString:@"idle"]) {
					[self.objNode runAnimation:@"idle" atSpeed:1.0];
				}
			} else if (![self.objNode.curAnimation.name isEqualToString:@"jump"]) {
				[self.objNode runAnimation:@"jump" atSpeed:1.0];
			}
			break;
			
		case kStatePushR:
			CCLOG(@"kStatePushR");
			[self.objNode setScaleX:1.0];
			if (body.vel.x <= 300.0) {
				[body applyImpulse:cpv(150,0) offset:cpvzero];
			}
			if (body.vel.y <= 0) {
				if (![self.objNode.curAnimation.name isEqualToString:@"idle"]) {
					[self.objNode runAnimation:@"idle" atSpeed:1.0];
				}
			} else if (![self.objNode.curAnimation.name isEqualToString:@"jump"]) {
				[self.objNode runAnimation:@"jump" atSpeed:1.0];
			}
			break;
			
		case kStateFalling:
			CCLOG(@"kStateFalling");
			if (body.vel.y <= 0) {
				if (![self.objNode.curAnimation.name isEqualToString:@"idle"]) {
					[self.objNode runAnimation:@"idle" atSpeed:1.0];
				}
			} else if (![self.objNode.curAnimation.name isEqualToString:@"jump"]) {
				[self.objNode runAnimation:@"jump" atSpeed:1.0];
			}
			break;
			
		default:
			
			break;
	}
}
Chipmunk Pro and cocos2D 2.x branch for iOS development
jcmeyer5
Posts: 89
Joined: Thu Dec 15, 2011 9:18 am
Contact:

Re: n00b question about fixed timestep in Chipmunk

Post by jcmeyer5 »

Okay, so I see a difference with Angry Chipmunks and my chicken scratch. Angry Chipmunks is (through the ChipmunkCocosBody class) using the update function attached to the body. I didnt do that. I just set sprite location = body location in the update. Heck, I dont even think Angry Chipmunks used the update function (schedule step for physics, but not the ccnode built in update).

EDIT: DUH! You just built and scheduled your own update method. I did the same, but I was still running the original as well (so two update loops, update: and step:. So I just took the [space step:FIXED_STEP] and stuck it in the main update: loop. But I feel like I am just back where I started...
Chipmunk Pro and cocos2D 2.x branch for iOS development
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: n00b question about fixed timestep in Chipmunk

Post by slembcke »

So do you still have an issue or not? I'm not sure if I follow.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
jcmeyer5
Posts: 89
Joined: Thu Dec 15, 2011 9:18 am
Contact:

Re: n00b question about fixed timestep in Chipmunk

Post by jcmeyer5 »

No, I think I am good now. Thanks for letting me confuse you.
Chipmunk Pro and cocos2D 2.x branch for iOS development
Post Reply

Who is online

Users browsing this forum: No registered users and 12 guests