JV-ODE: Break my tables!

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

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