Chipmunk - simple example

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

The forum is locked. These are the original blitzbasic.com forums, kept so they can still be read. No new topics, replies or edits can be made here. To join in, head over to the Blitz3D+ forums.

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)