JV-ODE: Break my tables!

Blitz3D Forums/Blitz3D Userlibs/JV-ODE: Break my tables!

Hi All,

Just beginning with ODE and here a experiment with breakable tables (yes, based on code you guys did before, so nothing new). I'm curious to know if you guys know any other ways to 'get bodies to relax' and auto disable themselves.

In the demo you can see when you've got lots of objects stacked on top of each other they keep bouncing around amongst each other. Lowering angular&linear thresholds can only go so far untill bodies come to rest in an unrealistic pose...

cheers,
Danny
p.s. How do you post a small box with code in it? unlike this big chunk:
Include "JV-ODE.bb"

; DANNY's Broken Table Test

Const ANGTHRESH# = 0.1		;default auto disable angular threshold
Const LINTHRESH# = 0.1		;default auto disable linear threshold
Const STEPTHRESH = 1

Graphics3D 800,600,0,2

Type odeGeom
	Field body
	Field geom
	Field mesh
	Field lastForce#
End Type

; ###################################################################################################
; ### Setup ODE

Global World=dWorldCreate()
Global Space=dHashSpaceCreate(0)
Global ContactGroup=dJointGroupCreate(0)

dWorldSetGravity(World,0,-0.48,0)
dWorldSetERP World, 0.25

dContactSetMu(40)

SeedRnd 666

Global camera, camerapivot
Create3D()

;add some random tables
r#=1
addTable -3,2,3, 2,1,2
addTable  3,2,3, 2,1,2
addTable -3,2,-3, 2,1,2
addTable  3,2,-3, 2,1,2
addTable  0,3,0, 2,1,2

; ###################################################################################################
;sfx = Load3DSound("bin\woodimpact02.wav")
;Global break = Load3DSound("bin\Door.wav")
;CreateListener camera

goSim = False

fps = 0
frames = 0
ftime = MilliSecs()+1000

While Not KeyHit(1)

	;make dizzy
	TurnEntity camerapivot, 0, 0.1, 0

	;ENTER = more boxes
	If KeyDown(28) Then AddObject(Rand(-r,r),Rand(-r,r))

	;SPACE = more tables
	If KeyHit(57) Then AddTable(Rand(-r,r),Rand(3,6),Rand(-r,r),2,1,2)

	If goSim Then	
		;add random boxes every couple ms
		If MilliSecs()-BoxTimer>50
			numbox=numbox+1
			;limit amount of boxes
			If numbox < 50 Then
				r# =4
				AddObject(Rand(-r,r),Rand(-r,r))
			EndIf
			BoxTimer=MilliSecs()
		End If

		;-
		PTime=MilliSecs()
		dSpaceCollide(Space,World,ContactGroup)
		dWorldQuickStep(World,0.1)
		dJointGroupEmpty(ContactGroup)	
		PhysicsTime#=MilliSecs()-PTime

		;check for breakage
		JointLimits(1.5)

	EndIf

	UpdateGeoms()

	UpdateWorld
	RenderWorld

	;fps check
	If MilliSecs() >=ftime Then
		goSim = True ;delay simulation with a second
		fps=frames
		frames=0
		ftime=MilliSecs()+999
	Else
		frames=frames+1
	EndIf

	;debug
	Color 250,250,250
	Text 5,0,"JV-ODE Version "+dGetVersion()
	Text 5,15,"Physics Time:"+PhysicsTime
	Text 5,30,"FPS: "+FPS
	Text GraphicsWidth()/2,50,"GREEN objects are ENABLED/ACTIVE - RED objects are DISABLED", 1
	Text GraphicsWidth()/2,65,"Press ENTER for more boxes", 1
	Text GraphicsWidth()/2,80,"Press SPACEBAR to add a Breakable Table!", 1

	;show
	Flip 1

Wend

dJointGroupDestroy(ContactGroup)
dSpaceDestroy(Space)
dWorldDestroy(World)
dCloseODE()

End

; ###################################################################################################

Function Create3D()

;| Default 3d scene

	; ### Create light
	
	Light=CreateLight()
	
	RotateEntity Light,45,-90,0
	LightColor Light,255,255,255
	AmbientLight 130,130,130
	
	; ### Create camera
	camerapivot = CreatePivot()
	Camera=CreateCamera(camerapivot)
	CameraClsColor Camera,0,0,0
	CameraRange Camera,0.01,250
	PositionEntity Camera,-5,7,-7
	PositionEntity camerapivot, 0,1,0
	PointEntity camera, camerapivot
	;make top text readable
	CameraFogColor camera, 0,0,0
	CameraFogRange camera, 5,30
	CameraFogMode camera, 1

	; ### Create plane
	dCreatePlane(Space,0,1,0,0)
	Plane=CreatePlane()
	EntityAlpha Plane,0.95
	PlaneTexture=CreateTexture(128,128,9)
	ClsColor 220,210,200
	Cls
	Color 150,120,110
	Rect 0,0,64,64,1
	Rect 64,64,64,64,1
	CopyRect 0,0,128,128,0,0,BackBuffer(),TextureBuffer(PlaneTexture)
	ScaleTexture PlaneTexture,5,5
	EntityTexture Plane,PlaneTexture,0,0
	Mirror=CreateMirror()
	Color 255,255,255

End Function

; ###################################################################################################

