Spazzing when force is too big?

Official forum for the Chipmunk2D Physics Library.
Post Reply
Stefan
Posts: 4
Joined: Tue Mar 31, 2009 3:56 pm
Contact:

Spazzing when force is too big?

Post by Stefan »

I'm trying to create a catapult-like object, but I have hit a problem that I can't solve.

I essentially have a long stick jointed to a large stand. At one end of the stick I jointed a heavy weight so that the stick gets turned upwards very quickly. Sounds simple enough, here are my two problems:

1. For this to work, the weight has to be much havier than the long stick. I did this by changing it's mass to 5 times that of the stick. When I start this setup, everything happens as planned and the stick moves up quickly - but the stick is spazzing out (e.g. moving violently around the joint).
I guess the reason for this is that the force applied to the joint is too big (?). What is the correct way to do this?

2. Once something touches the weight, the weight keeps on slowly rotating at a constant speed and seems to be completely ignoring gravity. This might indicate what I have done incorrectly (?).

Anyways, here is the code:

Code: Select all

	//global parameters
	float all_e = 0.1f;
	float all_u = 1.0f;
	float all_w = 1.0f;
	float all_m = 1.0f; // the first problem can be somewhat changed by the moment, but it still persists. also it's not much of a catapult if the arm moves slowly. :)

	int vertnumarm = 4;
	cpVect vertsarm[] = {
		cpv(-175,-10),
		cpv(-175, 10),
		cpv( 175, 10),
		cpv( 175,-10),
	};
	
	int vertnumstand = 4;
	cpVect vertsstand[] = {
		cpv(-125,-225),
		cpv(-15, 125),
		cpv( 15, 125),
		cpv( 125,-225),
	};
	
	int vertnumweight = 3;
	cpVect vertsweight[] = {
		cpv(-50,-100),
		cpv(  0, 0),
		cpv( 50,-100),
	};

	cpShape *shape;
	
	//create the weight
	cpBody  *stand;	
	stand = cpBodyNew(all_w, cpMomentForPoly(all_m, vertnumstand, vertsstand, cpvzero));
	stand->p = cpvzero;
	cpSpaceAddBody(space, stand);

	shape = cpPolyShapeNew(stand, vertnumstand, vertsstand, cpv(0,0));
	shape->e = all_e; shape->u = all_u;
	stand->cpBodySetMass
	shape->data = standgameobj;
	shape->collision_type = 9000;//this type does not collide with itself
	cpSpaceAddShape(space, shape);
	
	
	//create the arm (aka long stick)
	cpVect armoffset = cpv (-120,80);
	cpBody  *arm;
	arm = cpBodyNew(all_w, cpMomentForPoly(all_m, vertnumarm, vertsarm, cpvzero));
	arm->p = armoffset;
	cpSpaceAddBody(space, arm);
	
	shape = cpPolyShapeNew(arm, vertnumarm, vertsarm, cpvzero);
	shape->e = all_e; shape->u = all_u;
	shape->data = armgameobj;
	shape->collision_type = 9000;
	cpSpaceAddShape(space, shape);
	
	
	//create the weight
	cpVect weightoffset = cpv(50,armoffset.y);
	cpBody  *weight;
	weight = cpBodyNew(8.0f, cpMomentForPoly(all_m, vertnumweight, vertsweight, cpvzero));//notice the 8.0f! this is supposed to be heavy!
	weight->p = weightoffset;
	cpSpaceAddBody(space, weight);
	
	shape = cpPolyShapeNew(weight, vertnumweight, vertsweight, cpvzero);
	shape->e = all_e; shape->u = all_u;
	shape->data = weightgameobj;
	shape->collision_type = 9000;
	cpSpaceAddShape(space, shape);
	

	//join everything - Just ignore the offsets, they might be a little confusing without context. ;)
	cpJoint *joint1 = cpPinJointNew(stand, arm, cpv(0,armoffset.y), cpv(-armoffset.x,0));
	cpSpaceAddJoint(space, joint1);
	cpJoint *joint2 = cpPinJointNew(arm, weight, cpv(weightoffset.x-armoffset.x,0), cpv(0,0));//<- This is the problematic one
	cpSpaceAddJoint(space, joint2);
