Chipmunk - simple example

BlitzMax Modules Forums/Brucey's Modules/Chipmunk - simple example

Hey, i'm having a hard time coping with this, The examples are a bit hard to understand, and the documentation is a little blunt.

Could someone show me how to make a simple cube in space and let it drop to the floor?

Also, i see vec2 used alot, what is this?

Okay, here's something reasonably small...

SuperStrict

Framework BaH.Chipmunk
Import BRL.GLMax2D
?win32
Import BRL.D3D7Max2D
?

' Initialize the physics engine
InitChipmunk()

' create a static body
Local staticBody:CPBody = New CPBody.Create(INFINITY, INFINITY)
	
ResetShapeIdCounter()

' setup the space for the simulation to run in
Local space:CPSpace = New CPSpace.Create()
space.ResizeStaticHash(20.0, 999)
space.SetGravity(Vec2(0, 100))

' create a static segment (line)
Local shape:CPShape = New CPSegmentShape.Create(staticBody, Vec2(0,479), Vec2(640,479), 0)
shape.SetElasticity(1.0)
shape.SetFriction(1.0)
space.AddStaticShape(shape)


Local verts:CPVect[] = [ ..
	Vec2(-15,-15), ..
	Vec2(-15, 15), ..
	Vec2( 15, 15), ..
	Vec2( 15,-15)]

' Create our box body, slighty rotated to make things more exciting
Local body:CPBody = New CPBody.Create(1.0, MomentForPoly(1.0, verts, Vec2(0,0)))
body.SetPosition(Vec2(300, 20))
body.SetAngle(44)
space.AddBody(body)

' Create our box shape.
shape = New CPPolyShape.Create(body, verts, Vec2(0,0))
shape.SetElasticity(0.6)
shape.SetFriction(0.3)
space.AddShape(shape)



Local dt:Float = 1.0/60.0

'
' Create the graphics context and run the main loop
Graphics 640, 480, 0

SetColor(255, 255, 255)

While Not KeyDown(KEY_ESCAPE)

	Cls
	
	' draw shapes...
	space.GetActiveShapes().ForEach(drawObject)
	space.GetStaticShapes().ForEach(drawObject)
	
	' run a simulation step
	space.DoStep(dt)
	
	Flip

Wend

End

' The draw callback
Function drawObject(shape:Object, data:Object)

	If CPPolyShape(shape) Then
		drawPolyShape(CPPolyShape(shape))
	ElseIf CPSegmentShape(shape) Then
		drawSegmentShape(CPSegmentShape(shape))
	End If
	
End Function

' Draw a segment (line)
Function drawSegmentShape(shape:CPSegmentShape)

	SetRotation 0

	Local body:CPBody = shape.GetBody()
	Local pos:CPVect = body.GetPosition()

	Local a:CPVect = pos.Add(shape.GetEndPointA().Rotate(body.GetRot()))
	Local b:CPVect = pos.Add(shape.GetEndPointB().Rotate(body.GetRot()))
	
	DrawLine a.x, a.y, b.x, b.y

End Function

' Draw a poly
Function drawPolyShape(shape:CPPolyShape)

	Local body:CPBody = shape.GetBody()
	Local pos:CPVect = body.GetPosition()

	Local verts:CPVect[] = shape.GetVerts()
	Local First:CPVect
	Local last:CPVect
	
	For Local i:Int = 0 Until verts.length
		Local v:CPVect = pos.Add(verts[i].Rotate(body.GetRot()))
		
		If Not First Then
			First = v
		End If
		
		If last Then
			DrawLine last.x, last.y, v.x, v.y
		End If
		
		last = v
	Next
	
	DrawLine last.x, last.y, First.x, First.y

End Function


Vec2() is a convenience function to create a 2D vector (x, y), used for things like location, velocity, etc.

Interesting "explosion" effect
SuperStrict

Framework BaH.Chipmunk
Import BRL.GLMax2D
Import bah.random
?win32
Import BRL.D3D7Max2D
?

' Initialize the physics engine
InitChipmunk()

' create a static body
Local staticBody:CPBody = New CPBody.Create(INFINITY, INFINITY)
	
ResetShapeIdCounter()

