Collisions

Official forum for the Chipmunk2D Physics Library.
Post Reply
Q309185
Posts: 2
Joined: Wed Jul 30, 2008 3:35 pm
Contact:

Collisions

Post by Q309185 »

I just started working with Chipmunk a day or two ago, and I'm trying to set up a simple program to figure out how things work. The program is supposed to have a little square that bounces around inside of a box. Right now, the square falls straight through the box.

I'm writing the code in C++ on a Linux machine.

Here's the source code:

Code: Select all

using namespace std;
#ifdef __APPLE__
	#include "OpenGL/gl.h"
	#include "OpenGL/glu.h"
	#include <GLUT/glut.h>
#else
	#include <GL/gl.h>
	#include <GL/glext.h>
	#include <GL/glu.h>
	#include <GL/glut.h>
#endif

#include "chipmunk/chipmunk.h"
#include <cmath>
#include <iostream>
#include <vector>

static cpSpace* space;
static cpBody* staticBody;
static vector<cpShape*> shapes;
static vector<cpBody*> bodies;

void drawCircle(cpFloat x, cpFloat y, cpFloat r, cpFloat a)
{
	const int segs = 15;
	const cpFloat coef = 2.0*M_PI/(cpFloat)segs;
	
	int n;
	glBegin(GL_POLYGON); {
		for(n = 0; n < segs; n++){
			cpFloat rads = n*coef;
			glVertex2f(r*cos(rads + a) + x, r*sin(rads + a) + y);
		}
		glVertex2f(x,y);
	} glEnd();
}

void drawCircleShape(cpShape *shape)
{
	cpBody *body = shape->body;
	cpCircleShape *circle = (cpCircleShape *)shape;
	cpVect c = cpvadd(body->p, cpvrotate(circle->c, body->rot));
	drawCircle(c.x, c.y, circle->r, body->a);
}

void drawSegmentShape(cpShape *shape)
{
	cpBody *body = shape->body;
	cpSegmentShape *seg = (cpSegmentShape *)shape;
	cpVect a = cpvadd(body->p, cpvrotate(seg->a, body->rot));
	cpVect b = cpvadd(body->p, cpvrotate(seg->b, body->rot));
	
	glBegin(GL_LINES); {
		glVertex2f(a.x, a.y);
		glVertex2f(b.x, b.y);
	} glEnd();
}

void drawPolyShape(cpShape *shape)
{
	cpBody *body = shape->body;
	cpPolyShape *poly = (cpPolyShape *)shape;
	
	int num = poly->numVerts;
	cpVect *verts = poly->verts;
	
	int i;
	glBegin(GL_POLYGON);
	for(i=0; i<num; i++){
		cpVect v = cpvadd(body->p, cpvrotate(verts[i], body->rot));
		glVertex2f(v.x, v.y);
	} glEnd();
}

void drawObject(void *ptr, void *unused)
{
	cpShape *shape = (cpShape*)ptr;
	switch(shape->type){
		case CP_CIRCLE_SHAPE:
			drawCircleShape(shape);
			break;
		case CP_SEGMENT_SHAPE:
			drawSegmentShape(shape);
			break;
		case CP_POLY_SHAPE:
			drawPolyShape(shape);
			break;
		default:
			printf("Bad enumeration in drawObject().\n");
	}
}

void display(void)
{
	int i;
	
	glClear(GL_COLOR_BUFFER_BIT);
	glLoadIdentity();
	glColor3f(1.0, 1.0, 1.0);
	
	cpSpaceHashEach(space->activeShapes, &drawObject, NULL);
	cpSpaceHashEach(space->staticShapes, &drawObject, NULL);
	
	glutSwapBuffers();
	float dt = .001f;
	int intervals = 10;
	for ( int a = 0; a < intervals; a++ ) {
		for ( int b = 0; b < bodies.size(); b++ ) {
			cpBodyResetForces( bodies[b] );
		}
		cpSpaceStep( space, dt / intervals );
	}
	glutPostRedisplay();
}