Any help is greatly appreciated! Have a nice day. :)
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Spazzing when force is too big?

Post by slembcke »

You are right that it is because of the large forces involved on a lightweight object. Chipmunk doesn't necessarily calculate exact forces when lots of objects collide or are piled on top of each other. Doing so is extremely expensive, so like many physics engines it approximates the forces over a number of iterations considering each pair of objects individually. Each iteration makes the solution a bit more accurate.

A similar thing happens when you put a very heavy object on top of a very light object. The lightweight box on the bottom is pushed upwards by the ground by the amount it is pushing down with. (the ground is infinitely heavy so it can push as hard as it needs to) Then the collision between the light box and heavy box is processed, but the because the weight ratio favors the heavy box the solver ends transfers most of the force into the light box and only a little into the heavy box. After enough iterations the heavy box will be pushed up by small amounts enough times that it will have almost completely stopped moving downwards. (or at least enough that nobody will notice) If there were too few iterations, the boxes will look as though they are smushing together or the lightweight box might jitter wildly. That is basically the same thing that is happening to you. You have a lightweight stick that is trying to satisfy two very large forces, and it takes more computation to figure out how to do it.

Increasing the number of iterations used by the space should help, but will also increase the CPU requirements. If you can't increase the iterations enough and still get acceptable performance, you may need to get creative. Make it animate like a catapult, but don't simulate it like one.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
Stefan
Posts: 4
Joined: Tue Mar 31, 2009 3:56 pm
Contact:

Re: Spazzing when force is too big?

Post by Stefan »

Rising the iterations to 90 really fixed the problem for good. But the FPS penalty is obviously severe with a lot of other objects around.

Is there a way to only increase the iterations on one object? The catapult is the only object with the spazzing-problem. - It is also the only joint in the space, if that helps.

[Edit]
Another Idea - can I access the roation of an object directly? Then I could manually edit the roation of the catapult arm. Is that what you ment by "animate"? Or did you mean a static, prerendered animation?
ker
Posts: 56
Joined: Tue Jul 15, 2008 4:13 am
Contact:

Re: Spazzing when force is too big?

Post by ker »

I think he meant exactly what you are trying to do w/ set rotation.

use the function void cpBodySetAngle(cpBody *body, cpFloat a); to set the angle.

you can also set body->w for angularVelocity or body->t for torque (angular speedup). This makes sense if your arm has infinite inertia (the torque won't work probably, but the angularVelocity will).
Using the angularVelocity allows you to set the speed once instead of rotating the stick manually.
Stefan
Posts: 4
Joined: Tue Mar 31, 2009 3:56 pm
Contact:

Re: Spazzing when force is too big?

Post by Stefan »

Works perfectly and is way easier to code & control than what I intentionally planned. I actually got creative. ;)

Chipmunk is great. You two as well. Thanks. :D


For those who randomly bumped into this thread: Problem two (no gravity influence on rotation) was solved by setting better pointers. Check out example7 - the "bridges" there use something similar.
User avatar
slembcke
Site Admin
Posts: 4166
Joined: Tue Aug 14, 2007 7:13 pm
Contact:

Re: Spazzing when force is too big?

Post by slembcke »

Unfortunately you can't set iteration for specific objects. It's a little more complicated than that in the general case when collisions are involved so it wouldn't always work very well.

Though it sounds like you are on track now. It sounds lame to have to concede such things, but the reality is that AAA games do it too. As long as the distinction between how it works in real life and how it's implemented is similar enough nobody really notices.
Can't sleep... Chipmunks will eat me...
Check out our latest projects! -> http://howlingmoonsoftware.com/wordpress/
Post Reply

Who is online

Users browsing this forum: No registered users and 7 guests