' setup the space for the simulation to run in
Local space:CPSpace = New CPSpace.Create()
space.ResizeStaticHash(20.0, 999)
space.SetGravity(Vec2(0, 100))

' create a static segment (line)
Local shape:CPShape = New CPSegmentShape.Create(staticBody, Vec2(0,479), Vec2(640,479), 0)
shape.SetElasticity(1.0)
shape.SetFriction(1.0)
space.AddStaticShape(shape)


Local verts:CPVect[] = [ ..
	Vec2(-15,-15), ..
	Vec2(-15, 15), ..
	Vec2( 15, 15), ..
	Vec2( 15,-15)]

For Local i:Int = 0 To 400
' Create our box body, slighty rotated to make things more exciting
Local body:CPBody = New CPBody.Create(1.0, MomentForPoly(1.0, verts, Vec2(0,0)))
body.SetPosition(Vec2(Rnd(20,500), Rnd(20,500)))
body.SetAngle(44)
space.AddBody(body)

' Create our box shape.
shape = New CPPolyShape.Create(body, verts, Vec2(0,0))
shape.SetElasticity(0.6)
shape.SetFriction(0.3)
space.AddShape(shape)
Next


Local dt:Float = 1.0/60.0

'
' Create the graphics context and run the main loop
Graphics 640, 480, 0

SetColor(255, 255, 255)

While Not KeyDown(KEY_ESCAPE)

	Cls
	
	' draw shapes...
	space.GetActiveShapes().ForEach(drawObject)
	space.GetStaticShapes().ForEach(drawObject)
	
	' run a simulation step
	space.DoStep(dt)
	
	Flip

Wend

End

' The draw callback
Function drawObject(shape:Object, data:Object)

	If CPPolyShape(shape) Then
		drawPolyShape(CPPolyShape(shape))
	ElseIf CPSegmentShape(shape) Then
		drawSegmentShape(CPSegmentShape(shape))
	End If
	
End Function

' Draw a segment (line)
Function drawSegmentShape(shape:CPSegmentShape)

	SetRotation 0

	Local body:CPBody = shape.GetBody()
	Local pos:CPVect = body.GetPosition()

	Local a:CPVect = pos.Add(shape.GetEndPointA().Rotate(body.GetRot()))
	Local b:CPVect = pos.Add(shape.GetEndPointB().Rotate(body.GetRot()))
	
	DrawLine a.x, a.y, b.x, b.y

End Function

' Draw a poly
Function drawPolyShape(shape:CPPolyShape)

	Local body:CPBody = shape.GetBody()
	Local pos:CPVect = body.GetPosition()

	Local verts:CPVect[] = shape.GetVerts()
	Local First:CPVect
	Local last:CPVect
	
	For Local i:Int = 0 Until verts.length
		Local v:CPVect = pos.Add(verts[i].Rotate(body.GetRot()))
		
		If Not First Then
			First = v
		End If
		
		If last Then
			DrawLine last.x, last.y, v.x, v.y
		End If
		
		last = v
	Next
	
	DrawLine last.x, last.y, First.x, First.y

End Function


Here's the single box converted to 4...
SuperStrict

Framework BaH.Chipmunk
Import BRL.GLMax2D
?win32
Import BRL.D3D7Max2D
?

' Initialize the physics engine
InitChipmunk()

' create a static body
Local staticBody:CPBody = New CPBody.Create(INFINITY, INFINITY)
	
ResetShapeIdCounter()

' setup the space for the simulation to run in
Local space:CPSpace = New CPSpace.Create()
space.ResizeStaticHash(20.0, 999)
space.SetGravity(Vec2(0, 100))

' create a static segment (line)
Local shape:CPShape = New CPSegmentShape.Create(staticBody, Vec2(0,479), Vec2(640,479), 0)
shape.SetElasticity(1.0)
shape.SetFriction(1.0)
space.AddStaticShape(shape)


Local verts:CPVect[] = [ ..
	Vec2(-8,-8), ..
	Vec2(-8, 8), ..
	Vec2( 8, 8), ..
	Vec2( 8,-8)]
	
