To get the velocity of the car, you use a pivot and EntityDistance(). Each frame you return the distance between the current car location and the previous car location, the faster the car moves, the further it travels each frame.
Here's a modified car demo which has the above method implemented...
; ###################################################################################################
; # JV-ODE Car Demo #
; # Code by Jim Williams (VIP3R) #
; # Devious Codeworks - Copyright © 2007 #
; ###################################################################################################
AppTitle "JV-ODE 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 Force#=0
Global Steer#=0
Global Car
Global CGeom
Global CMesh
Global PrevPosPivot=CreatePivot()
Global PrevX#=0.0
Global PrevY#=0.0
Global PrevZ#=0.0
Global Velocity#=0.0
Global CarStartY=20
Dim Wheel(4)
Dim WGeom(4)
Dim Joint(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)
; ### Create car body
ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)
Car=ode\body
dBodySetRotation(ode\body,0,0,0)
dBodySetPosition(ode\body,0,CarStartY,0)
mass=dMassCreate()
dMassSetBoxTotal(mass,CMass,3,1,4)
dBodySetMass(ode\body,mass)
dMassDestroy(mass)
ode\geom=dCreateBox(Space,3,1,4)
CGeom=ode\geom
dGeomSetBody(ode\geom,ode\body)
ode\mesh=CreateCube()
CMesh=ode\mesh
ScaleMesh ode\mesh,1.5,0.5,2
RotateMesh ode\mesh,0,0,0
PositionMesh ode\mesh,0,0,0
EntityColor ode\mesh,40,80,255
EntityAlpha ode\mesh,1
; ### Create wheels
For count=1 To 4
ode.ODEGeom=New ODEGeom
ode\body=dBodyCreate(World)
Wheel(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(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(1),-2,CarStartY-0.5,+2)
dBodySetPosition(Wheel(2),+2,CarStartY-0.5,+2)
dBodySetPosition(Wheel(3),-2,CarStartY-0.5,-2)
dBodySetPosition(Wheel(4),+2,CarStartY-0.5,-2)
; ### 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)
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
CalcVelocity()
Text 0,0,"JV-ODE Version "+dGetVersion()
Text 0,15,"Physics Time:"+PhysicsTime
Text 0,50,"Force:"+Force
Text 0,65,"Torque:"+Torque
Text 640,0,"A - Accelerate"
Text 640,15,"Z - Brake/Reverse"
Text 640,30,"Arrows - Steering"
Text 640,45,"Space - Reset Car"
Text 0,100,"Car Velocity:"+Velocity
Text 0,130,"Rotation Velocity (W3):"+dJointGetHinge2Angle2Rate(Joint(3))
Flip
Wend
dJointGroupDestroy(ContactGroup)
dSpaceDestroy(Space)
dWorldDestroy(World)
dCloseODE()
End
; ###################################################################################################
Function SetupCar()
For count=1 To 4
Joint(count)=dJointCreateHinge2(World,0)
dJointAttach(Joint(count),Car,Wheel(count))
dJointSetHinge2Anchor(Joint(count),dBodyGetPositionX(Wheel(count)),dBodyGetPositionY(Wheel(count)),dBodyGetPositionZ(Wheel(count)))
dJointSetHinge2Axis1(Joint(count),0,1,0)
dJointSetHinge2Axis2(Joint(count),-1,0,0)
dJointSetHinge2Param(Joint(count),dParamSuspensionERP,0.8)
dJointSetHinge2Param(Joint(count),dParamSuspensionCFM,SuspensionHS)
If count>2
dJointSetHinge2Param(Joint(count),dParamLoStop,0)
dJointSetHinge2Param(Joint(count),dParamHiStop,0)
End If
Next
Force=0
End Function
; ###################################################################################################
Function CalcVelocity()
PositionEntity PrevPosPivot,PrevX,PrevY,PrevZ
Velocity#=EntityDistance(CMesh,PrevPosPivot)
PrevX#=EntityX(CMesh)
PrevY#=EntityY(CMesh)
PrevZ#=EntityZ(CMesh)
End Function
; ###################################################################################################
Function UpdateKeys()
If KeyDown(30)=1
Force=Force+0.08
If Force>30 Then Force=30
End If
If KeyDown(44)=1
Force=Force-0.1
If Force<-10 Then Force=-10
If Force>0 Then Force=Force*0.97
End If
If KeyDown(30)=0 And KeyDown(44)=0 Then Force=Force*0.99
If KeyDown(203)=1 Or KeyDown(205)=1
If KeyDown(203)=1
Steer=0.5
Else
Steer=-0.5
End If
Else
Steer=0
End If
If KeyHit(57)=1
Force=0
dBodySetRotation(Car,dGeomGetPitch#(CGeom),dGeomGetYaw#(CGeom),0)
End If
End Function
; ###################################################################################################
Function UpdateCar()
For count=1 To 4
dBodyEnable(Wheel(count))
Next
dBodyEnable(Car)
For count=1 To 4
dJointSetHinge2Param(Joint(count),dParamVel2,Force)
dJointSetHinge2Param(Joint(count),dParamFMax2,Torque)
Next
For count=1 To 2
angle#=Steer-dJointGetHinge2Angle1(Joint(count))
dJointSetHinge2Param(Joint(count),dParamVel,angle)
dJointSetHinge2Param(Joint(count),dParamFMax,400)
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
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
; ###################################################################################################
To store the handles of each car body you can use an array, each time you create a car, store a copy of the ode/body handle...
Car(number)=ode\body
The ODE body handle for car number two will then be 'Car(2)'.
As an alternative to arrays you can extend the ODEGeom type to include a car ID number and then cycle through each type to get the ode\body handle.