Function AddObject(xp#=666,zp#=666)

	size# = Rnd#(0.25,0.65)
	range# = 0.5

	If xp=666 Then xp=Rand(-range#,range#)
	yp=Rand(7,15)
	If zp=666 Then zp=Rand(-range#,range#)

	ode.ODEGeom=New ODEGeom

	ode\body=dBodyCreate(World)
	dBodySetRotation(ode\body,0,0,0)
	dBodySetPosition(ode\body,xp,yp,zp)
	dBodySetAutoDisableFlag(ode\body,1)

	dBodySetAutoDisableLinearThreshold ode\body, LINTHRESH
	dBodySetAutoDisableAngularThreshold ode\body, ANGTHRESH
	dBodySetAutoDisableSteps ode\body, STEPTHRESH

	ode\geom=dCreateBox(Space,size#,size#,size#)
	dGeomSetBody(ode\geom,ode\body)

	ode\mesh=CreateCube()
	ScaleMesh ode\mesh,size#/2,size#/2,size#/2
	EntityColor ode\mesh,Rand(255),Rand(255),Rand(255)
	EntityAlpha ode\mesh,1
	EntityShininess ode\mesh,0.7

	mass = dMassCreate()
	dMassSetBoxTotal mass, 25.0, size#,size#,size#
	dBodySetMass ode\body, mass
	dMassDestroy mass

End Function

; ###################################################################################################

Function AddTable(xp#, yp#, zp#, w#,h#,d#)

;# Creates a table with 4 legs - breakable legs! :)

	w# = Rnd(w#*0.5,w#*1.5)		;add some variation to the table's dimensions
	h# = Rnd(h#*0.5,h#*1.5)
	d# = Rnd(d#*0.5,d#*1.5)

	;table top dimensions
	th# = h# * 0.1

	;leg dimensions
	lw# = w#*0.1
	lh# = h#*0.9
	ld# = d#*0.1

	;create tabletop
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#, yp#, zp#
	dBodySetRotation ode\body, 0,0,0
	dBodySetAutoDisableFlag ode\body, 1
	dBodySetAutoDisableLinearThreshold ode\body, LINTHRESH
	dBodySetAutoDisableAngularThreshold ode\body, ANGTHRESH
	dBodySetAutoDisableSteps ode\body, STEPTHRESH

	ode\geom=dCreateBox(space,w#,th#,d#)
	dGeomSetBody ode\geom, ode\body	

	ode\mesh=CreateCube()
	EntityColor ode\mesh, 100,50,0
	ScaleMesh ode\mesh, w#/2,th#/2,d#/2
	tableBody = ode\body

;	yp# = yp# - 0.01 ;-> create small gap between table top & legs

	;create leg 1
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#-w#/2+lw#/2, yp#-lh#/2-th#/2, zp#-d#/2+ld#/2
	dBodySetRotation ode\body, 0,0,0
	dBodySetAutoDisableFlag ode\body, 1
	dBodySetAutoDisableLinearThreshold ode\body, LINTHRESH
	dBodySetAutoDisableAngularThreshold ode\body, ANGTHRESH
	dBodySetAutoDisableSteps ode\body, STEPTHRESH

	ode\geom=dCreateBox(space,lw#,lh#,ld#)
	dGeomSetBody ode\geom, ode\body	

	ode\mesh=CreateCube()
	EntityColor ode\mesh, 200,100,0
	ScaleMesh ode\mesh, lw#/2,lh#/2,ld#/2

	;join the legs to the table
	joint = dJointCreateHinge(world,0)
	dJointAttach joint, tableBody, ode\body
	dJointSetHingeAxis joint, -1,0,0
	dJointSetHingeAnchor joint, xp#-w#/2+lw#/2, yp#-th#/2, zp#-d#/2+ld#/2
	dJointSetHingeParam joint, dParamLoStop,  0
	dJointSetHingeParam joint, dParamHiStop,  0

	;create leg 2
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#+w#/2-lw#/2, yp#-lh#/2-th#/2, zp#-d#/2+ld#/2
	dBodySetRotation ode\body, 0,0,0
	dBodySetAutoDisableFlag ode\body, 1
	dBodySetAutoDisableLinearThreshold ode\body, LINTHRESH
	dBodySetAutoDisableAngularThreshold ode\body, ANGTHRESH
	dBodySetAutoDisableSteps ode\body, STEPTHRESH

	ode\geom=dCreateBox(space,lw#,lh#,ld#)
	dGeomSetBody ode\geom, ode\body	

	ode\mesh=CreateCube()
	EntityColor ode\mesh, 200,100,0
	ScaleMesh ode\mesh, lw#/2,lh#/2,ld#/2

	;join the legs to the table
	joint = dJointCreateHinge(world,0)
	dJointAttach joint, tableBody, ode\body
	dJointSetHingeAxis joint, -1,0,0
	dJointSetHingeAnchor joint, xp#+w#/2-lw#/2, yp#-th#/2, zp#-d#/2+ld#/2
	dJointSetHingeParam joint, dParamLoStop, -0.0
	dJointSetHingeParam joint, dParamHiStop,  0.0

	;create leg 3
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#+w#/2-lw#/2, yp#-lh#/2-th#/2, zp#+d#/2-ld#/2
	dBodySetRotation ode\body, 0,0,0
	dBodySetAutoDisableFlag ode\body, 1
	dBodySetAutoDisableLinearThreshold ode\body, LINTHRESH
	dBodySetAutoDisableAngularThreshold ode\body, ANGTHRESH
	dBodySetAutoDisableSteps ode\body, STEPTHRESH

	ode\geom=dCreateBox(space,lw#,lh#,ld#)
	dGeomSetBody ode\geom, ode\body	

	ode\mesh=CreateCube()
	EntityColor ode\mesh, 200,100,0
	ScaleMesh ode\mesh, lw#/2,lh#/2,ld#/2

	;join the legs to the table
	joint = dJointCreateHinge(world,0)
	dJointAttach joint, tableBody, ode\body
	dJointSetHingeAxis joint, -1,0,0
	dJointSetHingeAnchor joint, xp#+w#/2-lw#/2, yp#-th#/2, zp#+d#/2-ld#/2
	dJointSetHingeParam joint, dParamLoStop, -0.0
	dJointSetHingeParam joint, dParamHiStop,  0.0

	;create leg 4
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#-w#/2+lw#/2, yp#-lh#/2-th#/2, zp#+d#/2-ld#/2
	dBodySetRotation ode\body, 0,0,0
	dBodySetAutoDisableFlag ode\body, 1
	dBodySetAutoDisableLinearThreshold ode\body, LINTHRESH
	dBodySetAutoDisableAngularThreshold ode\body, ANGTHRESH
	dBodySetAutoDisableSteps ode\body, STEPTHRESH

	ode\geom=dCreateBox(space,lw#,lh#,ld#)
	dGeomSetBody ode\geom, ode\body	

	ode\mesh=CreateCube()
	EntityColor ode\mesh, 200,100,0
	ScaleMesh ode\mesh, lw#/2,lh#/2,ld#/2

	;join the legs to the table
	joint = dJointCreateHinge(world,0)
	dJointAttach joint, tableBody, ode\body
	dJointSetHingeAxis joint, -1,0,0
	dJointSetHingeAnchor joint, xp#-w#/2+lw#/2, yp#-th#/2, zp#+d#/2-ld#/2
	dJointSetHingeParam joint, dParamLoStop, -0.0
	dJointSetHingeParam joint, dParamHiStop,  0.0

End Function


; ###################################################################################################

Function UpdateGeoms()

	For ode.ODEGeom=Each ODEGeom
		If dBodyIsEnabled(ode\body)
			RotateEntity ode\mesh,dGeomGetPitch#(ode\geom),dGeomGetYaw#(ode\geom),dGeomGetRoll#(ode\geom)
			PositionEntity ode\mesh,dGeomGetPositionX#(ode\geom),dGeomGetPositionY#(ode\geom),dGeomGetPositionZ#(ode\geom)
			EntityColor ode\mesh, 0,255,0
		Else
			EntityColor ode\mesh, 255,0,0		
		End If

		;remove if object falls off the world
		If dGeomGetPositionY#(ode\geom) < -100 Then
			DebugLog "body "+Handle(ode)+" deleted"
			dGeomDestroy ode\geom
			dBodyDestroy ode\body
			FreeEntity ode\mesh
			Delete ode
		EndIf
	Next

End Function

; ###################################################################################################

Function JointLimits(limit)

For ode.ODEGeom=Each ODEGeom
	If dGeomIsEnabled(ode\geom)
		;If body=ode\body  ; specific body parts only
			numjoints=dBodyGetNumJoints(ode\body)
			If numjoints>0 
				For joints=0 To numjoints-1
					joint=dBodyGetJoint(ode\body,joints)
						If joint<>0 ; valid joints only
							If dJointGetType(joint)<>dJointTypeContact
								; Get linear velocity vector
						  		ax#=dBodyGetLinearVelX#(ode\body)
						  		ay#=dBodyGetLinearVelY#(ode\body)
							    az#=dBodyGetLinearVelZ#(ode\body)
							
								; Get Angular velocity vector
						  		bx#=dBodyGetAngularVelX#(ode\body)
						  		by#=dBodyGetAngularVelY#(ode\body)
								bz#=dBodyGetAngularVelZ#(ode\body)
								
						  		; Calculate magnitudes
								ForceA#=Sqr(ax*ax+ay*ay+az*az)
								ForceB#=Sqr(bx*bx+by*by+bz*bz)
								
								; Check for sudden deceleration 
								If Abs((ode\LastForce#-forceA#))>limit Then
									;dJointAttach(joint,0,0)
									dJointDestroy joint
;									EmitSound break, ode\mesh
								End If

								ode\LastForce#=ForceA#
						
							End If

					End If
				Next
			End If
		;End If
	End If
Next

End Function


Try lowering the dWorldQuickStep() step size to '0.05' or less to help the objects 'relax' a bit more.

I've posted some more tips in the JV-ODE thread for you.

Code Box Tags:
[ codebox ] & [ /codebox ] without the spaces

;)

More Table bashing!!
Used new ode functions:
dJointFeedbackEnable(joint)
dJointFeedbackDisable(joint) ; didn't try this one
dJointFeedbackIsEnabled(joint)
dJointSetFeedback(joint,feedback); didn't try this one
dJointGetFeedbackForce1(joint)
dJointGetFeedbackTorque1(joint)
dJointGetFeedbackForce2(joint)
dJointGetFeedbackTorque2(joint)

Set thresholds at world level to reduce code size.
Rebuilt jointlimit function.
Added the patented wayner fps physics timing.
Adjusted parameters, added mass, and improved stability.

Thanks for posting and allowing me to tinker.



Include "JV-ODE.bb"

; DANNY's Broken Table Test - abused by Wayne

Const ANGTHRESH# = 0.1		;default auto disable angular threshold
Const LINTHRESH# = 0.1		;default auto disable linear threshold
Const STEPTHRESH = 1

Graphics3D 800,600,0,2

Type odeGeom
	Field body
	Field geom
	Field mesh
End Type

; ###################################################################################################
; ### Setup ODE

Global World=dWorldCreate()
Global Space=dHashSpaceCreate(0)
Global ContactGroup=dJointGroupCreate(0)

dWorldSetAutoDisableFlag(World,1)

dWorldSetGravity(World,0,-0.48,0)
;dWorldSetERP World, 0.25
dWorldSetERP(World,0.4)
dContactSetMode(dContactBounce)
dContactSetBounce(0.0)
dContactSetMu(80)

; High Performance Settings
; Causes objects to settle down and sleep faster
dWorldSetAutoDisableLinearThreshold (World, .23)
dWorldSetAutoDisableAngularThreshold (World, .23)
dWorldSetAutoDisableSteps (World,24)
dContactSetMaxContacts(16)
dWorldSetQuickStepNumIterations (World,20) ; default 20

;dContactSetMu(40)

SeedRnd 666

Global camera, camerapivot
Create3D()

;add some random tables
r#=1
addTable -3,2,3, 2,1,2
addTable  3,2,3, 2,1,2
addTable -3,2,-3, 2,1,2
addTable  3,2,-3, 2,1,2
addTable  0,3,0, 2,1,2

; ###################################################################################################
;sfx = Load3DSound("bin\woodimpact02.wav")
;Global break = Load3DSound("bin\Door.wav")
;CreateListener camera
;===============================================================
; Render Loop

While Not KeyHit(1)
		;add random boxes every couple ms
		If MilliSecs()-BoxTimer>50
			numbox=numbox+1
			;limit amount of boxes
			If numbox < 50 Then
				r# =4
				AddObject(Rand(-r,r),Rand(-r,r))
			EndIf
			BoxTimer=MilliSecs()
		End If
		
	;make dizzy
	TurnEntity camerapivot, 0, 0.1, 0

	;ENTER = more boxes
	If KeyDown(28) Then AddObject(Rand(-r,r),Rand(-r,r))

	;SPACE = more tables
	If KeyHit(57) Then AddTable(Rand(-r,r),Rand(3,6),Rand(-r,r),2,1,2)
	
	; Calculate Time 
	If T=0 Then T=MilliSecs()
	T=MilliSecs() 
	
	;-----------------------------------------------------------
	; Mouse Look code
	
	; Mouse Movement runs in sync with render world

		mxs#=mxs#+(MouseXSpeed()-mxs#)/3
		mys#=mys#+(MouseYSpeed()-mys#)/3
	
		If MouseDown(2) Then 
			MoveMouse GraphicsWidth()/2,GraphicsHeight()/2
			p1#=p1#-mys#
			y1#=y1#-mxs#
			RotateEntity camera,-p1#,y1#,0
		End If
	;----------------------------------------------------------
	; WSAD - Movement

	; W- Forward
	If KeyDown(17) Or KeyDown(200) Then
		MoveEntity camera,0,0,1
	EndIf
	; S- Reverse
	If KeyDown(31) Or KeyDown(208) Then
		MoveEntity camera,0,0,-1
	EndIf
	
	; A- Left
	If KeyDown(30) Or KeyDown(203) Then
		MoveEntity camera,-1,0,0
	EndIf
	; D- Right
	If KeyDown(32) Or KeyDown(205) Then
		MoveEntity camera,1,0,0
	EndIf
	
	
	;-----------------------------------------------
	; Physics
	;
	; Run Physics every 20ms ( 50 Times/sec )
	If T > Time3 + 20 Then
		Time3=T	
		
		PTime=MilliSecs()
	
		UpdateGeoms()
	
		For x=1 To 2 ; Increase to improve resolution
			dSpaceCollide(Space,World,ContactGroup)
				dWorldQuickStep(World,0.05)
			dJointGroupEmpty(ContactGroup)
		Next
	
		PhysicsTime#=MilliSecs()-PTime
		jointlimits(423)
		
	End If
	
	;-----------------------------------------------
	; FPS
		If T > Time4 + 1000 Then
			Time4=T	
			FPS=Frames
			frames=0
		End If
		frames=frames+1
    ;-----------------------------------------------
	; render world every loop

	RenderWorld

	;debug
	Color 250,250,250
	Text 5,0,"JV-ODE Version "+dGetVersion()
	Text 5,15,"Physics Time:"+PhysicsTime
	Text 5,30,"FPS: "+FPS
	Text GraphicsWidth()/2,50,"GREEN objects are ENABLED/ACTIVE - RED objects are DISABLED", 1
	Text GraphicsWidth()/2,65,"Press ENTER for more boxes", 1
	Text GraphicsWidth()/2,80,"Press SPACEBAR to add a Breakable Table!", 1

	;show
	Flip 

Wend

dJointGroupDestroy(ContactGroup)
dSpaceDestroy(Space)
dWorldDestroy(World)
dCloseODE()

End

; ###################################################################################################

Function Create3D()

;| Default 3d scene

	; ### Create light
	
	Light=CreateLight()
	
	RotateEntity Light,45,-90,0
	LightColor Light,255,255,255
	AmbientLight 130,130,130
	
	; ### Create camera
	camerapivot = CreatePivot()
	Camera=CreateCamera(camerapivot)
	CameraZoom camera, 1.5
	CameraClsColor Camera,0,0,0
	CameraRange Camera,0.01,250
	PositionEntity Camera,-5,7,-7
	PositionEntity camerapivot, 0,1,0
	PointEntity camera, camerapivot
	;make top text readable
	CameraFogColor camera, 0,0,0
	CameraFogRange camera, 5,30
	CameraFogMode camera, 1

	; ### Create plane
	dCreatePlane(Space,0,1,0,0)
	Plane=CreatePlane()
	EntityAlpha Plane,0.95
	PlaneTexture=CreateTexture(128,128,9)
	ClsColor 220,210,200
	Cls
	Color 150,120,110
	Rect 0,0,64,64,1
	Rect 64,64,64,64,1
	CopyRect 0,0,128,128,0,0,BackBuffer(),TextureBuffer(PlaneTexture)
	ScaleTexture PlaneTexture,5,5
	EntityTexture Plane,PlaneTexture,0,0
	Mirror=CreateMirror()
	Color 255,255,255

End Function

; ###################################################################################################

Function AddObject(xp#=666,zp#=666)

	size# = Rnd#(0.25,0.65)
	range# = 0.5

	If xp=666 Then xp=Rand(-range#,range#)
	yp=Rand(7,15)
	If zp=666 Then zp=Rand(-range#,range#)

	ode.ODEGeom=New ODEGeom

	ode\body=dBodyCreate(World)
	dBodySetRotation(ode\body,0,0,0)
	dBodySetPosition(ode\body,xp,yp,zp)
	dBodySetAutoDisableFlag(ode\body,1)

	;dBodySetAutoDisableLinearThreshold ode\body, LINTHRESH
	;dBodySetAutoDisableAngularThreshold ode\body, ANGTHRESH
	;dBodySetAutoDisableSteps ode\body, STEPTHRESH
	
	ode\geom=dCreateBox(Space,size#,size#,size#)
	dGeomSetBody(ode\geom,ode\body)
	
	ode\mesh=CreateCube()
	ScaleMesh ode\mesh,size#/2,size#/2,size#/2
	EntityColor ode\mesh,Rand(255),Rand(255),Rand(255)
	EntityAlpha ode\mesh,1
	EntityShininess ode\mesh,0.7

	mass = dMassCreate()
	dMassSetBoxTotal mass, 100.0, size#,size#,size#
	dBodySetMass ode\body, mass
	dMassDestroy mass

End Function

; ###################################################################################################

Function AddTable(xp#, yp#, zp#, w#,h#,d#)

;# Creates a table with 4 legs - breakable legs! :)

	w# = Rnd(w#*0.5,w#*1.5)		;add some variation to the table's dimensions
	h# = Rnd(h#*0.5,h#*1.5)
	d# = Rnd(d#*0.5,d#*1.5)

	;table top dimensions
	th# = h# * 0.1

	;leg dimensions
	lw# = w#*0.1
	lh# = h#*0.9
	ld# = d#*0.1

	;create tabletop
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#, yp#, zp#
	dBodySetRotation ode\body, 0,0,0
	dBodySetAutoDisableFlag ode\body, 1

	ode\geom=dCreateBox(space,w#,th#,d#)
	dGeomSetBody ode\geom, ode\body	

	ode\mesh=CreateCube()
	EntityColor ode\mesh, 100,50,0
	ScaleMesh ode\mesh, w#/2,th#/2,d#/2
	
	mass = dMassCreate()
	dMassSetBoxTotal mass, 20.0, w#,th#,d#
	dBodySetMass ode\body, mass
	dMassDestroy mass
	
	tableBody = ode\body

;	yp# = yp# - 0.01 ;-> create small gap between table top & legs

	;create leg 1
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#-w#/2+lw#/2, yp#-lh#/2-th#/2, zp#-d#/2+ld#/2
	dBodySetRotation ode\body, 0,0,0
	dBodySetAutoDisableFlag ode\body, 1

	ode\geom=dCreateBox(space,lw#,lh#,ld#)
	dGeomSetBody ode\geom, ode\body	

	ode\mesh=CreateCube()
	EntityColor ode\mesh, 200,100,0
	ScaleMesh ode\mesh, lw#/2,lh#/2,ld#/2
	
	mass = dMassCreate()
	dMassSetBoxTotal mass, 5.0, lw#,lh#,ld#
	dBodySetMass ode\body, mass
	dMassDestroy mass

	;join the legs to the table
	joint = dJointCreateHinge(world,0)
	dJointAttach joint, tableBody, ode\body
	dJointSetHingeAxis joint, -1,0,0
	dJointSetHingeAnchor joint, xp#-w#/2+lw#/2, yp#-th#/2, zp#-d#/2+ld#/2
	dJointSetHingeParam joint, dParamLoStop,  0
	dJointSetHingeParam joint, dParamHiStop,  0
	dJointFeedbackEnable(Joint) ; Allow feedback for breakable joints

	;create leg 2
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#+w#/2-lw#/2, yp#-lh#/2-th#/2, zp#-d#/2+ld#/2
	dBodySetRotation ode\body, 0,0,0
	dBodySetAutoDisableFlag ode\body, 1

	ode\geom=dCreateBox(space,lw#,lh#,ld#)
	dGeomSetBody ode\geom, ode\body	

	ode\mesh=CreateCube()
	EntityColor ode\mesh, 200,100,0
	ScaleMesh ode\mesh, lw#/2,lh#/2,ld#/2
	
	mass = dMassCreate()
	dMassSetBoxTotal mass, 5.0, lw#,lh#,ld#
	dBodySetMass ode\body, mass
	dMassDestroy mass

	;join the legs to the table
	joint = dJointCreateHinge(world,0)
	dJointAttach joint, tableBody, ode\body
	dJointSetHingeAxis joint, -1,0,0
	dJointSetHingeAnchor joint, xp#+w#/2-lw#/2, yp#-th#/2, zp#-d#/2+ld#/2
	dJointSetHingeParam joint, dParamLoStop, -0.0
	dJointSetHingeParam joint, dParamHiStop,  0.0
	dJointFeedbackEnable(Joint) ; Allow feedback for breakable joints
	
	;create leg 3
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#+w#/2-lw#/2, yp#-lh#/2-th#/2, zp#+d#/2-ld#/2
	dBodySetRotation ode\body, 0,0,0
	dBodySetAutoDisableFlag ode\body, 1
	;dBodySetAutoDisableLinearThreshold ode\body, LINTHRESH
	;dBodySetAutoDisableAngularThreshold ode\body, ANGTHRESH
	;dBodySetAutoDisableSteps ode\body, STEPTHRESH

	ode\geom=dCreateBox(space,lw#,lh#,ld#)
	dGeomSetBody ode\geom, ode\body	

	ode\mesh=CreateCube()
	EntityColor ode\mesh, 200,100,0
	ScaleMesh ode\mesh, lw#/2,lh#/2,ld#/2
	
	mass = dMassCreate()
	dMassSetBoxTotal mass, 5.0, lw#,lh#,ld#
	dBodySetMass ode\body, mass
	dMassDestroy mass

	;join the legs to the table
	joint = dJointCreateHinge(world,0)
	dJointAttach joint, tableBody, ode\body
	dJointSetHingeAxis joint, -1,0,0
	dJointSetHingeAnchor joint, xp#+w#/2-lw#/2, yp#-th#/2, zp#+d#/2-ld#/2
	dJointSetHingeParam joint, dParamLoStop, -0.0
	dJointSetHingeParam joint, dParamHiStop,  0.0
	dJointFeedbackEnable(Joint) ; Allow feedback for breakable joints

	;create leg 4
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#-w#/2+lw#/2, yp#-lh#/2-th#/2, zp#+d#/2-ld#/2
	dBodySetRotation ode\body, 0,0,0
	dBodySetAutoDisableFlag ode\body, 1

	ode\geom=dCreateBox(space,lw#,lh#,ld#)
	dGeomSetBody ode\geom, ode\body	

	ode\mesh=CreateCube()
	EntityColor ode\mesh, 200,100,0
	ScaleMesh ode\mesh, lw#/2,lh#/2,ld#/2

	mass = dMassCreate()
	dMassSetBoxTotal mass, 5.0, lw#,lh#,ld#
	dBodySetMass ode\body, mass
	dMassDestroy mass
	
	;join the legs to the table
	joint = dJointCreateHinge(world,0)
	dJointAttach joint, tableBody, ode\body
	dJointSetHingeAxis joint, -1,0,0
	dJointSetHingeAnchor joint, xp#-w#/2+lw#/2, yp#-th#/2, zp#+d#/2-ld#/2
	dJointSetHingeParam joint, dParamLoStop, -0.0
	dJointSetHingeParam joint, dParamHiStop,  0.0
	dJointFeedbackEnable(Joint) ; Allow feedback for breakable joints

End Function


; ###################################################################################################

Function UpdateGeoms()

	For ode.ODEGeom=Each ODEGeom
		If dBodyIsEnabled(ode\body)
			RotateEntity ode\mesh,dGeomGetPitch#(ode\geom),dGeomGetYaw#(ode\geom),dGeomGetRoll#(ode\geom)
			PositionEntity ode\mesh,dGeomGetPositionX#(ode\geom),dGeomGetPositionY#(ode\geom),dGeomGetPositionZ#(ode\geom)
			EntityColor ode\mesh, 0,255,0
		Else
			EntityColor ode\mesh, 255,0,0		
		End If

		;remove if object falls off the world
		If dGeomGetPositionY#(ode\geom) < -100 Then
			DebugLog "body "+Handle(ode)+" deleted"
			dGeomDestroy ode\geom
			dBodyDestroy ode\body
			FreeEntity ode\mesh
			Delete ode
		EndIf
	Next

End Function

; ###################################################################################################

Function JointLimits(limit)

For ode.ODEGeom=Each ODEGeom
	If dGeomIsEnabled(ode\geom)
 		numjoints=dBodyGetNumJoints(ode\body)
		If numjoints>0 
			For joints=0 To numjoints-1
				joint=dBodyGetJoint(ode\body,joints)
					If joint<>0 ; valid joints only
						If dJointFeedbackIsEnabled(Joint)=1
							; Get linear velocity vector
							dJointGetFeedbackForce1(Joint)
							If Abs(dVectorX())>limit Or Abs(dVectorY())>limit Or Abs(dVectorZ())>limit
								dJointAttach(joint,0,0) ; break joint
							Else
								dJointGetFeedbackForce2(Joint)
								If Abs(dVectorX())>limit Or Abs(dVectorY())>limit Or Abs(dVectorZ())>limit
									dJointAttach(joint,0,0) ; Break joint
								Else
									dJointGetFeedbackTorque1(Joint)
									If Abs(dVectorX())>limit Or Abs(dVectorY())>limit Or Abs(dVectorZ())>limit
										dJointAttach(joint,0,0) ; Break joint				
									Else
										dJointGetFeedbackTorque2(Joint)
										If Abs(dVectorX())>limit Or Abs(dVectorY())>limit Or Abs(dVectorZ())>limit
											dJointAttach(joint,0,0) ; Break joint
										End If	
									End If
										
								End If		
							End If			
					
						End If
				End If
			Next
		End If
	End If
Next

End Function


Good stuff Wayne! :D

I just found out that there's a 'fixed joint'. For the table I'm using a hinge joint with it's Lo/HiStop set to 0 to prevent wobbly legs. But a 'fixed joint' would make more sense right since the table legs are not supposed to be just connected to each other and not move - JUST BREAK! eh eh...

BUT If I replace any 'dJointCreateHinge' with a 'dJointCreateFixed' then I get a MAV when ever I try to run it...

This normal? Wrapper bug? ode bug? me bugged?

cheers
Danny.

Fixed joints work ok, so it must be 'you bugged' :D

Take a look at the 'CarDemo-SphereWrapCylinder.bb' demo, it contains use of the fixed joint. It boils down to...

Joint=dJointCreateFixed(World,0)
dJointAttach(Joint,Body1,Body2)
dJointSetFixed(Joint)


I'd guess you've forgotten to remove some (or all) of the now redundant hinge functions... dJointSetHingeAnchor() / dJointSetHingeParam() etc.

If you're still getting errors, post some code and I'll try to help ;)

Yep, you're right. Tried it, works! cool! ....

I think one of the mayor differences between ode & tokamak (there more I'm sure) but is that you don't have Animated vs Rigid Bodies. And ODE rigid bodies behave more than you'd expect them to: when you move them around they affect their surroundings; with Tok you couldn't do that without losing colision & interaction.

A simple example is to create a door which you can open automatically (player presses spacebar, rotate door +90 degrees to open) BUT can get stuck when for example you've got a dozen heavy crates stacked on top of each other on the other side. This should block the door. But if the player pushes hard enough, he should be able to open the door AND shift the crates at the same time...
I'm gonna try that next! :)

Super cool! Check this out... Danny's Diner!

Hold down the left mousebutton to move the white player cube and move him through the doors, bump over tables, etc!

Wayne... If you're up for a tinker... Any idea HOW you can prevent that white player cube to go THROUGH walls and other bodies?! ;)

Include "JV-ODE.bb"

; DANNY's DoorStop Test - to be abused by Wayne

Const ANGTHRESH# = 0.1		;default auto disable angular threshold
Const LINTHRESH# = 0.1		;default auto disable linear threshold
Const STEPTHRESH = 1

Graphics3D 800,600,0,2

Type odeGeom
	Field body
	Field geom
	Field mesh
End Type

; ###################################################################################################
; ### Setup ODE

Global World=dWorldCreate()
Global Space=dHashSpaceCreate(0)
Global ContactGroup=dJointGroupCreate(0)

;dWorldSetAutoDisableFlag(World,1)

dWorldSetGravity(World,0,-0.48,0)
dWorldSetERP World, 0.25
dWorldSetERP(World,0.4)
dContactSetMaxContacts 40
dContactSetMode(dContactBounce)
dContactSetBounce(0.0)
dContactSetMu(80)

; High Performance Settings
; Causes objects to settle down and sleep faster
dWorldSetAutoDisableLinearThreshold (World, .23)
dWorldSetAutoDisableAngularThreshold (World, .23)
dWorldSetAutoDisableSteps (World,24)
dContactSetMaxContacts(16)
dWorldSetQuickStepNumIterations (World,20) ; default 20

SeedRnd 666

Global camera, camerapivot
Create3D()

;add door
AddDoor 0,1, 4, 1.3,2,0.10, 5
AddDoor 0,1,-4, 1.3,2,0.10, 5

;add some tables
r#=1
addTable -2,2,-1, 2,1,2
addTable  2,2, 1, 2,1,2

;Create 'master box' (tm)

size# = 0.75
weight# = 25.0

MasterBody=dBodyCreate(World)
dBodySetRotation(MasterBody,0,0,0)
dBodySetPosition(MasterBody,0,size#,0)
dBodySetAutoDisableFlag(MasterBody,1)
MasterGeom=dCreateBox(Space,size#,size#,size#)
dGeomSetBody(MasterGeom,MasterBody)
MasterMesh=CreateCube()
ScaleMesh MasterMesh,size#/2,size#/2,size#/2
EntityColor MasterMesh, 255,255,255
EntityAlpha MasterMesh,1
EntityShininess MasterMesh,0.7
mass = dMassCreate()
dMassSetBoxTotal mass, weight#, size#,size#,size#
dBodySetMass MasterBody, mass
dMassDestroy mass

; ###################################################################################################
; ### Render Loop

While Not KeyHit(1)

	;LEFT MOUSE BUTTON: position box
	If MouseDown(1) Then
		;position master box on mouse position
		ent = CameraPick(camera, MouseX(),MouseY())
		If ent <> 0 Then
			dBodySetPosition masterBody, PickedX#(), PickedY#()+size#/2, PickedZ#()
			dBodySetRotation masterBody, 0,0,0
		EndIf
	EndIf

	;add random boxes every couple ms
	If MilliSecs()-BoxTimer>25
		numbox=numbox+1
		;limit amount of boxes
		If numbox < 10 Then
			r# =4
			AddObject(Rand(-r,r),Rand(-r,r))
		EndIf
		BoxTimer=MilliSecs()
	End If

	;make dizzy
	TurnEntity camerapivot, 0, 0.01, 0

	;ENTER = more boxes
	If KeyDown(28) Then AddObject(Rand(-r,r),Rand(-r,r))

	;SPACE = more tables
	If KeyHit(57) Then AddTable(Rand(-r,r),Rand(3,6),Rand(-r,r),2,1,2)

	; Calculate Time 
	If T=0 Then T=MilliSecs()
	T=MilliSecs() 

	;-----------------------------------------------------------
	; Mouse Look code

	; Mouse Movement runs in sync with render world
	mxs#=mxs#+(MouseXSpeed()-mxs#)/6
	mys#=mys#+(MouseYSpeed()-mys#)/6

	If MouseDown(2) Then 
		MoveMouse GraphicsWidth()/2,GraphicsHeight()/2
		p1#=p1#-mys#
		y1#=y1#-mxs#
		RotateEntity camera,-p1#,y1#,0
	End If

	;----------------------------------------------------------
	; WSAD - Movement

	; W- Forward
	speed# = 0.4
	If KeyDown(17) Or KeyDown(200) Then
		MoveEntity camera,0,0,speed#
	EndIf
	; S- Reverse
	If KeyDown(31) Or KeyDown(208) Then
		MoveEntity camera,0,0,-speed#
	EndIf

	; A- Left
	If KeyDown(30) Or KeyDown(203) Then
		MoveEntity camera,-speed#,0,0
	EndIf
	; D- Right
	If KeyDown(32) Or KeyDown(205) Then
		MoveEntity camera,speed#,0,0
	EndIf

	;-----------------------------------------------
	; Physics
	;
	; Run Physics every 20ms ( 50 Times/sec )
	If T > Time3 + 20 Then
		Time3=T	
		PTime=MilliSecs()
		UpdateGeoms()
		;exceptional manual hack
		PositionEntity MasterMesh, dGeomGetPositionX#(MasterGeom),dGeomGetPositionY#(MasterGeom),dGeomGetPositionZ#(MasterGeom)
		RotateEntity MasterMesh, dGeomGetPitch#(MasterGeom),dGeomGetYaw#(MasterGeom),dGeomGetRoll#(MasterGeom)
		;continue
		For x=1 To 2 ; Increase to improve resolution
			dSpaceCollide(Space,World,ContactGroup)
				dWorldQuickStep(World,0.05)
			dJointGroupEmpty(ContactGroup)
		Next
		PhysicsTime#=MilliSecs()-PTime
		jointlimits(750)
	End If

	;-----------------------------------------------
	; FPS
		If T > Time4 + 1000 Then
			Time4=T	
			FPS=Frames
			frames=0
		End If
		frames=frames+1
    ;-----------------------------------------------
	; render world every loop

	RenderWorld

	;label 'the player'
	CameraProject camera,dGeomGetPositionX#(MasterGeom), dGeomGetPositionY#(MasterGeom)+size#*2, dGeomGetPositionZ#(MasterGeom)
	x = ProjectedX#()
	y = ProjectedY#()

	;debug
	Color 220,220,220
	Text 5,0,"JV-ODE Version "+dGetVersion()
	Text 5,15,"Physics Time:"+PhysicsTime
	Text 5,30,"FPS: "+FPS
	Text GraphicsWidth()/2,75,"Press ENTER for more boxes", 1
	Text GraphicsWidth()/2,90,"Press SPACEBAR to add breakable tables!", 1

	Color 250,220,0
	Text GraphicsWidth()/2,50,"USE LEFT MOUSE BUTTON TO POSITION & MOVE THE WHITE 'PLAYER' CUBE!", 1

	Color 255,255,255
	If x>0 And y>0 Then Text x,y,"PLAYER",1,0
	;show
	Flip 0

Wend

dJointGroupDestroy(ContactGroup)
dSpaceDestroy(Space)
dWorldDestroy(World)
dCloseODE()

End

; ###################################################################################################

Function Create3D()

;| Default 3d scene

	; ### Create light
	Light=CreateLight()
	RotateEntity Light,45,-90,0
	LightColor Light,255,255,255
	AmbientLight 130,130,130

	; ### Create camera
	camerapivot = CreatePivot()
	Camera=CreateCamera(camerapivot)
	CameraZoom camera, 1.5
	CameraClsColor Camera,0,0,0
	CameraRange Camera,0.01,250
	PositionEntity Camera,-5,7,-7
	PositionEntity camerapivot, 0,1,0
	PointEntity camera, camerapivot
	;make top text readable
	CameraFogColor camera, 0,0,0
	CameraFogRange camera, 5,30
	CameraFogMode camera, 1

	; ### Create plane
	dCreatePlane(Space,0,1,0,0)
	Plane=CreatePlane()
	EntityAlpha Plane,0.95
	EntityPickMode plane, 2, True
	PlaneTexture=CreateTexture(128,128,9)
	ClsColor 220,210,200
	Cls
	Color 150,120,110
	Rect 0,0,64,64,1
	Rect 64,64,64,64,1
	CopyRect 0,0,128,128,0,0,BackBuffer(),TextureBuffer(PlaneTexture)
	ScaleTexture PlaneTexture,5,5
	EntityTexture Plane,PlaneTexture,0,0
	Mirror=CreateMirror()
	Color 255,255,255

End Function

; ###################################################################################################

Function AddDoor(x#,y#,z#, w#,h#,d#, weight#=5)

	doorframe# = 0.02		; Depending on the thickness of the door, need a little space between door & frame
							;(because the hinge is in the center (zaxis) of the door, in stead of on an end.

	; ALSO, the door itself needs to be a centimeter or so from the floor, else it will drag
	; and leave nasty marks on the floor!

	ode.odeGeom = New odeGeom

	ode\body=dBodyCreate(World)
	dBodySetRotation(ode\body,0,0,0)
	dBodySetPosition(ode\body,x#,y#+0.01,z#)
	ode\geom=dCreateBox(Space,w#,h#-0.02,d#)
	dGeomSetBody(ode\geom,ode\body)
	ode\mesh=CreateCube()
	ScaleMesh ode\mesh,w#/2,h#/2-0.02,d#/2
	EntityColor ode\mesh,100,0,120
	EntityAlpha ode\mesh,1
	EntityShininess ode\mesh,0.7
	mass = dMassCreate()
	dMassSetBoxTotal mass, weight#, w#,h#-0.02,d#
	dBodySetMass ode\body, mass
	dMassDestroy mass
	;add hinge joint to the door
	joint=dJointCreateHinge(World,0)
	dJointAttach joint, 0, ode\body
	dJointSetHingeAxis joint, 0,1,0
	dJointSetHingeAnchor joint, x#+w#/2,y#,z#
	dJointSetHingeParam joint, dParamLoStop, -0.5 * 3.14		;1pi = 180 degrees
	dJointSetHingeParam joint, dParamHiStop,  0.5 * 3.14

	;wall dimensions
	ww# = 5.0
	wh# = h#
	wd# = 0.25

	;add wall segment - right of door (geometry only!)
	ode.odeGeom = New odeGeom
	ode\body=0	; nobody here!
	ode\geom=dCreateBox(Space,ww#,wh#,wd#)
	dGeomSetPosition ode\geom, x#+w#/2+ww#/2+doorframe#,y#,z#
	ode\mesh=CreateCube()
	ScaleMesh ode\mesh,ww#/2, wh#/2, wd#/2
	EntityColor ode\mesh,100,100,100
	EntityShininess ode\mesh,0.7

	;add wall segment - left of door (geometry only!)
	ode.odeGeom = New odeGeom
	ode\body=0	; nobody here!
	ode\geom=dCreateBox(Space,ww#,wh#,wd#)
	dGeomSetPosition ode\geom, x#-w#/2-ww#/2-doorframe#,y#,z#
	ode\mesh=CreateCube()
	ScaleMesh ode\mesh,ww#/2, wh#/2, wd#/2
	EntityColor ode\mesh,100,100,100
	EntityShininess ode\mesh,0.7

End Function


; ###################################################################################################

Function AddObject(xp#=666,zp#=666)

	size# = Rnd#(0.25,0.65)
	range# = 0.5

	If xp#=666 Then xp=Rand(-range#,range#)
	yp#=Rand(7,15)
	If zp#=666 Then zp=Rand(-range#,range#)

	ode.ODEGeom=New ODEGeom

	ode\body=dBodyCreate(World)
	dBodySetRotation(ode\body,0,0,0)
	dBodySetPosition(ode\body,xp#,yp#,zp#)
	ode\geom=dCreateBox(Space,size#,size#,size#)
	dGeomSetBody(ode\geom,ode\body)
	ode\mesh=CreateCube()
	ScaleMesh ode\mesh,size#/2,size#/2,size#/2
	EntityColor ode\mesh,Rand(255),Rand(255),Rand(255)
	EntityAlpha ode\mesh,1
	EntityShininess ode\mesh,0.7
	mass = dMassCreate()
	dMassSetBoxTotal mass, 10.0, size#,size#,size#
	dBodySetMass ode\body, mass
	dMassDestroy mass

End Function

; ###################################################################################################

Function AddTable(xp#, yp#, zp#, w#,h#,d#)

;# Creates a table with 4 legs - breakable legs! :)

	w# = Rnd(w#*0.5,w#*1.5)		;add some variation to the table's dimensions
	h# = Rnd(h#*0.5,h#*1.5)
	d# = Rnd(d#*0.5,d#*1.5)

	;table top dimensions
	th# = h# * 0.1

	;leg dimensions
	lw# = w#*0.1
	lh# = h#*0.9
	ld# = d#*0.1

	;create tabletop
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#, yp#, zp#
	dBodySetRotation ode\body, 0,0,0

	ode\geom=dCreateBox(space,w#,th#,d#)
	dGeomSetBody ode\geom, ode\body	

	ode\mesh=CreateCube()
	EntityColor ode\mesh, 100,50,0
	ScaleMesh ode\mesh, w#/2,th#/2,d#/2
	
	mass = dMassCreate()
	dMassSetBoxTotal mass, 20.0, w#,th#,d#
	dBodySetMass ode\body, mass
	dMassDestroy mass
	
	tableBody = ode\body

	;create leg 1
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#-w#/2+lw#/2, yp#-lh#/2-th#/2, zp#-d#/2+ld#/2
	dBodySetRotation ode\body, 0,0,0

	ode\geom=dCreateBox(space,lw#,lh#,ld#)
	dGeomSetBody ode\geom, ode\body	

	ode\mesh=CreateCube()
	EntityColor ode\mesh, 200,100,0
	ScaleMesh ode\mesh, lw#/2,lh#/2,ld#/2
	
	mass = dMassCreate()
	dMassSetBoxTotal mass, 5.0, lw#,lh#,ld#
	dBodySetMass ode\body, mass
	dMassDestroy mass

	;join the leg to the table
	joint = dJointCreateFixed(world,0)
	dJointAttach joint, tableBody, ode\body
	dJointSetFixed joint
	dJointFeedbackEnable(Joint) ; Allow feedback for breakable joints

	;create leg 2
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#+w#/2-lw#/2, yp#-lh#/2-th#/2, zp#-d#/2+ld#/2
	dBodySetRotation ode\body, 0,0,0

	ode\geom=dCreateBox(space,lw#,lh#,ld#)
	dGeomSetBody ode\geom, ode\body	

	ode\mesh=CreateCube()
	EntityColor ode\mesh, 200,100,0
	ScaleMesh ode\mesh, lw#/2,lh#/2,ld#/2
	
	mass = dMassCreate()
	dMassSetBoxTotal mass, 5.0, lw#,lh#,ld#
	dBodySetMass ode\body, mass
	dMassDestroy mass

	;join the leg to the table
	joint = dJointCreateFixed(world,0)
	dJointAttach joint, tableBody, ode\body
	dJointSetFixed joint
	dJointFeedbackEnable(Joint) ; Allow feedback for breakable joints
	
	;create leg 3
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#+w#/2-lw#/2, yp#-lh#/2-th#/2, zp#+d#/2-ld#/2
	dBodySetRotation ode\body, 0,0,0

	ode\geom=dCreateBox(space,lw#,lh#,ld#)
	dGeomSetBody ode\geom, ode\body	
	ode\mesh=CreateCube()
	EntityColor ode\mesh, 200,100,0
	ScaleMesh ode\mesh, lw#/2,lh#/2,ld#/2
	mass = dMassCreate()
	dMassSetBoxTotal mass, 5.0, lw#,lh#,ld#
	dBodySetMass ode\body, mass
	dMassDestroy mass

	;join the leg to the table
	joint = dJointCreateFixed(world,0)
	dJointAttach joint, tableBody, ode\body
	dJointSetFixed joint
	dJointFeedbackEnable(Joint) ; Allow feedback for breakable joints

	;create leg 4
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#-w#/2+lw#/2, yp#-lh#/2-th#/2, zp#+d#/2-ld#/2
	dBodySetRotation ode\body, 0,0,0

	ode\geom=dCreateBox(space,lw#,lh#,ld#)
	dGeomSetBody ode\geom, ode\body	
	ode\mesh=CreateCube()
	EntityColor ode\mesh, 200,100,0
	ScaleMesh ode\mesh, lw#/2,lh#/2,ld#/2
	mass = dMassCreate()
	dMassSetBoxTotal mass, 5.0, lw#,lh#,ld#
	dBodySetMass ode\body, mass
	dMassDestroy mass

	;join the leg to the table
	joint = dJointCreateFixed(world,0)
	dJointAttach joint, tableBody, ode\body
	dJointSetFixed joint
	dJointFeedbackEnable(Joint) ; Allow feedback for breakable joints

End Function


; ###################################################################################################

Function UpdateGeoms()

	For ode.ODEGeom=Each ODEGeom

		RotateEntity ode\mesh,dGeomGetPitch#(ode\geom),dGeomGetYaw#(ode\geom),dGeomGetRoll#(ode\geom)
		PositionEntity ode\mesh,dGeomGetPositionX#(ode\geom),dGeomGetPositionY#(ode\geom),dGeomGetPositionZ#(ode\geom)

		If ode\body <> 0 Then
			If dBodyIsEnabled(ode\body)
;				EntityColor ode\mesh, 0,255,0
			Else
;				EntityColor ode\mesh, 255,0,0		
			End If
		EndIf

		;remove if object falls off the world
		If dGeomGetPositionY#(ode\geom) < -100 Then
			DebugLog "body "+Handle(ode)+" deleted"
			dGeomDestroy ode\geom
			dBodyDestroy ode\body
			FreeEntity ode\mesh
			Delete ode
		EndIf
	Next

End Function

; ###################################################################################################

Function JointLimits(limit)

For ode.ODEGeom=Each ODEGeom
	If dGeomIsEnabled(ode\geom) And ode\body <> 0
 		numjoints=dBodyGetNumJoints(ode\body)
		If numjoints>0 
			For joints=0 To numjoints-1
				joint=dBodyGetJoint(ode\body,joints)
					If joint<>0 ; valid joints only
						If dJointFeedbackIsEnabled(Joint)=1
							; Get linear velocity vector
							dJointGetFeedbackForce1(Joint)
							If Abs(dVectorX())>limit Or Abs(dVectorY())>limit Or Abs(dVectorZ())>limit
								dJointAttach(joint,0,0) ; break joint
							Else
								dJointGetFeedbackForce2(Joint)
								If Abs(dVectorX())>limit Or Abs(dVectorY())>limit Or Abs(dVectorZ())>limit
									dJointAttach(joint,0,0) ; Break joint
								Else
									dJointGetFeedbackTorque1(Joint)
									If Abs(dVectorX())>limit Or Abs(dVectorY())>limit Or Abs(dVectorZ())>limit
										dJointAttach(joint,0,0) ; Break joint				
									Else
										dJointGetFeedbackTorque2(Joint)
										If Abs(dVectorX())>limit Or Abs(dVectorY())>limit Or Abs(dVectorZ())>limit
											dJointAttach(joint,0,0) ; Break joint
										End If	
									End If
										
								End If		
							End If			
					
						End If
				End If
			Next
		End If
	End If
Next

End Function


Ah, you're going to have severe problems forcing an objects position and rotation with ODE. The correct way is to add force/torque to the body or joint, ODE should be allowed to handle the position and rotation of all objects in the simulation.

Try adding the following to the Render Loop...

dBodyEnable(masterBody)
If KeyDown(59) Then dBodyAddForce(masterBody,-10,0,0)
If KeyDown(60) Then dBodyAddForce(masterBody,10,0,0)
If KeyDown(61) Then dBodyAddForce(masterBody,0,0,10)
If KeyDown(62) Then dBodyAddForce(masterBody,0,0,-10)

Use the F1-F4 keys to move the player box.

If you don't want the box to roll over, you can either lower its friction directly (see geom contacts) or create a sphere with a cube attached by a joint (encasing the sphere, except for its base). There are some demos showing the latter in the older JV-ODE threads, have a look for Psychic Parrots demo.

Cheers vip3r,

yes I realise forcing position & rotation is not the proper thing to do. But I'm pleasantly surprised how well ODE handles it nonetheless..

more to experiment...

If you don't want the cube to roll you can dampen it's angular velocity along x,y, or z axis. using:
dBodySetAngularVel (dBodyID, dReal x, dReal y, dReal z)

With doors consider:
The ...ForceAtPos and ...ForceAtRelPos functions take an extra position vector (in global or body-relative coordinates respectively) that specifies the point at which the force is applied. All other functions apply the force at the center of mass.

Oh goodie a new progie to play with!

:)

Cheers Wayne. I'm now trying to figure out why the Hinge joint tries to go back to it's original orientation? When you push-open a door, it will close again - like those little doors they have in saloon's ;) In this case it works nice, but as a control freak, I'd like to determin that myself :)

Next progie on the menu... "Crowd surfing zombie makes it out the backdoor!"

Hmm... harder than I thought...

Sorry for harassing you guys, just tell me to shut up..

If not, How can you control the root (first) joint in a chain of joints?

Examples:
- If I create a rope made out of ball/socket joints, how can I move the start/top of the rope?
- More appropreate: Let's say my hierarchy of joints is used for a ragdoll. How can I MOVE the ragdoll by assigning one of the joints or bodies as a root and set it's position?

I've tried hacking away in the zombie demo, but either head remains in place while his body drops (sick neck stretch!) or he goes in some eleptic state.. I can't reposition the joint. So I've tried repositioning the root body or it's geometry only but all this don't work :(

any hints appreciated!

danny.

Hows this:
Clamps player rotation.
Allows mouse to control the player.

I like the doors.

8)

Include "JV-ODE.bb"

; DANNY's DoorStop Test - to be abused by Wayne

Const ANGTHRESH# = 0.1		;default auto disable angular threshold
Const LINTHRESH# = 0.1		;default auto disable linear threshold
Const STEPTHRESH = 1

Graphics3D 800,600,0,2

Type odeGeom
	Field body
	Field geom
	Field mesh
End Type

; ###################################################################################################
; ### Setup ODE

Global World=dWorldCreate()
Global Space=dHashSpaceCreate(0)
Global ContactGroup=dJointGroupCreate(0)

;dWorldSetAutoDisableFlag(World,1)

dWorldSetGravity(World,0,-0.48,0)
dWorldSetERP World, 0.25
dWorldSetERP(World,0.4)
dContactSetMaxContacts 40
dContactSetMode(dContactBounce)
dContactSetBounce(0.0)
dContactSetMu(80)

; High Performance Settings
; Causes objects to settle down and sleep faster
dWorldSetAutoDisableLinearThreshold (World, .23)
dWorldSetAutoDisableAngularThreshold (World, .23)
dWorldSetAutoDisableSteps (World,24)
dContactSetMaxContacts(16)
dWorldSetQuickStepNumIterations (World,20) ; default 20

SeedRnd 666

Global camera, camerapivot
Create3D()

;add door
AddDoor 0,1, 4, 1.3,2,0.10, 5
AddDoor 0,1,-4, 1.3,2,0.10, 5

;add some tables
r#=1
addTable -2,2,-1, 2,1,2
addTable  2,2, 1, 2,1,2

;Create 'master box' (tm)

size# = 0.75
weight# = 100.0

MasterBody=dBodyCreate(World)
dBodySetRotation(MasterBody,0,0,0)
dBodySetPosition(MasterBody,0,size#,0)
dBodySetAutoDisableFlag(MasterBody,1)
MasterGeom=dCreateBox(Space,size#,size#,size#)
dGeomSetBody(MasterGeom,MasterBody)
MasterMesh=CreateCube()
ScaleMesh MasterMesh,size#/2,size#/2,size#/2
EntityColor MasterMesh, 255,255,255
EntityAlpha MasterMesh,1
EntityShininess MasterMesh,0.7
mass = dMassCreate()
dMassSetBoxTotal mass, weight#, size#,size#,size#
dBodySetMass MasterBody, mass
dMassDestroy mass

; ###################################################################################################
; ### Render Loop

While Not KeyHit(1)

	;LEFT MOUSE BUTTON: position box
	If MouseDown(1) Then
		;position master box on mouse position
		ent = CameraPick(camera, MouseX(),MouseY())
		If ent <> 0 Then
			dBodyEnable(masterBody)
			dBodyAddForce(masterBody,-(399-MouseX())*6,0,(299-MouseY())*7)
			MoveMouse 399,299
		EndIf
	EndIf

	;add random boxes every couple ms
	If MilliSecs()-BoxTimer>25
		numbox=numbox+1
		;limit amount of boxes
		If numbox < 10 Then
			r# =4
			AddObject(Rand(-r,r),Rand(-r,r))
		EndIf
		BoxTimer=MilliSecs()
	End If

	;make dizzy
	TurnEntity camerapivot, 0, 0.01, 0

	;ENTER = more boxes
	If KeyDown(28) Then AddObject(Rand(-r,r),Rand(-r,r))

	;SPACE = more tables
	If KeyHit(57) Then AddTable(Rand(-r,r),Rand(3,6),Rand(-r,r),2,1,2)

	; Calculate Time 
	If T=0 Then T=MilliSecs()
	T=MilliSecs() 

	;-----------------------------------------------------------
	; Mouse Look code

	; Mouse Movement runs in sync with render world
	mxs#=mxs#+(MouseXSpeed()-mxs#)/6
	mys#=mys#+(MouseYSpeed()-mys#)/6

	If MouseDown(2) Then 
		MoveMouse GraphicsWidth()/2,GraphicsHeight()/2
		p1#=p1#-mys#
		y1#=y1#-mxs#
		RotateEntity camera,-p1#,y1#,0
	End If

	;----------------------------------------------------------
	; WSAD - Movement

	; W- Forward
	speed# = 0.4
	If KeyDown(17) Or KeyDown(200) Then
		MoveEntity camera,0,0,speed#
	EndIf
	; S- Reverse
	If KeyDown(31) Or KeyDown(208) Then
		MoveEntity camera,0,0,-speed#
	EndIf

	; A- Left
	If KeyDown(30) Or KeyDown(203) Then
		MoveEntity camera,-speed#,0,0
	EndIf
	; D- Right
	If KeyDown(32) Or KeyDown(205) Then
		MoveEntity camera,speed#,0,0
	EndIf

	;-----------------------------------------------
	; Physics
	;
	; Run Physics every 20ms ( 50 Times/sec )
	If T > Time3 + 20 Then
		Time3=T	
		PTime=MilliSecs()
		UpdateGeoms()
		;exceptional manual hack
		PositionEntity MasterMesh, dGeomGetPositionX#(MasterGeom),dGeomGetPositionY#(MasterGeom),dGeomGetPositionZ#(MasterGeom)
		RotateEntity MasterMesh, dGeomGetPitch#(MasterGeom),dGeomGetYaw#(MasterGeom),dGeomGetRoll#(MasterGeom)
		;continue
		For x=1 To 2 ; Increase to improve resolution
			dSpaceCollide(Space,World,ContactGroup)
				dWorldQuickStep(World,0.05)
				; clamp player rotation
				dBodySetAngularVel(masterbody,0,0,0)
				dBodySetRotation(MasterBody,0,0,0)
			dJointGroupEmpty(ContactGroup)
			
			
		Next

		
		PhysicsTime#=MilliSecs()-PTime
		jointlimits(750)
	End If

	;-----------------------------------------------
	; FPS
		If T > Time4 + 1000 Then
			Time4=T	
			FPS=Frames
			frames=0
		End If
		frames=frames+1
    ;-----------------------------------------------
	; render world every loop

	RenderWorld

	;label 'the player'
	CameraProject camera,dGeomGetPositionX#(MasterGeom), dGeomGetPositionY#(MasterGeom)+size#*2, dGeomGetPositionZ#(MasterGeom)
	x = ProjectedX#()
	y = ProjectedY#()

	;debug
	Color 220,220,220
	Text 5,0,"JV-ODE Version "+dGetVersion()
	Text 5,15,"Physics Time:"+PhysicsTime
	Text 5,30,"FPS: "+FPS
	Text GraphicsWidth()/2,75,"Press ENTER for more boxes", 1
	Text GraphicsWidth()/2,90,"Press SPACEBAR to add breakable tables!", 1

	Color 250,220,0
	Text GraphicsWidth()/2,50,"USE LEFT MOUSE BUTTON TO POSITION & MOVE THE WHITE 'PLAYER' CUBE!", 1

	Color 255,255,255
	If x>0 And y>0 Then Text x,y,"PLAYER",1,0
	;show
	Flip 0

Wend

dJointGroupDestroy(ContactGroup)
dSpaceDestroy(Space)
dWorldDestroy(World)
dCloseODE()

End

; ###################################################################################################

Function Create3D()

;| Default 3d scene

	; ### Create light
	Light=CreateLight()
	RotateEntity Light,45,-90,0
	LightColor Light,255,255,255
	AmbientLight 130,130,130

	; ### Create camera
	camerapivot = CreatePivot()
	Camera=CreateCamera(camerapivot)
	CameraZoom camera, 1.5
	CameraClsColor Camera,0,0,0
	CameraRange Camera,0.01,250
	PositionEntity Camera,-5,7,-7
	PositionEntity camerapivot, 0,1,0
	PointEntity camera, camerapivot
	;make top text readable
	CameraFogColor camera, 0,0,0
	CameraFogRange camera, 5,30
	CameraFogMode camera, 1

	; ### Create plane
	dCreatePlane(Space,0,1,0,0)
	Plane=CreatePlane()
	EntityAlpha Plane,0.95
	EntityPickMode plane, 2, True
	PlaneTexture=CreateTexture(128,128,9)
	ClsColor 220,210,200
	Cls
	Color 150,120,110
	Rect 0,0,64,64,1
	Rect 64,64,64,64,1
	CopyRect 0,0,128,128,0,0,BackBuffer(),TextureBuffer(PlaneTexture)
	ScaleTexture PlaneTexture,5,5
	EntityTexture Plane,PlaneTexture,0,0
	Mirror=CreateMirror()
	Color 255,255,255

End Function

; ###################################################################################################

Function AddDoor(x#,y#,z#, w#,h#,d#, weight#=5)

	doorframe# = 0.02		; Depending on the thickness of the door, need a little space between door & frame
							;(because the hinge is in the center (zaxis) of the door, in stead of on an end.

	; ALSO, the door itself needs to be a centimeter or so from the floor, else it will drag
	; and leave nasty marks on the floor!

	ode.odeGeom = New odeGeom

	ode\body=dBodyCreate(World)
	dBodySetRotation(ode\body,0,0,0)
	dBodySetPosition(ode\body,x#,y#+0.01,z#)
	ode\geom=dCreateBox(Space,w#,h#-0.02,d#)
	dGeomSetBody(ode\geom,ode\body)
	ode\mesh=CreateCube()
	ScaleMesh ode\mesh,w#/2,h#/2-0.02,d#/2
	EntityColor ode\mesh,100,0,120
	EntityAlpha ode\mesh,1
	EntityShininess ode\mesh,0.7
	mass = dMassCreate()
	dMassSetBoxTotal mass, weight#, w#,h#-0.02,d#
	dBodySetMass ode\body, mass
	dMassDestroy mass
	;add hinge joint to the door
	joint=dJointCreateHinge(World,0)
	dJointAttach joint, 0, ode\body
	dJointSetHingeAxis joint, 0,1,0
	dJointSetHingeAnchor joint, x#+w#/2,y#,z#
	dJointSetHingeParam joint, dParamLoStop, -0.5 * 3.14		;1pi = 180 degrees
	dJointSetHingeParam joint, dParamHiStop,  0.5 * 3.14

	;wall dimensions
	ww# = 5.0
	wh# = h#
	wd# = 0.25

	;add wall segment - right of door (geometry only!)
	ode.odeGeom = New odeGeom
	ode\body=0	; nobody here!
	ode\geom=dCreateBox(Space,ww#,wh#,wd#)
	dGeomSetPosition ode\geom, x#+w#/2+ww#/2+doorframe#,y#,z#
	ode\mesh=CreateCube()
	ScaleMesh ode\mesh,ww#/2, wh#/2, wd#/2
	EntityColor ode\mesh,100,100,100
	EntityShininess ode\mesh,0.7

	;add wall segment - left of door (geometry only!)
	ode.odeGeom = New odeGeom
	ode\body=0	; nobody here!
	ode\geom=dCreateBox(Space,ww#,wh#,wd#)
	dGeomSetPosition ode\geom, x#-w#/2-ww#/2-doorframe#,y#,z#
	ode\mesh=CreateCube()
	ScaleMesh ode\mesh,ww#/2, wh#/2, wd#/2
	EntityColor ode\mesh,100,100,100
	EntityShininess ode\mesh,0.7

End Function


; ###################################################################################################

Function AddObject(xp#=666,zp#=666)

	size# = Rnd#(0.25,0.65)
	range# = 0.5

	If xp#=666 Then xp=Rand(-range#,range#)
	yp#=Rand(7,15)
	If zp#=666 Then zp=Rand(-range#,range#)

	ode.ODEGeom=New ODEGeom

	ode\body=dBodyCreate(World)
	dBodySetRotation(ode\body,0,0,0)
	dBodySetPosition(ode\body,xp#,yp#,zp#)
	ode\geom=dCreateBox(Space,size#,size#,size#)
	dGeomSetBody(ode\geom,ode\body)
	ode\mesh=CreateCube()
	ScaleMesh ode\mesh,size#/2,size#/2,size#/2
	EntityColor ode\mesh,Rand(255),Rand(255),Rand(255)
	EntityAlpha ode\mesh,1
	EntityShininess ode\mesh,0.7
	mass = dMassCreate()
	dMassSetBoxTotal mass, 10.0, size#,size#,size#
	dBodySetMass ode\body, mass
	dMassDestroy mass

End Function

; ###################################################################################################

Function AddTable(xp#, yp#, zp#, w#,h#,d#)

;# Creates a table with 4 legs - breakable legs! :)

	w# = Rnd(w#*0.5,w#*1.5)		;add some variation to the table's dimensions
	h# = Rnd(h#*0.5,h#*1.5)
	d# = Rnd(d#*0.5,d#*1.5)

	;table top dimensions
	th# = h# * 0.1

	;leg dimensions
	lw# = w#*0.1
	lh# = h#*0.9
	ld# = d#*0.1

	;create tabletop
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#, yp#, zp#
	dBodySetRotation ode\body, 0,0,0

	ode\geom=dCreateBox(space,w#,th#,d#)
	dGeomSetBody ode\geom, ode\body	

	ode\mesh=CreateCube()
	EntityColor ode\mesh, 100,50,0
	ScaleMesh ode\mesh, w#/2,th#/2,d#/2
	
	mass = dMassCreate()
	dMassSetBoxTotal mass, 20.0, w#,th#,d#
	dBodySetMass ode\body, mass
	dMassDestroy mass
	
	tableBody = ode\body

	;create leg 1
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#-w#/2+lw#/2, yp#-lh#/2-th#/2, zp#-d#/2+ld#/2
	dBodySetRotation ode\body, 0,0,0

	ode\geom=dCreateBox(space,lw#,lh#,ld#)
	dGeomSetBody ode\geom, ode\body	

	ode\mesh=CreateCube()
	EntityColor ode\mesh, 200,100,0
	ScaleMesh ode\mesh, lw#/2,lh#/2,ld#/2
	
	mass = dMassCreate()
	dMassSetBoxTotal mass, 5.0, lw#,lh#,ld#
	dBodySetMass ode\body, mass
	dMassDestroy mass

	;join the leg to the table
	joint = dJointCreateFixed(world,0)
	dJointAttach joint, tableBody, ode\body
	dJointSetFixed joint
	dJointFeedbackEnable(Joint) ; Allow feedback for breakable joints

	;create leg 2
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#+w#/2-lw#/2, yp#-lh#/2-th#/2, zp#-d#/2+ld#/2
	dBodySetRotation ode\body, 0,0,0

	ode\geom=dCreateBox(space,lw#,lh#,ld#)
	dGeomSetBody ode\geom, ode\body	

	ode\mesh=CreateCube()
	EntityColor ode\mesh, 200,100,0
	ScaleMesh ode\mesh, lw#/2,lh#/2,ld#/2
	
	mass = dMassCreate()
	dMassSetBoxTotal mass, 5.0, lw#,lh#,ld#
	dBodySetMass ode\body, mass
	dMassDestroy mass

	;join the leg to the table
	joint = dJointCreateFixed(world,0)
	dJointAttach joint, tableBody, ode\body
	dJointSetFixed joint
	dJointFeedbackEnable(Joint) ; Allow feedback for breakable joints
	
	;create leg 3
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#+w#/2-lw#/2, yp#-lh#/2-th#/2, zp#+d#/2-ld#/2
	dBodySetRotation ode\body, 0,0,0

	ode\geom=dCreateBox(space,lw#,lh#,ld#)
	dGeomSetBody ode\geom, ode\body	
	ode\mesh=CreateCube()
	EntityColor ode\mesh, 200,100,0
	ScaleMesh ode\mesh, lw#/2,lh#/2,ld#/2
	mass = dMassCreate()
	dMassSetBoxTotal mass, 5.0, lw#,lh#,ld#
	dBodySetMass ode\body, mass
	dMassDestroy mass

	;join the leg to the table
	joint = dJointCreateFixed(world,0)
	dJointAttach joint, tableBody, ode\body
	dJointSetFixed joint
	dJointFeedbackEnable(Joint) ; Allow feedback for breakable joints

	;create leg 4
	ode.odegeom = New odegeom
	ode\body = dBodyCreate(world)
	dBodySetPosition ode\body, xp#-w#/2+lw#/2, yp#-lh#/2-th#/2, zp#+d#/2-ld#/2
	dBodySetRotation ode\body, 0,0,0

	ode\geom=dCreateBox(space,lw#,lh#,ld#)
	dGeomSetBody ode\geom, ode\body	
	ode\mesh=CreateCube()
	EntityColor ode\mesh, 200,100,0
	ScaleMesh ode\mesh, lw#/2,lh#/2,ld#/2
	mass = dMassCreate()
	dMassSetBoxTotal mass, 5.0, lw#,lh#,ld#
	dBodySetMass ode\body, mass
	dMassDestroy mass

	;join the leg to the table
	joint = dJointCreateFixed(world,0)
	dJointAttach joint, tableBody, ode\body
	dJointSetFixed joint
	dJointFeedbackEnable(Joint) ; Allow feedback for breakable joints

End Function


; ###################################################################################################

Function UpdateGeoms()

	For ode.ODEGeom=Each ODEGeom

		RotateEntity ode\mesh,dGeomGetPitch#(ode\geom),dGeomGetYaw#(ode\geom),dGeomGetRoll#(ode\geom)
		PositionEntity ode\mesh,dGeomGetPositionX#(ode\geom),dGeomGetPositionY#(ode\geom),dGeomGetPositionZ#(ode\geom)

		If ode\body <> 0 Then
			If dBodyIsEnabled(ode\body)
;				EntityColor ode\mesh, 0,255,0
			Else
;				EntityColor ode\mesh, 255,0,0		
			End If
		EndIf

		;remove if object falls off the world
		If dGeomGetPositionY#(ode\geom) < -100 Then
			DebugLog "body "+Handle(ode)+" deleted"
			dGeomDestroy ode\geom
			dBodyDestroy ode\body
			FreeEntity ode\mesh
			Delete ode
		EndIf
	Next

End Function

; ###################################################################################################

Function JointLimits(limit)

For ode.ODEGeom=Each ODEGeom
	If dGeomIsEnabled(ode\geom) And ode\body <> 0
 		numjoints=dBodyGetNumJoints(ode\body)
		If numjoints>0 
			For joints=0 To numjoints-1
				joint=dBodyGetJoint(ode\body,joints)
					If joint<>0 ; valid joints only
						If dJointFeedbackIsEnabled(Joint)=1
							; Get linear velocity vector
							dJointGetFeedbackForce1(Joint)
							If Abs(dVectorX())>limit Or Abs(dVectorY())>limit Or Abs(dVectorZ())>limit
								dJointAttach(joint,0,0) ; break joint
							Else
								dJointGetFeedbackForce2(Joint)
								If Abs(dVectorX())>limit Or Abs(dVectorY())>limit Or Abs(dVectorZ())>limit
									dJointAttach(joint,0,0) ; Break joint
								Else
									dJointGetFeedbackTorque1(Joint)
									If Abs(dVectorX())>limit Or Abs(dVectorY())>limit Or Abs(dVectorZ())>limit
										dJointAttach(joint,0,0) ; Break joint				
									Else
										dJointGetFeedbackTorque2(Joint)
										If Abs(dVectorX())>limit Or Abs(dVectorY())>limit Or Abs(dVectorZ())>limit
											dJointAttach(joint,0,0) ; Break joint
										End If	
									End If
										
								End If		
							End If			
					
						End If
				End If
			Next
		End If
	End If
Next

End Function


Danny. To move a ragdoll I move the head and then cycle through all the component objects and move them the same displacement (head's new positon - head's old position). I move the joints the same amount.

Rotating limbs gets a lot more tricky. It should be possible to create joint handlers that rotate joints based on an objects position (think a sphere placed at each joint that you can click and drag).

The tricky bit with ragdolls is keeping the object and joint alignments in sync when you want to save their posture. Object's rotation and positon is taken from the centre, while joints are at the end. If you think of a thigh bone (cube) hanging straight down, to rotate it so it sticks 90 degrees forwards, the joint at the hip is rotated 90 degrees easy enough. But the thigh cube is rotated 90 degrees AND moved up and out. If you just rotate the thigh cube it'll be all wrong. Hence for ragdolls there's cases where you need to destroy and rebuild the whole jointed model.

I haven't totally mastered joints. If I create a seesaw with motor forces so it spins around, I can move the seesaw and reposition the joint. eg. If I create a box (20,2,70) in size at (0,100,0) with a hinge joint at (0,0,0) on the x axis, with forces, it spins fine. If I then set the box's position to (30,100,0) and the joint's position to (30,100,0), the joint goes mental. I hack a workaround by saving the object and joint's new positions and then rebuilding the scene.

I haven't identified the cause of the problem. Checking the joint and body positons with dJoint...() and dBody...() functions show they align. As I've a workable solution for my needs I haven't looked further into it.

Thanks for the tips, and I hear what you're saying Shifty, I've made a key-frame animated / partially IK driven ragdoll before using Tokamak.
So I know how tricky it is to get a proper animation working in different circumstances;
I experimented with several different ways to keyframe limbs (in relation to another) etc. with mixed success. To makes things easier I also wanted to be able to re-use animations on different characters with different proportions! Again, mixed results; haven't found 'the perfect way' yet. I'll defenitly be spending some time trying to sort this out...

I'd like to experiment with motors as well. That WAS actually the whole reason why I switched to ODE, because I was trying to build little robots if your like, that propel themselves by building leg-type constructs with motors on them. Really funny stuff to watch those critters stumble around - but it was all too limited so in the end rather useless really.. :/

But first, I'll try and move that doll like you said. Sounds like there's no choice but to FORCE the position on ALL bodies (and thus inderectly the joints as well) using BodySetPosition as opposed to using Forces...

Danny-

I don't understand ODE motors. I just applied forces to joints using

dJointSet...Param(dParamVel)
dJointSet...Param(dParamFMax)

At a guess, the joints have a motor object bydefault that's an angular motor, but it's not clear to me what and how the Motor functions are and should be used.

Hi Shifty,

I've managed to get some motor's working. Forget about using 'AMotor' - couldn't get that to work ;)
But create a HingeJoint, and like you set yourself, use the dParamVel and dParamFMax to add an angular velocity to the hinge joint.

I'll post a little example demo in a few minutes...
Danny

[edit] Shifty, check out http://www.blitzbasic.com/Community/posts.php?topic=56125 for the demo