' the positions of for boxes
Local positions:CPVect[] = [ ..
	Vec2(300, 20), ..
	Vec2(300, -2), ..
	Vec2(310, 10), ..
	Vec2(289, 10)]

For Local i:Int = 0 Until positions.length
	
	' Create our box body, slighty rotated to make things more exciting
	Local body:CPBody = New CPBody.Create(1.0, MomentForPoly(1.0, verts, Vec2(0,0)))
	body.SetPosition(positions[i])
	body.SetAngle(45)
	space.AddBody(body)
	
	' Create our box shape.
	shape = New CPPolyShape.Create(body, verts, Vec2(0,0))
	shape.SetElasticity(0.6)
	shape.SetFriction(0.3)
	space.AddShape(shape)
Next


Local dt:Float = 1.0/60.0

'
' Create the graphics context and run the main loop
Graphics 640, 480, 0

SetColor(255, 255, 255)

While Not KeyDown(KEY_ESCAPE)

	Cls
	
	' draw shapes...
	space.GetActiveShapes().ForEach(drawObject)
	space.GetStaticShapes().ForEach(drawObject)
	
	' run a simulation step
	space.DoStep(dt)
	
	Flip

Wend

End

' The draw callback
Function drawObject(shape:Object, data:Object)

	If CPPolyShape(shape) Then
		drawPolyShape(CPPolyShape(shape))
	ElseIf CPSegmentShape(shape) Then
		drawSegmentShape(CPSegmentShape(shape))
	End If
	
End Function

' Draw a segment (line)
Function drawSegmentShape(shape:CPSegmentShape)

	SetRotation 0

	Local body:CPBody = shape.GetBody()
	Local pos:CPVect = body.GetPosition()

	Local a:CPVect = pos.Add(shape.GetEndPointA().Rotate(body.GetRot()))
	Local b:CPVect = pos.Add(shape.GetEndPointB().Rotate(body.GetRot()))
	
	DrawLine a.x, a.y, b.x, b.y

End Function

' Draw a poly
Function drawPolyShape(shape:CPPolyShape)

	Local body:CPBody = shape.GetBody()
	Local pos:CPVect = body.GetPosition()

	Local verts:CPVect[] = shape.GetVerts()
	Local First:CPVect
	Local last:CPVect
	
	For Local i:Int = 0 Until verts.length
		Local v:CPVect = pos.Add(verts[i].Rotate(body.GetRot()))
		
		If Not First Then
			First = v
		End If
		
		If last Then
			DrawLine last.x, last.y, v.x, v.y
		End If
		
		last = v
	Next
	
	DrawLine last.x, last.y, First.x, First.y

End Function


Thanks, alot more documented so i understand what the calls are for, brucey, if you could, add one of these to the examples with the module

right two questions-

i knocked this up with a basic understanding on how chipmunk works, (use the arrow keys to move the box)

SuperStrict

Import Bah.chipmunk

AppTitle = "Untitled Physics Project"

Graphics 800,600

InitChipmunk()

Global staticBody:CPBody = New CPBody.Create(INFINITY, INFINITY)

ResetShapeIdCounter()

Global space:CPSpace = New CPSpace.Create()
	space.ResizeStaticHash(20.0, 999)
	space.SetGravity(Vec2(0, 100))
	

Global box1:CPBody = Box(Vec2(400,300),50,0,20,20,True)



MakeWalls()



Local dt:Float = 1.0/60.0

While Not AppTerminate()
Cls
	
	'update everything
	space.GetActiveShapes().ForEach(drawObject)
	space.GetStaticShapes().ForEach(drawObject)
	space.DoStep(dt)
	CheckInput()

Flip
Wend
End


