Here's a two car demo with simple AI controlling the second car.
The 'Force' variable is changed to an array, one for each car...
; ###################################################################################################
; # JV-ODE Twin Car Demo #
; # Code by Jim Williams (VIP3R) #
; # Devious Codeworks - Copyright © 2007 #
; ###################################################################################################
AppTitle "JV-ODE Twin Car Demo"
Include "JV-ODE.bb"
Graphics3D 800,600,0,2
Global CMass#=200 ; ### Car Mass
Global WMass#=14 ; ### Wheel Mass
Global WorldERP#=1 ; ### World Error Correction
Global WorldFriction#=70 ; ### World Friction
Global Torque#=24 ; ### Joint Torque
Global SuspensionHS#=0.01 ; ### Suspension Hardness/Softness (Higher=Softer - Lower=Harder)
Global CarAmount=2
Global ControlTimer=0
Global SteeringTimer=0
Dim Force#(CarAmount)
Dim Steer#(CarAmount)
Dim Car(CarAmount)
Dim CGeom(CarAmount)
Dim CMesh(CarAmount)
Global CarStartY=20
Dim Wheel(CarAmount,4)
Dim WGeom(CarAmount,4)
Dim Joint(CarAmount,4)
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.98,0)
dWorldSetERP(World,WorldERP)
dContactSetMode(dContactSlip1)
dContactSetMu(WorldFriction)
For CarID=1 To 2
; ### Create car body
ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)
Car(CarID)=ode\body
dBodySetRotation(ode\body,0,0,0)
dBodySetPosition(ode\body,CarID*10,CarStartY,0)
mass=dMassCreate()
dMassSetBoxTotal(mass,CMass,3,1,4)
dBodySetMass(ode\body,mass)
dMassDestroy(mass)
ode\geom=dCreateBox(Space,3,1,4)
CGeom(CarID)=ode\geom
dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateCube()
CMesh(CarID)=ode\mesh
ScaleMesh ode\mesh,1.5,0.5,2
RotateMesh ode\mesh,0,0,0
PositionMesh ode\mesh,0,0,0
If CarID=1
EntityColor ode\mesh,40,80,255
Else
EntityColor ode\mesh,180,40,180
End If
EntityAlpha ode\mesh,1
; ### Create wheels
For count=1 To 4
ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)
Wheel(CarID,count)=ode\body
dBodySetRotation(ode\body,0,0,0)
dBodySetPosition(ode\body,0,0,0)
mass=dMassCreate()
dMassSetSphereTotal(mass,WMass,0.7)
dBodySetMass(ode\body,mass)
dMassDestroy(mass)
ode\geom=dCreateSphere(Space,0.7)
WGeom(CarID,count)=ode\geom
dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateCylinder(8)
ScaleMesh ode\mesh,0.7,0.25,0.7
RotateMesh ode\mesh,0,0,90
PositionMesh ode\mesh,0,0,0
EntityColor ode\mesh,255,255,255
Next
dBodySetPosition(Wheel(CarID,1),(CarID*10)-2,CarStartY-0.5,+2)
dBodySetPosition(Wheel(CarID,2),(CarID*10)+2,CarStartY-0.5,+2)
dBodySetPosition(Wheel(CarID,3),(CarID*10)-2,CarStartY-0.5,-2)
dBodySetPosition(Wheel(CarID,4),(CarID*10)+2,CarStartY-0.5,-2)
Next
; ### Create some objects
SeedRnd MilliSecs()
For spheres=1 To 20
ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)
dBodySetRotation(ode\body,0,0,0)
dBodySetPosition(ode\body,Rnd(-100,100),30,Rnd(-100,100))
ode\geom=dCreateSphere(Space,4)
dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateSphere()
ScaleMesh ode\mesh,4,4,4
RotateMesh ode\mesh,0,0,0
PositionMesh ode\mesh,0,0,0
EntityColor ode\mesh,Rnd(255),Rnd(255),Rnd(255)
EntityAlpha ode\mesh,1
EntityShininess ode\mesh,0.7
Next
For capsules=1 To 20
ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)
dBodySetRotation(ode\body,90,0,0)
dBodySetPosition(ode\body,Rnd(-100,100),30,Rnd(-100,100))
ode\geom=dCreateCapsule(Space,1,8)
dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateCylinder(8)
ScaleMesh ode\mesh,1,5,1
RotateMesh ode\mesh,90,0,0 ; <<< Mesh X-Axis must be rotated 90 degrees to fix cylinder alignment
PositionMesh ode\mesh,0,0,0
EntityColor ode\mesh,Rnd(255),Rnd(255),Rnd(255)
EntityAlpha ode\mesh,1
EntityShininess ode\mesh,0.7
Next
; ### Create light
Global Light=CreateLight()
RotateEntity Light,45,-90,0
LightColor Light,255,255,255
AmbientLight 130,130,130
; ### Create camera
Global CameraPivot=CreatePivot(CMesh(1))
PositionEntity CameraPivot,0,2,-7
Global Camera=CreateCamera()
CameraClsColor Camera,0,0,0
CameraRange Camera,1,1000
; ### 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()
; ###################################################################################################
; ### BLITZ STATIC OBJECT (White)
blitzobject=CreateCube()
ScaleMesh blitzobject,1,4,20
RotateMesh blitzobject,-10,8,4
PositionMesh blitzobject,10,5,40
EntityColor blitzobject,255,255,255
EntityAlpha blitzobject,1
; ### ODE STATIC OBJECT (Blue)
ode.ODEGeom=New ODEGeom
ode\geom=dCreateBox(Space,2,8,40)
dGeomSetRotation(ode\geom,-10,8,4)
dGeomSetPosition(ode\geom,20,5,40)
ode\mesh=CreateCube()
ScaleMesh ode\mesh,1,4,20
RotateMesh ode\mesh,0,0,0
PositionMesh ode\mesh,0,0,0
EntityColor ode\mesh,0,100,200
EntityAlpha ode\mesh,1
; ### ODE STATIC OBJECT (Red)
ode.ODEGeom=New ODEGeom
ode\geom=dCreateBox(Space,18,0.2,40)
dGeomSetRotation(ode\geom,-14,0,0)
dGeomSetPosition(ode\geom,-20,4.9,40)
ode\mesh=CreateCube()
ScaleMesh ode\mesh,9,0.1,20
RotateMesh ode\mesh,0,0,0
PositionMesh ode\mesh,0,0,0
EntityColor ode\mesh,200,0,100
EntityAlpha ode\mesh,1
; ###################################################################################################
SetupCar()
While Not KeyHit(1)
UpdateKeys()
PTime=MilliSecs()
UpdateCar()
UpdateGeoms()
dSpaceCollide(Space,World,ContactGroup)
dWorldQuickStep(World,0.1)
dJointGroupEmpty(ContactGroup)
PhysicsTime#=MilliSecs()-PTime
UpdateCam()
UpdateWorld
RenderWorld
Text 0,0,"JV-ODE Version "+dGetVersion()
Text 0,15,"Physics Time:"+PhysicsTime
Text 0,50,"Force Car 1:"+Force(1)
Text 0,65,"Force Car 2:"+Force(2)
Text 0,80,"Torque:"+Torque
Text 640,0,"A - Accelerate"
Text 640,15,"Z - Brake/Reverse"
Text 640,30,"Arrows - Steering"
Text 640,45,"Space - Reset Car"
Flip
Wend
dJointGroupDestroy(ContactGroup)
dSpaceDestroy(Space)
dWorldDestroy(World)
dCloseODE()
End
; ###################################################################################################
Function SetupCar()
For CarID=1 To 2
For count=1 To 4
Joint(CarID,count)=dJointCreateHinge2(World,0)
dJointAttach(Joint(CarID,count),Car(CarID),Wheel(CarID,count))
dJointSetHinge2Anchor(Joint(CarID,count),dBodyGetPositionX(Wheel(CarID,count)),dBodyGetPositionY(Wheel(CarID,count)),dBodyGetPositionZ(Wheel(CarID,count)))
dJointSetHinge2Axis1(Joint(CarID,count),0,1,0)
dJointSetHinge2Axis2(Joint(CarID,count),-1,0,0)
dJointSetHinge2Param(Joint(CarID,count),dParamSuspensionERP,0.8)
dJointSetHinge2Param(Joint(CarID,count),dParamSuspensionCFM,SuspensionHS)
If count>2
dJointSetHinge2Param(Joint(CarID,count),dParamLoStop,0)
dJointSetHinge2Param(Joint(CarID,count),dParamHiStop,0)
End If
Next
Force(CarID)=0
Next
End Function
; ###################################################################################################
Function UpdateKeys()
; ### Player Control For Car 1
If KeyDown(30)=1
Force(1)=Force(1)+0.08
If Force(1)>30 Then Force(1)=30
End If
If KeyDown(44)=1
Force(1)=Force(1)-0.1
If Force(1)<-10 Then Force(1)=-10
If Force(1)>0 Then Force(1)=Force(1)*0.97
End If
If KeyDown(30)=0 And KeyDown(44)=0 Then Force(1)=Force(1)*0.99
If KeyDown(203)=1 Or KeyDown(205)=1
If KeyDown(203)=1
Steer(1)=0.5
Else
Steer(1)=-0.5
End If
Else
Steer(1)=0
End If
If KeyHit(57)=1
Force(1)=0
dBodySetRotation(Car(1),dGeomGetPitch#(CGeom(1)),dGeomGetYaw#(CGeom(1)),0)
End If
; ### Simple AI For Car 2
If ControlTimer>100
SeedRnd MilliSecs()
AIKey=Rnd(100)
If AIKey<40
Force(2)=Force(2)+0.8
If Force(2)>10 Then Force(2)=10
End If
If AIKey=>40 Then Force(2)=Force(2)*0.99
ControlTimer=0
End If
If SteeringTimer>100
SeedRnd MilliSecs()
AIKey=Rnd(100)
Steer(2)=0
If AIKey<30 Then Steer(2)=0.5
If AIKey>70 Then Steer(2)=-0.5
SteeringTimer=0
End If
ControlTimer=ControlTimer+1
SteeringTimer=SteeringTimer+1
End Function
; ###################################################################################################
Function UpdateCar()
For CarID=1 To 2
For count=1 To 4
dBodyEnable(Wheel(CarID,count))
Next
dBodyEnable(Car(CarID))
For count=1 To 4
dJointSetHinge2Param(Joint(CarID,count),dParamVel2,Force(CarID))
dJointSetHinge2Param(Joint(CarID,count),dParamFMax2,Torque)
Next
For count=1 To 2
angle#=Steer(CarID)-dJointGetHinge2Angle1(Joint(CarID,count))
dJointSetHinge2Param(Joint(CarID,count),dParamVel,angle)
dJointSetHinge2Param(Joint(CarID,count),dParamFMax,400)
Next
Next
End Function
; ###################################################################################################
Function UpdateCam()
PositionEntity CameraPivot,0,3,-12
camx#=EntityX(CameraPivot,1)-EntityX(Camera)
camy#=EntityY(CameraPivot,1)-EntityY(Camera)
camz#=EntityZ(CameraPivot,1)-EntityZ(Camera)
TranslateEntity Camera,camx*0.5,camy*0.5,camz*0.5
PointEntity Camera,CMesh(1)
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)
Next
End Function
; ###################################################################################################