Verlet physics applied to a simple car model.

Blitz3D Forums/Blitz3D Programming/Verlet physics applied to a simple car model.

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.

ok heres a big update. lots of stuff fixed. read top of code for details.

;credit: miracle did the original port of verlet physics To BB. this code is based on that port.
;aug 27 03
;fixed per verlet friction contact friction
;added slip state to tires
;roll over in the ROLL axis problem much improved. still has problem with pitch roll over.
;moved z axis force from pivot to per verlet calculation
;cleaned up a bunch of junk code.
;changed chase cam to be more exciting - well ok its not exciting but it move more lol. it does however have a problem when car is upside down.
;fixed frozen front wheel.

Graphics3D HEIGHT,WIDTH,16,2
Const HEIGHT=640					; graphics width
Const WIDTH=480					; graphics height
Const ACTIVE=1					; collision type
Const VERLET=2					; collision Type
Const FRONT_TIRE=0				; Vobject part name
Const REAR_TIRE=1					; Vobject part name
Const BODY=2						; Vobject part name
Const CENTER=3					; Vobject part name
Const SIZE#=8					; just a multiplier for how big the Vobject will be
Const ITERATIONS = 2				; How many loops through the "relaxation" routine, Lower = speed up / lose accuracy
Global DeltaTime#					; Time between physics calculations
Global vGrav.Vector = Vector(0.0,9,0.0)	; Gravity. yes i know its a positive value. still dont know why this is but it works.
Global vTemp1.Vector = Vector(0,0,0)	; Some temporary vectors for calculations
Global vTemp2.Vector = Vector(0,0,0)
Global world_friction#=0				; air resistance
Global temp_turn#=0
front_stiff=20						; This is actually the mass value for the front wheel. lower mass = less stiff. caution will collapse
rear_stiff=30						; This is actually the mass value for the rear wheel. lower mass = less stiff. caution will collapse

Type Vector
	Field x#
	Field y#
	Field z#
End Type

Type VerletPack							
	Field start_loc.vector					; Defines where this verlet started at so we can fix it when it gets to far out of place
	Field current.Vector						; Current position
	Field old.Vector						; Last position
	Field gravity.Vector						; Accumulated forces
	Field radius#							; Collider radius
	Field mass.vector						; Point mass of this particular verlet
	Field entity							; Pivot assigned to this verlet for both position and collision
	Field mesh							; Mesh assigned to this verlet if any such as wheels or body parts
	Field part								; Describes what verlet represents. example wheel or body part.
	Field state							; Collideable status true/false	
	Field contact_friction#					; When in contact with the ground how much friction is applied
	Field traction							; true if tire is sticking, false if its skidding
End Type

Type Constraint							; Two verlets connected by a mutual spring
	Field v1.VerletPack						; First verlet
	Field v2.VerletPack						; Second verlet
	Field d#								; Distance between verlets
End Type

Type Vobject								; This is the parent object that the verlets are associated with
	Field v.VerletPack[8]					; The array of individual verlets
	Field num_verlets						; Total number of verlets (array dim value)
	Field player_pivot						; Pivot used to represent player. this pivot is dynamically controlled by player.
	Field player							; Mesh used to represent the player. this mesh is parented to player_pivot
	Field center.VerletPack					; Used to position player_pivot but not neccessarily parented to.
	Field x1.VerletPack						; x1 and x2 are used to define a vector left/right to align player_pivot
	Field x2.VerletPack
	Field z1.VerletPack						; z1 and z2 are used to define a vector forward/aft to align player_pivot
	Field z2.VerletPack
	Field X_vec#							; vectors for calculations
	Field Y_vec#
	Field Z_vec#
	Field mass#							; Mass for physics calculation on entire Vobject
	Field horsepower#						; Force for physics calculations on entire Vobject
	Field acceleration#						; Rate at which the Vobject accelerates
End Type