'makes a box
Function Box:CPBody(p:CPVect, a:Float, w:Float,WIDTH:Int,HEIGHT:Int,r:Int = False)

	Global verts:CPVect[] = [ ..
		Vec2(-WIDTH/2,-HEIGHT/2.0), ..
		Vec2(-WIDTH/2, HEIGHT/2.0), ..
		Vec2( WIDTH/2, HEIGHT/2.0), ..
		Vec2( WIDTH/2,-HEIGHT/2.0) ]
	Rem	
	Global verts:CPVect[] = [ ..
		Vec2( -WIDTH/2,-HEIGHT/2), ..
		Vec2( WIDTH/2, -HEIGHT/2), ..
		Vec2( -WIDTH/2, HEIGHT/2), ..
		Vec2( WIDTH/2, HEIGHT/2) ]
	End Rem
	Local body:CPBody = New CPBody.Create(1.0, MomentForPoly(1.0, verts, CPVZero))
	body.SetPosition(p)
	body.SetAngle(a)
	body.SetAngularVelocity(w)
	space.AddBody(body)
	
	Local shape:CPShape = New CPPolyShape.Create(body, verts, CPVZero)
	shape.SetElasticity(0.6)
	shape.SetFriction(0.3)
	space.AddShape(shape)
	
	If r = True Return body
End Function

' The draw callback
Function drawObject(shape:Object, data:Object)

	If CPPolyShape(shape) Then
		drawPolyShape(CPPolyShape(shape))
	ElseIf CPSegmentShape(shape) Then
		drawSegmentShape(CPSegmentShape(shape))
	End If
	
End Function

' Draw a segment (line)
Function drawSegmentShape(shape:CPSegmentShape)

	SetRotation 0

	Local body:CPBody = shape.GetBody()
	Local pos:CPVect = body.GetPosition()

	Local a:CPVect = pos.Add(shape.GetEndPointA().Rotate(body.GetRot()))
	Local b:CPVect = pos.Add(shape.GetEndPointB().Rotate(body.GetRot()))
	
	DrawLine a.x, a.y, b.x, b.y

End Function

' Draw a poly
Function drawPolyShape(shape:CPPolyShape)

	Local body:CPBody = shape.GetBody()
	Local pos:CPVect = body.GetPosition()

	Local verts:CPVect[] = shape.GetVerts()
	Local First:CPVect
	Local last:CPVect
	
	For Local i:Int = 0 Until verts.length
		Local v:CPVect = pos.Add(verts[i].Rotate(body.GetRot()))
		
		If Not First Then
			First = v
		End If
		
		If last Then
			DrawLine last.x, last.y, v.x, v.y
		End If
		
		last = v
	Next
	
	DrawLine last.x, last.y, First.x, First.y

End Function


'make the walls
Function Makewalls()
	' create a static segment (line)
	Local shape:CPShape = New CPSegmentShape.Create(staticBody, Vec2(0,599), Vec2(800,599), 0)
	shape.SetElasticity(1.0)
	shape.SetFriction(1.0)
	space.AddStaticShape(shape)
	' create a static segment (line)
	shape = New CPSegmentShape.Create(staticBody, Vec2(0,599), Vec2(0,0), 0)
	shape.SetElasticity(1.0)
	shape.SetFriction(1.0)
	space.AddStaticShape(shape)
	' create a static segment (line)
	shape = New CPSegmentShape.Create(staticBody, Vec2(800,599), Vec2(800,0), 0)
	shape.SetElasticity(1.0)
	shape.SetFriction(1.0)
	space.AddStaticShape(shape)
	' create a static segment (line)
	shape = New CPSegmentShape.Create(staticBody, Vec2(0,0), Vec2(800,0), 0)
	shape.SetElasticity(1.0)
	shape.SetFriction(1.0)
	space.AddStaticShape(shape)
End Function

'Check for user input
Function CheckInput()
	If KeyHit(KEY_RIGHT) box1.applyimpulse(Vec2(200,0),Vec2(200,0))
	If KeyHit(KEY_LEFT) box1.applyimpulse(Vec2(-200,0),Vec2(-200,0))
	If KeyHit(KEY_UP) box1.applyimpulse(Vec2(0,-200),Vec2(0,-200))
	If KeyHit(KEY_DOWN) box1.applyimpulse(Vec2(0,200),Vec2(0,200))
End Function


1) if you push the box fast enough it passes through the lines, any ways to prevent this?
2) Can anyone knock something up involving images? I cant get my head around it, how would you make a image have physics properties, as right now i'm messing with white lines

