JV-ODE Physics Thread 3

Blitz3D Forums/Blitz3D Userlibs/JV-ODE Physics Thread 3

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.

Pyramid of Destruction II
Add your own sounds for that special touch.
Select different planets and watch gravity at work.
Other features include: Mouse Look, WSAD and arrow keys, Pyramid reconstruction, Mouse pushing, spacebar shooting.

-enjoy

; ###################################################################################################
; #								JV-ODE - Pyramid Destruction Demo											#
; #									Code by Jim Williams (VIP3R)									#
; ###################################################################################################

AppTitle "JV-ODE - Pyramid Destruction II"

Include "JV-ODE.bb"

;Graphics3D 800,600,0,2
Graphics3D 1024,768,32,1


Global ElapsedTime
Global LastTime
Global FrameCount
Global Frames
Global Time

Global Proj
Global Projbody
Global snd1
Global snd2
Global piv1

Global Planet$
Global gx

piv1=CreatePivot()

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,-1.0,0)
Planet="Earth"

dWorldSetERP(World,0.4)
dContactSetMode(dContactBounce)
dContactSetBounce(0.0)
dContactSetMu(80)

; High Performance Settings
; Causes objects to settle down and sleep faster
dWorldSetAutoDisableLinearThreshold (World, .05)
dWorldSetAutoDisableAngularThreshold (World, .05)
dWorldSetAutoDisableSteps (World, 5)
dContactSetMaxContacts(32)
dWorldSetQuickStepNumIterations (World,20)

; ### Create light

Global Light=CreateLight()

RotateEntity Light,45,-90,0
LightColor Light,255,255,255
AmbientLight 130,130,130

; ### Create camera

Global Camera=CreateCamera()
CameraClsColor Camera,0,0,0
CameraRange Camera,1,1000
PositionEntity Camera,30,25,-100
RotateEntity Camera,15,0,0

; ### Load sounds
snd1=Load3DSound("media\Impact.wav")
snd2=LoadSound("media\whizz.wav")

SoundVolume snd2,.2

mic1=CreateListener(camera,.3,1,1) ; Create listener, make it child of camera 

; ### Create plane

dCreatePlane(Space,0,1,0,0)

Plane=CreatePlane()

EntityAlpha Plane,0.8

PlaneTexture=CreateTexture(128,128,9)

ClsColor 0,200,80
Cls

Color 255,255,255

Rect 0,0,64,64,1
Rect 64,64,64,64,1

CopyRect 0,0,128,128,0,0,BackBuffer(),TextureBuffer(PlaneTexture)
ScaleTexture PlaneTexture,20,20
EntityTexture Plane,PlaneTexture,0,0

Mirror=CreateMirror()

; Construct pyramid

Wide=9  ; Number of blocks wide at the base
Gap#=7  ; Gap spacing
RBW#=5  ; Real block width