void addBoundingBox() {
	//infinite mass, infinite moment of inertia
	staticBody = cpBodyNew( INFINITY, INFINITY );
	
	cpVect p1 = cpv(10,10), p2 = cpv(90,10), p3 = cpv(90,90), p4 = cpv(10,90);
	
	cpShape *seg1, *seg2, *seg3, *seg4;
	seg1 = cpSegmentShapeNew( staticBody, p1, p2, 1 );
	seg2 = cpSegmentShapeNew( staticBody, p2, p3, 1 );
	seg3 = cpSegmentShapeNew( staticBody, p3, p4, 1 );
	seg4 = cpSegmentShapeNew( staticBody, p4, p1, 1 );
	
	//bodies.push_back( staticBody );
	shapes.push_back( seg1 );
	shapes.push_back( seg2 );
	shapes.push_back( seg3 );
	shapes.push_back( seg4 );
	
	//friction
	seg1->u = 1;
	seg2->u = 1;
	seg3->u = 1;
	seg4->u = 1;
	
	//elasticity
	seg1->e = .95f;
	seg2->e = .95f;
	seg3->e = .95f;
	seg4->e = .95f;
	
	cpSpaceAddStaticShape( space, seg1 );
	cpSpaceAddStaticShape( space, seg2 );
	cpSpaceAddStaticShape( space, seg3 );
	cpSpaceAddStaticShape( space, seg4 );
}

void addPolygon( float x, float y, int sides=4, float radius=.1f, float rotation=.0001f, float mass = 1, float friction=1, float elasticity=.95f ) {
	//mass, moment of inertia
	cpBody* polygon = cpBodyNew( mass, 1 ); 
	
	cpVect points[sides];
	for ( int a = 0; a < sides; a++ ) {
		float angle = rotation + a * 2 * M_PI / sides;
		float px = x + radius * cos( -angle ); 
		float py = y + radius * sin( -angle );
		points[a] = cpv(px, py);
		//cout << px << ", " << py << "." << endl;
	}
	
	cpShape *segments[sides];
	for ( int a = 0; a < sides; a++ ) {
		segments[a] = cpSegmentShapeNew( polygon, points[a], points[(a+1)%sides], 0 );
		segments[a]->u = friction;
		segments[a]->e = elasticity;
		
		cpSpaceAddShape( space, segments[a] );
		shapes.push_back( segments[a] );
	}
	cpSpaceAddBody( space, polygon );
	bodies.push_back( polygon );
	
	//moment of inertia stuff
	cpFloat moment = cpMomentForPoly( mass, sides, points, cpvzero );
	cpBodySetMoment( polygon, moment );
}

int collide( cpShape* s1, cpShape* s2, cpContact* contact, int a, cpFloat f, void* data ) {
	cout << "Collision!!!" << endl;
	return 1;
}

void initObjects() {
	space = cpSpaceNew();
	space->gravity = cpv( 0.f, -100.f);
    cpSpaceResizeStaticHash(space, 50.f, 10);
    cpSpaceResizeActiveHash(space, 50.f, 100);
	
	addBoundingBox();
	addPolygon( 50.f, 100.f, 4, 5.f );
	//addPolygon( 60.f, 100.f, 4, 5.f );
	cpSpaceSetDefaultCollisionPairFunc(space, &collide, NULL);
}

void glInit() {
	glClearColor(0,0,0,1);
	glPointSize( 1 );
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho( 0, 100, 0, 100, -1, 1 );
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glColor3f( 0, 0, 0 );
}

void glutInit(int argc, char** argv) {
	glutInit( &argc, argv );
	glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);
	glutInitWindowSize( 500, 500 );
	glutCreateWindow("Chipmunk Experiment");
	glutDisplayFunc( display );
}

int main(int argc, char** argv) {
	cpInitChipmunk();
	//main window
	glutInit( argc, argv );
	//gl stuff
	glInit();
	//objects in world
	initObjects();
	
	glutMainLoop();
	return 0;
}
What am I doing wrong?
viblo
Posts: 206
Joined: Tue Aug 21, 2007 3:12 pm
Contact:

Re: Collisions

Post by viblo »

I havent looked closley at your code, but try to reverse the order of the vertices in the polygon, if they are in the wrong (counter? clockwise order) it wont work and its a common error, at least for me :)
http://www.pymunk.org - A python library built on top of Chipmunk to let you easily get cool 2d physics in your python game/app
Michael Buckley
Posts: 46
Joined: Tue Aug 21, 2007 10:30 am
Contact:

Re: Collisions

Post by Michael Buckley »

There are a couple of things going on here. The first is that, as stated in the documentation, line segments do not generate collisions with other line segments. They only generate collisions with circles and polygons. Since your little square is supposed to be a polygon, you should create a cpPolyShape instead of a cpSegmentShape.

Second, at least in older versions of the library, I would occasionally have problems with static shapes if I did not call cpSpaceRehashStatic(space); after adding or removing a static shape. You can do this once at the end of all your additions and removals for a frame.

Finally, make sure that all your vertices are specified in counter-clockwise order. This doesn't matter for line segments, so it doesn't come into play now, but for your bounding box, p1, p2, p3 and p4 were specified in clockwise order. They would be in counter-clockwise order if Chipmunk specified 0, 0 as the bottom left, like OpenGL does, rather than the top right.
Q309185
Posts: 2
Joined: Wed Jul 30, 2008 3:35 pm
Contact:

Re: Collisions

Post by Q309185 »

Yeah, I switched over to using a polygon instead of a series of line segments and now it works great! Thanks!

But something weird is going on with clockwise/counterclockwise ordering. Whenever I use counterclockwise order, the square bounces once at the bottom of the screen, then falls through. Whenever I use clockwise order (like I had it), it works fine. This is the exact opposite of my intuition, the documentation, and what you just told me. So what's up?

Also, I've noticed something strange, but possibly correct: when the square stops bouncing, it will keep leaning back and forth from side to side seemingly indefinitely. Shouldn't gravity or friction or something make it stop eventually?
Michael Buckley
Posts: 46
Joined: Tue Aug 21, 2007 10:30 am
Contact:

Re: Collisions

Post by Michael Buckley »

Hmm, I've been doing everything counter-clockwise and have been fine. Can you post the code you're using to make the polygon?

As for the square jittering, there are a number of things that can cause that. The first is high elasticity, though that should eventually stop bouncing it. The second is not using enough iterations on your space. Try increasing the iterations and see if that helps out. The third could be an odd center of gravity. if it's a box, all the vertices should be equally far from the center. It's probably also a good idea to make a square with faces in the cardinal directions (up, down, left and right) and then rotate it, rather than specifying vertices of an already rotated polygon. The last are the cp_collision_slop and the cp_bias_coef global variables. Tweaking these can help. For one game, I had to make the cp_bias_coef = 0.75 for things to work correct.y
User avatar
tartley
Posts: 37
Joined: Thu Jun 12, 2008 5:01 pm
Location: London, England
Contact:

Re: Collisions

Post by tartley »

The docs and your intuition are correct that the API requires counterclockwise winding, but under the assumption that your Y-axis points downwards. If (like me) your Y-axis points upwards, then what was counterclockwise is now clockwise.

I'm very new to all this, so I could be mistaken, but this is as I understand it.
[color=#808080]Tartley - Jonathan Hartley, [url]http://tartley.com[/url]
Using Pymunk (Chipmunk's Python bindings) for a game project:
[url]http://code.google.com/p/sole-scion[/url][/color]
Michael Buckley
Posts: 46
Joined: Tue Aug 21, 2007 10:30 am
Contact:

Re: Collisions

Post by Michael Buckley »

Yeah, as I mentioned in one of my posts, Chipmunk's y-axis points downwards.
Post Reply

Who is online

Users browsing this forum: No registered users and 3 guests