;***** make the vehicle ****************************************
	tempx# = 0							;start location of vehicle
	tempy# = 20							;start location of vehicle
	tempz# = 150							;start location of vehicle
	Global car.Vobject = New Vobject 			;initialize the Vobject type
	car\player_pivot=CreatePivot()			;this is the master pivot that the player will contol
	car\player=CreateCube(car\player_pivot)	;mesh that is assigned to player_pivot. in this case a simple cube for a car body
	ScaleEntity car\player, 15,6,30			;get car body into postion and scaled etc
	EntityColor car\player, 255,0,0
	PositionEntity car\player, 0, 2, -6
	car\num_verlets = 8						;total number of verlets in the Vobject. count from zero
	car\mass=10							;this mass value is used for physics calculations on player_pivot.
	car\horsepower = 500					;the force exerted on z axis,local to pivot, of verlet
	sx# = 1.9								;just a multiplier for the Vobject size
	sy# = 1.2								;just a multiplier for the Vobject size
	sz# = 2.65							;just a multiplier for the Vobject size
	
	;parameters   x,y,z,radius, mass, part,mesh,state,collision_type, contact_friction
	a.VerletPack = Verlet(tempx - SIZE * sx, tempy - SIZE * sy, tempz - SIZE * sz,  7, front_stiff, FRONT_TIRE, CreateCylinder(12), True, VERLET, .01)
	b.VerletPack = Verlet(tempx + SIZE * sx, tempy - SIZE * sy, tempz - SIZE * sz, 7, front_stiff, FRONT_TIRE, CreateCylinder(12), True, VERLET, .01)
	c.VerletPack = Verlet(tempx + SIZE * sx, tempy + SIZE * sy, tempz - SIZE * sz, 7, 400.0, BODY, 0, True, VERLET, .07)
	d.VerletPack = Verlet(tempx - SIZE * sx, tempy + SIZE * sy, tempz - SIZE * sz, 7, 400.0, BODY, 0, True, VERLET, .07)
	e.VerletPack = Verlet(tempx - SIZE * sx, tempy - SIZE * sy, tempz + SIZE * sz, 9, rear_stiff, REAR_TIRE, CreateCylinder(12), True, VERLET, .01)
	f.VerletPack = Verlet(tempx + SIZE * sx, tempy - SIZE * sy, tempz + SIZE * sz, 9, rear_stiff, REAR_TIRE, CreateCylinder(12), True, VERLET, .01)
	g.VerletPack = Verlet(tempx + SIZE * sx, tempy + SIZE * sy, tempz + SIZE * sz, 7, 400.0, BODY, 0, True, VERLET, .07)
	h.VerletPack = Verlet(tempx - SIZE * sx, tempy + SIZE * sy, tempz + SIZE * sz, 7, 400.0, BODY, 0, True, VERLET, .07)
	i.VerletPack = Verlet(tempx, tempy + 5, tempz + 8, 7, 400.0, CENTER, 0, False, VERLET, 0)
	
	; Edges
	Constraint2(a,b)
	Constraint2(b,c)
	Constraint2(a,d)
	Constraint2(c,d)
	Constraint2(e,f)	
	Constraint2(f,g)
	Constraint2(e,h)
	Constraint2(g,h)
	Constraint2(a,e)
	Constraint2(b,f)
	Constraint2(c,g)
	Constraint2(d,h)

	; Cross-faces
	Constraint2(a,c)
	Constraint2(b,d)
	Constraint2(e,g)
	Constraint2(f,h)
	Constraint2(a,f)
	Constraint2(a,h)
	Constraint2(b,e)
	Constraint2(b,g)
	Constraint2(c,f)
	Constraint2(c,h)
	Constraint2(d,e)
	Constraint2(d,g)

	; Diagonals
	Constraint2(a,g)
	Constraint2(b,h)
	Constraint2(c,e)
	Constraint2(d,f)
	
	; Constraining the center sphere
	Constraint2(a,i)
	Constraint2(b,i)
	Constraint2(c,i)
	Constraint2(d,i)
	Constraint2(e,i)
	Constraint2(f,i)
	Constraint2(g,i)
	Constraint2(h,i)

	; Assign individual verlets to the array	
	car\v[0] = i
	car\v[1] = a
	car\v[2] = b
	car\v[3] = c
	car\v[4] = d
	car\v[5] = e
	car\v[6] = f
	car\v[7] = g
	car\v[8] = h
	
	; assign a verlet the center position
	car\center=i
	; Set up variables used for player mesh/pivot aligntovector. one is left to right, other is forward back.
	car\x1=c
	car\x2=d
	car\z1=g
	car\z2=c
	
	PositionEntity car\player_pivot, EntityX(car\center\entity),EntityY(car\center\entity),EntityZ(car\center\entity)
	measure_pivots(car.Vobject, 0)