For j#=wide To 1 Step -1
	For k#=1 To j
		AddObject(k#*Gap+(wide-j#)*Gap/2,RBW/2 + (wide-j#)*RBW)
		bcount=bcount+1
	Next
Next
		
addProjectile(EntityX(camera),EntityY(camera),EntityZ(camera))

		

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

While Not KeyHit(1)

    UpdateControls()

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

; Mouse Look code

; Execute every 25ms ( 40/sec )
If T > Time2 + 25 Then
	Time2=T
	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
	EndIf
EndIf	


	
	PTime=MilliSecs()

	UpdateGeoms()
	

	dSpaceCollide(Space,World,ContactGroup)
	
	UpdateSounds()
	
	dWorldQuickStep(World,0.1)
	
	dJointGroupEmpty(ContactGroup)

	PhysicsTime#=MilliSecs()-PTime

	UpdateWorld

	RenderWorld
	
	Color 255,255,255
	Text 0,0,"JV-ODE Version "+dGetVersion()
	Text 0,15,"Physics Time:"+PhysicsTime
	Text 0,30,"FPS:"+Fps()
	Color 255,0,0
	Text 0,60,"P - Planet="+Planet
	Color 255,255,255
	Text 0,75,"LM - Pushes Object"
	Text 0,90, "RM - Mouse Look"
	Text 0,105, "R  - Reconstruct Pyramid"
	Text 0,120, "WSAD - Movement"
    Text 0,135, "Space - Shoots"

	Flip  

Wend

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

End

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

Function AddObject(x#,height#)

ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)

dBodySetRotation(ode\body,0,0,0)
dBodySetPosition(ode\body,x,Height,0)

dBodySetAutoDisableFlag(ode\body,1)
mass=dMassCreate()
dMassSetBox(mass,1,5,5,5)
dMassSetBoxTotal(mass,20,5,5,5)
dBodySetMass(ode\body,mass)
dMassDestroy(mass)
ode\geom=dCreateBox(Space,5,5,5)
dGeomContactSetMode(ode\geom,dContactBounce)
dGeomContactSetBounce(ode\geom,0.0)
dGeomContactSetSoftERP(ode\geom,0.1)
dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateCube()
ScaleMesh ode\mesh,2.5,2.5,2.5
EntityColor ode\mesh,Rand(255),Rand(255),Rand(255)
EntityAlpha ode\mesh,1
EntityShininess ode\mesh,0.7

EntityPickMode ode\mesh,2 ; Make pickable

End Function

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

Function PosObject(x#,height#, body)

dBodyDisable(body)
dBodySetRotation(body,0,0,0)
dBodySetPosition(body,x,Height,0)
dBodySetLinearVel  (body, 0,0,0)
dBodySetAngularVel (body, 0,0,0)
dBodyEnable(body)

End Function

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

Function AddProjectile(X#,Y#,Z#)

ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)

dBodySetRotation(ode\body,0,0,0)
dBodySetPosition(ode\body,x#,Y#,Z#)

dBodySetAutoDisableFlag(ode\body,1)
mass=dMassCreate()
dMassSetBox(mass,1,5,5,5)
dMassSetBoxTotal(mass,20,5,5,5)
dBodySetMass(ode\body,mass)
dMassDestroy(mass)
ode\geom=dCreateBox(Space,5,5,5)
dGeomContactSetMode(ode\geom,dContactBounce)
dGeomContactSetBounce(ode\geom,0.0)
dGeomContactSetSoftERP(ode\geom,0.1)
dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateCube()
ScaleMesh ode\mesh,2.5,2.5,2.5
EntityColor ode\mesh,Rand(255),Rand(255),Rand(255)
EntityAlpha ode\mesh,1
EntityShininess ode\mesh,0.7

proj=ode\mesh ; ENTITY	
projbody=ode\body

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)
	End If
Next

End Function

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

Function Fps()
Time=MilliSecs()

ElapsedTime=ElapsedTime+Time-LastTime
LastTime=Time
FrameCount=FrameCount+1

If ElapsedTime>1000
	ElapsedTime=0
	Frames=FrameCount
	FrameCount=0
EndIf
Return Frames
End Function 

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

Function UpdateControls()

	If MouseDown(1)=1

	CameraPick(Camera,MouseX(),MouseY())
		If PickedEntity()
			For ode.ODEGeom=Each ODEGeom
				If ode\mesh=PickedEntity()
					dBodyEnable(ode\body)
					dBodyAddForce ode\body,-500*PickedNX#(),-500*PickedNY#(),-500*PickedNZ#()
				End If
			Next
		End If
	End If


	; Spacebar - Fire
	If KeyDown(57) Then
		dBodyDisable(Projbody)
		; Set projectile to match camera orientation
		dBodySetRotation(Projbody,EntityPitch(camera),EntityYaw(camera),EntityRoll(camera))
		dBodySetPosition(Projbody,EntityX(camera),EntityY(camera),EntityZ(camera))
		; Set projectile velocity and spin to zero
		dBodySetLinearVel  (Projbody, 0,0,0)
		dBodySetAngularVel (Projbody, 0,0,0)
		
		dBodyEnable(Projbody)
		dBodyAddRelForce(Projbody,0,0,8000)
		
		PlaySound snd2
	EndIf
	
	; Reconstruct pyramid
	If KeyDown(19) Then
		ode.ODEGeom=First ODEGeom
		
			; Construct pyramid
	
			Wide=9  ; Number of blocks wide at the base
			Gap#=7  ; Gap spacing
			RBW#=5  ; Real block width
			
			For j#=wide To 1 Step -1
				For k#=1 To j
					PosObject(k#*Gap+(wide-j#)*Gap/2,RBW/2 + (wide-j#)*RBW,ode\body)
					ode = After ode
				Next
			Next
			
		
	End If

; WSAD - Movement

; W- Forward
If KeyDown(17) Or KeyDown(200) Then
	MoveEntity camera,0,0,1
EndIf
; S- Reverse
If KeyDown(32) Or KeyDown(208) Then
	MoveEntity camera,0,0,-1
EndIf

; W- Left
If KeyDown(30) Or KeyDown(203) Then
	MoveEntity camera,-1,0,0
EndIf
; S- Right
If KeyDown(32) Or KeyDown(205) Then
	MoveEntity camera,1,0,0
EndIf

; G - Gravity
If KeyHit(25) Then
	gx=gx+1
	If gx>3 Then gx=1
	Select gx
	  Case 1
		Planet="Earth"
		dWorldSetGravity(World,0,-1.0,0)
	
	  Case 2
		Planet="Mars"
		dWorldSetGravity(World,0,-.33333,0)

	  Case 3
		Planet="Moon"
		dWorldSetGravity(World,0,-.16666,0)
		
	End Select
	
EndIf


End Function

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

Function UpdateSounds()

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 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)
					
					;If ForceA>.01
					;	LinearDamp(ode\body,.04)
					;End If
					
					If ForceA>1.0
						PositionEntity piv1,dGeomGetPositionX#(ode\geom),dGeomGetPositionY#(ode\geom),dGeomGetPositionZ#(ode\geom)
						EmitSound(snd1,piv1)
					End If

					;If ForceB>.01
					;	AngularDamp(ode\body,.06)
					;End If
					
				End If
			Next
		End If
	End If
Next

End Function