1) That's called tunnelling.
Basically, the simulation runs in time segements, and, if an object happens to be moving fast enough so that between two steps it could completely pass through another object, the simulation could miss that collision altogether.
There are 2 ways you can use to avoid this.
A) Decrease the time-step size so that in effect, the simulation moves more slowly, and therefore is more likely to catch the contact of a fast moving object.
B) Use Continuous Collision Detection. This is more expensive processing wise, but guarantees collisions won't be missed.

Chipmunk doesn't do CCD, but you can apply A with something like the following to your example above:
' number of calculation steps per visual frame
Local steps:Float = 4

Local dt:Float = 1.0/60.0/steps

While Not AppTerminate()
Cls
	
	'update everything
	space.GetActiveShapes().ForEach(drawObject)
	space.GetStaticShapes().ForEach(drawObject)
	' process the steps
	For Local i:Int = 0 Until steps
		space.DoStep(dt)
	Next
	CheckInput()

Flip
Wend

If you know objects have a limited maximum velocity, you can apply this method without too much of a performance hit.

Box2D does CCD, but I've not finished the wrap yet.

Demo2 does images, btw :-)

If you look at main2.bmx, at the drawPolyShape() and drawCircleShape() functions, you'll see it does something like this:
	Local body:CPBody = shape.GetBody()
	Local pos:CPVect = body.GetPosition()


	SetRotation body.GetAngle()
	DrawImage crate, pos.x, pos.y

I believe that the body "position" is the midpoint of the body, which makes using images a bit easier - eg. AutoMidHandle().

Of course, if your body is more complex than a square, (perhaps made up of several different shapes), then your image should match that shape.
As you can see from the code, it's not too difficult.

I see that now, i thought the graphics were chipmunk's internaly, not Blitz shapes!

new question, i'm trying to make a chain function, bugging my thus far, I need to figure out what direction the chain is going (i'm betting on CPVect.angle), to calculate the next position of a link based on the position of the last one..

this is what i have so far:

'makes a circle
Function Circle:CPBody(p:CPVect,d:Float,r:Int = False)

	Local radius:Float = d/2
	Local body:CPBody = New CPBody.Create(10.0, MomentForCircle(10.0, 0.0, radius, Vec2(0,0)))
	body.SetPosition(p)
	space.AddBody(body)
	
	Local shape:CPShape = New CPCircleShape.Create(body, radius, Vec2(0,0))
	shape.SetElasticity(0)
	shape.SetFriction(0.1)
	space.AddShape(shape)

	If r=True Return body
End Function