;****** end make vehicle *******************************************************************


Collisions VERLET,ACTIVE,2,2
MoveMouse WIDTH/2,HEIGHT/2

lgt = CreateLight()
LightColor lgt,300,300,300
RotateEntity lgt,35,0,0
AmbientLight 94,94,80
Global cam = CreateCamera()
CameraFogMode cam,0
CameraFogColor cam,128,128,180
CameraClsColor cam,128,128,180
CameraRange cam,1,4000
CameraFogRange cam,500,3000
CameraZoom cam,1.25

bump=CreateCylinder(4)
ScaleEntity bump, 5,600,20
RotateEntity bump,0,0,90
EntityType bump, ACTIVE
EntityColor bump,0,255,0
PositionEntity bump,0,0,-500
PositionEntity CopyEntity(bump),0,0,-600
PositionEntity CopyEntity(bump),0,0,-700
PositionEntity CopyEntity(bump),0,0,-800
PositionEntity CopyEntity(bump),0,0,-900

jump=CreateCube()
ScaleEntity jump,200,100,100
RotateEntity jump,15,0,0
PositionEntity jump,0,-70,-600
EntityType jump,ACTIVE

landing=CreateCube()
ScaleEntity landing,200,100,100
RotateEntity landing,15,180,0
PositionEntity landing,0,-70,-1000
EntityType landing,ACTIVE

grid_tex=CreateTexture( 256,256,1+4+8 )
SetBuffer TextureBuffer( grid_tex )
ScaleTexture grid_tex,500,500
Color 255,255,255:Rect 0,0,256,256,False
grid_tex2=CreateTexture( 32,32,1+8 )
SetBuffer TextureBuffer( grid_tex2 )
ScaleTexture grid_tex2,50,50
Color 0,0,255:Rect 0,0,32,32,False
SetBuffer BackBuffer()
flr=CreatePlane()
EntityType flr,ACTIVE
EntityTexture flr,grid_tex,0,1
EntityTexture flr,grid_tex2,0,0
TextureBlend grid_tex,3
EntityBlend flr,1
EntityAlpha flr,.6
EntityFX flr,1
PositionEntity flr,0,0,0

ScaleEntity car\v[1]\mesh,car\v[1]\radius,car\v[1]\radius/2,car\v[1]\radius
RotateEntity car\v[1]\mesh,0,0,90
PositionEntity car\v[1]\mesh,0,0,0

ScaleEntity car\v[2]\mesh,car\v[2]\radius,car\v[2]\radius/2,car\v[2]\radius
RotateEntity car\v[2]\mesh,0,0,90
PositionEntity car\v[2]\mesh,0,0,0

ScaleEntity car\v[5]\mesh,car\v[5]\radius,car\v[5]\radius/2,car\v[5]\radius
RotateEntity car\v[5]\mesh,0,0,90
PositionEntity car\v[5]\mesh,0,0,0

ScaleEntity car\v[6]\mesh,car\v[6]\radius,car\v[6]\radius/2,car\v[6]\radius
RotateEntity car\v[6]\mesh,0,0,90
PositionEntity car\v[6]\mesh,0,0,0

;********* functions defined ********************************************

; measure the start locations for each verlet so it can be fixed if it collapses
Function measure_pivots(name.Vobject, center_element)
	For count=1 To name\num_verlets
		If name\v[count]\part <> CENTER Then
			EntityParent name\v[count]\entity, name\v[center_element]\entity
			name\v[count]\start_loc\x=EntityX(name\v[count]\entity)
			name\v[count]\start_loc\y=EntityY(name\v[count]\entity)
			name\v[count]\start_loc\z=EntityZ(name\v[count]\entity)
			EntityParent name\v[count]\entity, 0
		Else
			name\v[count]\start_loc\x=0
			name\v[count]\start_loc\y=0
			name\v[count]\start_loc\z=0
		End If
	Next
End Function

; use this function to fix a collapsed Vobject
Function fix_verlet(name.Vobject)
	For count=1 To name\num_verlets
		EntityParent name\v[count]\entity, name\center\entity
		tempx# = name\v[count]\start_loc\x + name\center\current\x
		tempy# = name\v[count]\start_loc\y + name\center\current\y
		tempz# = name\v[count]\start_loc\z + name\center\current\z
		PositionEntity name\v[count]\entity, tempx, tempy, tempz
		name\v[count]\current\x = tempx
		name\v[count]\current\y = tempy
		name\v[count]\current\z = tempz
		name\v[count]\old\x = tempx
		name\v[count]\old\y = tempy
		name\v[count]\old\z = tempz
		EntityParent name\v[count]\entity, 0
	Next
End Function