'makes a chain from point A to point B
Function Chain(a:CPVect,b:CPVect)
	Local body1:CPBody
	Local body2:CPBody
	Local joint:CPPivotJoint
	Local links:Int = a.length / 12
	Local direction:CPVect = a.angle	
	
	For Local i:Int = 1 To links / 2
		'MY HEAD HURTS
		body1 = Circle(a.Add(Vec2(a.angle'????
		body2 = Circle(a.Add(Vec2(a.angle'????	
		joint =	
	Next
	
End Function


Hey guys, I couldnt figure out how to calculate the advances dirction in pixels for the chain links, so i just settled on horizontal chains.

I must say, i'm impressed with Chipmunk, but the only major problem it gives me is when you try to stack elastic ships, (they cant hold still) other then that, i'm amazed at how fast it actually is


If anyone is interested, here is the little physics sandbox source-

SuperStrict

Import Bah.chipmunk
'types
'---
'---
'---





'FUNCTIONS
'---
'---
'---

'makes a box
Function Box:CPBody(p:CPVect, a:Float, w:Float,WIDTH:Int,HEIGHT:Int,r:Int = False)

	Local verts:CPVect[] = [ ..
		Vec2(-WIDTH/2,-HEIGHT/2.0), ..
		Vec2(-WIDTH/2, HEIGHT/2.0), ..
		Vec2( WIDTH/2, HEIGHT/2.0), ..
		Vec2( WIDTH/2,-HEIGHT/2.0) ]
		
		
	Local body:CPBody = New CPBody.Create(1.0, MomentForPoly(1.0, verts, CPVZero))
	body.SetPosition(p)
	body.SetAngle(a)
	body.SetAngularVelocity(w)
	space.AddBody(body)
	
	Local shape:CPShape = New CPPolyShape.Create(body, verts, CPVZero)
	shape.SetElasticity(0)
	shape.SetFriction(0.5)
	space.AddShape(shape)
	
	If r = True Return body
End Function

'makes a circle
Function Circle:CPBody(p:CPVect,d:Float,r:Int = False,m:Float = 1)

	Local radius:Float = d/2
	Local body:CPBody = New CPBody.Create(m, MomentForCircle(10.0, 0.0, radius, Vec2(0,0)))
	body.SetPosition(p)
	space.AddBody(body)
	
	Local shape:CPShape = New CPCircleShape.Create(body, radius, Vec2(0,0))
	shape.SetElasticity(0)
	shape.SetFriction(0.1)
	space.AddShape(shape)

	If r=True Return body
End Function

'makes a chain with a specified amount of diameter 10 circles
Function Chain(p:CPVect,length:Int,a_a:Int = False,a_b:Int = False)
	Local body1:CPBody
	Local body2:CPBody
	Local joint:CPPivotJoint
	Local body1pos:CPVect
	Local body2pos:CPVect
	Local px:Float = p.GetX()
	Local py:Float = p.Gety()

	
	For Local i:Int = 1 To length
	

		body1 = Circle(Vec2( (px-((length/2)*12)-12) + (i * 12), py),10,True)
		body1pos = body1.GetPosition()
		If body2 <> Null
			joint = New CPPivotJoint.Create(body1, body2, Vec2( (body1pos.x + body2pos.x)/2, py ) )
			space.AddJoint(joint)
		End If
			
		
		body2 = Circle(Vec2(body1pos.GetX() + 12, py),10,True)
		body2pos = body2.GetPosition()
		joint = New CPPivotJoint.Create(body1, body2, Vec2( (body1pos.x + body2pos.x)/2, py ) )
		space.AddJoint(joint)
		
	Next
	
End Function

' The draw callback
Function drawObject(shape:Object, data:Object)

	If CPPolyShape(shape) Then
		drawPolyShape(CPPolyShape(shape))
	ElseIf CPSegmentShape(shape) Then
		drawSegmentShape(CPSegmentShape(shape))
	ElseIf CPCircleShape(shape) Then
		drawCircleShape(CPCircleShape(shape))
	End If
	
End Function

' Draw a segment (line)
Function drawSegmentShape(shape:CPSegmentShape)

	SetRotation 0

	Local body:CPBody = shape.GetBody()
	Local pos:CPVect = body.GetPosition()

	Local a:CPVect = pos.Add(shape.GetEndPointA().Rotate(body.GetRot()))
	Local b:CPVect = pos.Add(shape.GetEndPointB().Rotate(body.GetRot()))
	
	DrawLine a.x, a.y, b.x, b.y

End Function

' Draw a poly
Function drawPolyShape(shape:CPPolyShape)

	Local body:CPBody = shape.GetBody()
	Local pos:CPVect = body.GetPosition()

	Local verts:CPVect[] = shape.GetVerts()
	Local First:CPVect
	Local last:CPVect
	
	For Local i:Int = 0 Until verts.length
		Local v:CPVect = pos.Add(verts[i].Rotate(body.GetRot()))
		
		If Not First Then
			First = v
		End If
		
		If last Then
			DrawLine last.x, last.y, v.x, v.y
		End If
		
		last = v
	Next
	
	DrawLine last.x, last.y, First.x, First.y

End Function

Function drawCircleShape(shape:CPCircleShape)
	Local body:CPBody = shape.GetBody()
	
	Local center:CPVect = shape.GetTransformedCenter()
	Local radius:Float = shape.GetRadius()
	
	DrawOval center.x - radius, center.y - radius, radius*2, radius*2
End Function


'make the walls
Function Makewalls()
	' create a static segment (line)
	Local shape:CPShape = New CPSegmentShape.Create(staticBody, Vec2(0,599), Vec2(800,599), 0)
	shape.SetElasticity(0)
	shape.SetFriction(1.0)
	space.AddStaticShape(shape)
	' create a static segment (line)
	shape = New CPSegmentShape.Create(staticBody, Vec2(0,599), Vec2(0,0), 0)
	shape.SetElasticity(0)
	shape.SetFriction(1.0)
	space.AddStaticShape(shape)
	' create a static segment (line)
	shape = New CPSegmentShape.Create(staticBody, Vec2(800,599), Vec2(800,0), 0)
	shape.SetElasticity(0)
	shape.SetFriction(1.0)
	space.AddStaticShape(shape)
	' create a static segment (line)
	shape = New CPSegmentShape.Create(staticBody, Vec2(0,0), Vec2(800,0), 0)
	shape.SetElasticity(0)
	shape.SetFriction(1.0)
	space.AddStaticShape(shape)
	
	shape = New CPSegmentShape.Create(staticBody, Vec2(200,200), Vec2(600,200), 0)
	shape.SetElasticity(0)
	shape.SetFriction(1.0)
	space.AddStaticShape(shape)
	shape = New CPSegmentShape.Create(staticBody, Vec2(500,200), Vec2(200,50), 0)
	shape.SetElasticity(0)
	shape.SetFriction(1.0)
	space.AddStaticShape(shape)

	Local seasaw:CPBody = Box(Vec2(400,400),0,0,200,2,True)
	Local joint:CPPivotJoint = New CPPivotJoint.Create(seasaw, staticBody, seasaw.GetPosition() )
	space.AddJoint(joint)

End Function

'Check for user input
Function CheckInput()
	If KeyDown(KEY_RIGHT) box1.applyimpulse(Vec2(50,0),Vec2(50,0))
	If KeyDown(KEY_LEFT) box1.applyimpulse(Vec2(-50,0),Vec2(-50,0))
	If KeyDown(KEY_UP) box1.applyimpulse(Vec2(0,-50),Vec2(0,-50))
	If KeyDown(KEY_DOWN) box1.applyimpulse(Vec2(0,50),Vec2(0,50))
	
	If KeyHit(KEY_P) play = Not play
	
	If KeyHit(KEY_1) Circle(Vec2(MouseX(),MouseY()),20)
	If KeyHit(KEY_2) Box(Vec2(MouseX(),MouseY()),0,0,20,20)
	If KeyHit(KEY_3) Box(Vec2(MouseX(),MouseY()),0,0,150,5)
	If KeyHit(KEY_4) Chain(Vec2(MouseX(),MouseY()),16)
	
End Function

AppTitle = "Untitled Physics Project"

Graphics 800,600

InitChipmunk()

Global staticBody:CPBody = New CPBody.Create(INFINITY, INFINITY)

ResetShapeIdCounter()

Global space:CPSpace = New CPSpace.Create()
	space.ResizeStaticHash(150, 999)
	space.ResizeActiveHash(150, 999)
	space.SetGravity(Vec2(0, 1000))
	

Global box1:CPBody = Circle(Vec2(400,300),50,True,5)

MakeWalls()

Global play:Int = False

'fps stuff
Local FPS_TICK:Int
Local FPS:Int
Local FPS_TIMER:Int

'physics logic timing
Local steps:Float = 3
Local dt:Float = 1.0/60.0/steps

While Not AppTerminate()
Cls
	
	'update everything
	space.GetActiveShapes().ForEach(drawObject)
	space.GetStaticShapes().ForEach(drawObject)
	If play=True
		space.DoStep(dt)
	End If
	CheckInput()
	
	'Get FPS
	If MilliSecs() > FPS_TIMER+1000
		FPS = FPS_TICK
		FPS_TIMER = MilliSecs()
		FPS_TICK = 0
	End If
	FPS_TICK:+1
	
	SetColor 70,153,255
	DrawText "FPS: "+FPS,10,60
	DrawText "Controls:",10,0
	DrawText "[1] - Circle | [2] - Box | [3] - Plank | [4] - Chain",10,20
	DrawText "[Arrow Keys] - Move ball | [P] Pause/Play simulation",10,40
	If play=False
		DrawText "Paused",740,10
	Else
		DrawText "Playing",740,10
	End If
	SetColor 255,255,255
Flip
Wend
End


instructions will be printed at the top, but incase you cant read them:

[1]-[4] makes shapes
[>][<][^][v] (arrow/cursor keys) move the player circle
[P] pauses and plays the simulation, (allowing you to place objects then start)