Global crash, debugx#
Function DoVerlet(name.Vobject, accelerator)
	For count = 0 To name\num_verlets
		If (name\v[count]\part = REAR_TIRE Or name\v[count]\part = FRONT_TIRE) And CountCollisions(name\v[count]\entity) >0
			TFormVector vgrav\x, vgrav\y,  vgrav\z, 0, name\player_pivot
			tempvax# = TFormedX()
			tempvay# = TFormedY()
			tempvaz# = TFormedZ()
			TFormVector name\v[count]\current\x, name\v[count]\current\y,  name\v[count]\current\z, 0, name\player_pivot
			temptempx#= TFormedX()
			temptempy#= TFormedY()
			temptempz#= TFormedZ()
			tempvmx# = TFormedX()
			tempvmy# = TFormedY()
			tempvmz# = TFormedZ()
			TFormVector name\v[count]\old\x, name\v[count]\old\y,  name\v[count]\old\z, 0, name\player_pivot
			tempvoldx# = TFormedX()
			tempvoldy# = TFormedY()
			tempvoldz# = TFormedZ()
			TFormVector EntityX(name\v[count]\entity,True), EntityY(name\v[count]\entity,True),  EntityZ(name\v[count]\entity,True), 0, name\player_pivot
			tempentityx# = TFormedX()
			tempentityy# = TFormedY()
			tempentityz# = TFormedZ()
			debugx=tempvmx - tempvoldx
			If Abs(tempvmx - tempvoldx) > 3 Then
				name\v[count]\traction=False
				tempvmx = tempvmx - ((tempvoldx*.9) + (tempvax * (DeltaTime * DeltaTime))) + (temptempx * .9)
				tempvmy = tempvmy - ((tempvoldy * .9) + (tempvay * (DeltaTime * DeltaTime))) + (temptempy * .9)  
				tempvmz = tempvmz - ((tempvoldz * .9) + ((tempvaz + (accelerator * name\horsepower / name\mass)) * (DeltaTime * DeltaTime))) + (temptempz * .9)
				Else
				name\v[count]\traction=True 
				tempvmx = tempvmx - ((tempvoldx*.1) + (tempvax * (DeltaTime * DeltaTime))) + (temptempx * .1)
				tempvmy = tempvmy - ((tempvoldy * (1- name\v[count]\contact_friction)) + (tempvay * (DeltaTime * DeltaTime))) + (temptempy * (1- name\v[count]\contact_friction))  
				tempvmz = tempvmz - ((tempvoldz * (1- name\v[count]\contact_friction)) + ((tempvaz + (accelerator * name\horsepower / name\mass)) * (DeltaTime * DeltaTime))) + (temptempz * (1- name\v[count]\contact_friction))
			End If
			tempvoldx = temptempx
			tempvoldy = temptempy
			tempvoldz = temptempz
			TFormVector tempvmx, tempvmy,  tempvmz, name\player_pivot, 0
			name\v[count]\current\x = TFormedX()
			name\v[count]\current\y = TFormedY()
			name\v[count]\current\z = TFormedZ()
			TFormVector tempvoldx, tempvoldy,  tempvoldz, name\player_pivot, 0
			name\v[count]\old\x = TFormedX()
			name\v[count]\old\y = TFormedY()
			name\v[count]\old\z = TFormedZ()
			Else
				name\v[count]\gravity\x = vgrav\x
				name\v[count]\gravity\y = vgrav\y
				name\v[count]\gravity\z = vgrav\z
				tempx# = name\v[count]\current\x
				tempy# = name\v[count]\current\y
				tempz# = name\v[count]\current\z
				If CountCollisions(name\v[count]\entity) >0 Then
 					name\v[count]\current\x = name\v[count]\current\x - ((name\v[count]\old\x * (1- name\v[count]\contact_friction)) + (name\v[count]\gravity\x * (DeltaTime * DeltaTime))) + (tempx * (1- name\v[count]\contact_friction))
					name\v[count]\current\y = name\v[count]\current\y - ((name\v[count]\old\y * (1- name\v[count]\contact_friction)) + (name\v[count]\gravity\y * (DeltaTime * DeltaTime))) + (tempy * (1- name\v[count]\contact_friction))
					name\v[count]\current\z = name\v[count]\current\z - ((name\v[count]\old\z * (1- name\v[count]\contact_friction)) + (name\v[count]\gravity\z * (DeltaTime * DeltaTime))) + (tempz * (1- name\v[count]\contact_friction))
					Else
						name\v[count]\current\x = name\v[count]\current\x - (name\v[count]\old\x + (name\v[count]\gravity\x * (DeltaTime * DeltaTime))) + tempx
						name\v[count]\current\y = name\v[count]\current\y - (name\v[count]\old\y + (name\v[count]\gravity\y * (DeltaTime * DeltaTime))) + tempy
						name\v[count]\current\z = name\v[count]\current\z - (name\v[count]\old\z + (name\v[count]\gravity\z * (DeltaTime * DeltaTime))) + tempz
				End If	
				name\v[count]\old\x = tempx
				name\v[count]\old\y = tempy
				name\v[count]\old\z = tempz
		End If
		If name\v[count]\part = FRONT_TIRE Then ;*** steering
			PositionEntity name\v[count]\entity, name\v[count]\current\x, name\v[count]\current\y, name\v[count]\current\z
			EntityParent  name\v[count]\entity, name\player_pivot
			TurnEntity name\player_pivot, 0, temp_turn, 0
			EntityParent  name\v[count]\entity, 0
				
			Else 
				PositionEntity name\v[count]\entity, name\v[count]\current\x, name\v[count]\current\y, name\v[count]\current\z
		End If
	Next
	UpdateWorld
	
	crash=0
	For count = 0 To name\num_verlets
		If (name\v[count]\part = FRONT_TIRE Or REAR_TIRE) And Abs(Name\v[count]\current\y - EntityY(name\v[count]\Entity)) >9 Then crash=crash+1
	Next
	If crash >= 1 Then
		For count = 0 To name\num_verlets
			name\v[count]\current\y=name\v[count]\current\y + 5
			name\v[count]\old\y=name\v[count]\current\y
			PositionEntity name\v[count]\entity, name\v[count]\current\x, name\v[count]\current\y, name\v[count]\current\z
		Next
		UpdateWorld
	End If

	turn_rate = 0
	For count = 0 To name\num_verlets
		If CountCollisions(name\v[count]\entity) And name\v[count]\part = FRONT_TIRE And name\v[count]\traction=True Then
			turn_rate = turn_rate + .5
		End If
		name\v[count]\current\x = EntityX(name\v[count]\entity)
		name\v[count]\current\y = EntityY(name\v[count]\entity)
		name\v[count]\current\z = EntityZ(name\v[count]\entity)
	Next
	For n = 1 To ITERATIONS
		For c.Constraint = Each Constraint
			setDistance(c\v1, c\v2, c\d)
		Next
	Next
	;body and wheel stuff
	PositionEntity name\player_pivot, EntityX(name\center\entity), EntityY(name\center\entity), EntityZ(name\center\entity)
	name\X_vec = EntityX(name\x1\entity) - EntityX(name\x2\entity)
	name\Y_vec = EntityY(name\x1\entity) - EntityY(name\x2\entity)
	name\Z_vec = EntityZ(name\x1\entity) - EntityZ(name\x2\entity)
	AlignToVector name\player_pivot, name\X_vec, name\Y_vec, name\Z_vec, 1
	For count=0 To name\num_verlets
		If name\v[count]\part = FRONT_TIRE Or name\v[count]\part = REAR_TIRE Then
			AlignToVector name\v[count]\entity, name\X_vec, name\Y_vec, name\Z_vec, 1
		End If
	Next
	name\X_vec = EntityX(name\z1\entity) - EntityX(name\z2\entity)
	name\Y_vec = EntityY(name\z1\entity) - EntityY(name\z2\entity)
	name\Z_vec = EntityZ(name\z1\entity) - EntityZ(name\z2\entity)
	AlignToVector name\player_pivot, name\X_vec, name\Y_vec, name\Z_vec, 3
	TFormVector name\v[0]\current\x - name\v[0]\old\x, name\v[0]\current\y - name\v[0]\old\y,  name\v[0]\current\z - name\v[0]\old\z, name\v[0]\entity, name\player_pivot
	TurnEntity name\v[1]\entity, TFormedZ() * name\v[1]\radius, 0, 0, False
	TurnEntity name\v[2]\entity, TFormedZ() * name\v[2]\radius, 0, 0, False
	TurnEntity name\v[5]\entity, TFormedZ() * name\v[5]\radius, 0, 0, False
	TurnEntity name\v[6]\entity, TFormedZ() * name\v[6]\radius, 0, 0, False
End Function

Function SetDistance(v1.VerletPack,v2.VerletPack,dist#)	
		vtemp1\x=v1\current\x - v2\current\x
		vtemp1\y=v1\current\y - v2\current\y
		vtemp1\z=v1\current\z - v2\current\z
		deltalength# = Sqr((vTemp1\x * vTemp1\x) + (vTemp1\y * vTemp1\y) + (vTemp1\z * vTemp1\z))
		If deltalength <= 0.0 deltalength = 0.0000001
		diff# = (deltalength - dist) / deltalength
		txmass# =  v1\mass\x + v2\mass\x
		tymass# =  v1\mass\y + v2\mass\y
		tzmass# =  v1\mass\z + v2\mass\z

		v1\current\x=v1\current\x - vtemp1\x * (diff * (v2\mass\x / txmass)); * (diff+1.2) 
		v1\current\y=v1\current\y - vtemp1\y * (diff * (v2\mass\y / tymass))  * (diff+1)
		v1\current\z=v1\current\z - vtemp1\z * (diff * (v2\mass\z / tzmass)); * (diff+1.2)
		v2\current\x=v2\current\x + vtemp1\x *(diff * (v1\mass\x / txmass)); / (diff+1.2)
		v2\current\y=v2\current\y + vtemp1\y *(diff * (v1\mass\y / tymass))  / (diff+1)
		v2\current\z=v2\current\z + vtemp1\z *(diff * (v1\mass\z / tzmass)); / (diff+1.2)
End Function

Function Verlet.VerletPack(x#,y#,z#,radius#, mass#, part,mesh,state,collision_type, contact_friction#)
	v.VerletPack = New VerletPack
	v\current = Vector(x,y,z)	;current location
	v\old = Vector(x,y,z)	;old location
	v\start_loc = Vector(0,0,0) ; initalize with zeros to be filled later
	v\part=part		;part identifier such as wheel or body
	If radius <= 0.0 radius = 0.01
	v\radius = radius	;collision radius
	If mass <= 0.0 mass = 0.01
	If v\part= FRONT_TIRE Or v\part= REAR_TIRE Then v\mass = Vector(100,mass,100) Else v\mass = Vector(400,400,400)
	v\entity = CreatePivot()	;used as the collision element
	PositionEntity v\entity,x,y,z,True
	v\mesh=mesh		;mesh assigned if any
	If mesh<>0 Then EntityParent  v\mesh, v\entity,True
	v\state=state		;true for collideable, false for non collideable
	If v\state=True Then
		EntityType v\entity, collision_type
		EntityRadius v\entity,radius#
	End If
	v\contact_friction=contact_friction#
	v\gravity = Vector(0.0,0.0,0.0)
	Return v
End Function

Function Constraint2.Constraint(v1.VerletPack,v2.VerletPack)
	c.Constraint = New Constraint
	c\v1 = v1
	c\v2 = v2
	c\d = Sqr((v2\current\x - v1\current\x)^2 + (v2\current\y - v1\current\y)^2 + (v2\current\z - v1\current\z)^2)
	;Return c	; You may need this someday ... we don't for what we have here
End Function

;// Create a Vector
Function Vector.Vector(x#=0.0,y#=0.0,z#=0.0)
	v.Vector = New Vector
	v\x=x
	v\y=y
	v\z=z
	Return v
End Function 

;display directions
While Not KeyHit(57)
	RenderWorld
	Text 20,20, "Tab changes view from mouse look modes to front/side views."
	Text 20,35, "Arrow keys control vehicle.
	Text 20,50, "Escape exits program."
	Text 20,65, "Space bar resets vehicle"
	Text 20,80, "Hit space bar to begin."
	Flip False
Wend

;temp_Vobject2.Vobject = First Vobject
Global turn_rate#=0
DeltaTime#=.09
HidePointer
fRate = (1000/72) ;*set second number to desired frame rate
view=2
;**************** main loop ***************************************	
While Not KeyHit(1)
	time1 = MilliSecs() ;time at start of processing loop
	temp_turn#=0
	accelerator=0
	If KeyDown(203) temp_turn=turn_rate
	If KeyDown(205) temp_turn=-turn_rate
	If KeyDown(200) accelerator=1
	If KeyDown(208) accelerator=-1
	If KeyDown(57) Then 
		vGrav\y=0
		fix_verlet(car.Vobject) 
		Else 
			vGrav.Vector = Vector(0.0,9,0.0)
	End If
		DoVerlet(car.Vobject, accelerator)
	If KeyHit(15) Then 
		view=view+1
		If view >=3 Then view=0
	End If
	PositionEntity cam,EntityX(car\center\entity),EntityY(car\center\entity),EntityZ(car\center\entity)
	tempmousex#=tempmousex-MouseXSpeed()
	tempmousey#=tempmousey+MouseYSpeed()
	Select view
	Case 0 
		RotateEntity cam, tempmousey+10 , tempmousex+180, 0
	Case 1
		RotateEntity cam,tempmousey , EntityYaw(car\player_pivot,True)+90, 0
	Case 2
		RotateEntity cam,EntityPitch(car\player_pivot,True)/4 +15 , EntityYaw(car\player_pivot,True)+180, EntityRoll(car\player_pivot,True) /2
	End Select
	MoveEntity cam,0,0,-150
	MoveMouse WIDTH/2,HEIGHT/2
	
	RenderWorld
	Text 20,20, "lateral velocity: "+debugx
	Delay fRate - (MilliSecs() - time1) ;delay execution
	Flip False
Wend
End