Wheel Positioning.
Because the code required for each wheel is very similar this is split, first we have a small function:
local function PositionWheels( v, xA, yA, zA )
for i = 1, 4 do
PositionWheel( i, v, xA, yA, zA )
end
end
-- don't think this needs much explanation!
And then the biggy which does all the hard work:
-- first a little list to help simplify the code a bit, for a given wheel number this simply
-- indicates whether it is a front or rear wheel
local turnDir = { 'F', 'R', 'F', 'R' }
-- couple of quats for working with
local rotQuat = nil
local finQuat = nil
local function PositionWheel( num, v, xA, yA, zA )
-- we need our wheel offsets again, this time we use the passed in index
-- to get the appropriate list for the wheel we are working on
local wo = wheelOffsets[num]
-- more rotational geometry, we calculated these before so could have stored
-- them for future use but that would overcomplicate the code
local xo, yo, zo = Rotate3D( wo.x, wo.y, wo.z, xA, yA, zA )
-- we did store the individual wheel height though ao now we use it to work out
-- how high or low (within sensible limits) to put the wheel
local suspensionOffset = wheelHeights[num]
if suspensionOffset > 4 then suspensionOffset = 4 end
if suspensionOffset < -4 then suspensionOffset = -4 end
-- now we can position the individual wheel on it's axle
ResetPosition( v.wheels[num].Ent, v.x + xo,
v.y + yo - suspensionOffset,
v.z + zo );
-- and depending on whether the wheel is a front left or front
-- right turn the wheel to match the turn angle
-- also we need to flip the wheel over so the hub is on the outside
if turnDir[num] == 'F' then
if num == 1 then
finQuat = Q.FromEuler( 0, rad( v.turnAng ), 0 )
else
finQuat = Q.FromEuler( 0, rad( -v.turnAng ), rad( 180 ) )
end
else
-- rear wheel don't turn but we still need to flip one of them
if num == 2 then
finQuat = Q.FromEuler( 0, 0, 0 )
else
finQuat = Q.FromEuler( 0, 0, rad( 180 ) )
end
end
-- at this point the quaternion we have calculated, finQuat,
-- represents the angles needed to turn and flip the wheel
-- entity so now we need to give a bit of tilt relative to the
-- suspension travel, again within reasonable limits
if num < 3 then suspensionOffset = -suspensionOffset end
-- now multiply the quaternion representing the direction of
-- travel of the vehicle with 'finQuat' to work out the anmgles
-- at which to put the wheel in 'world' terms
-- (note that the order of multiplication matters!)
finQuat = Q.Mul( v.quat, finQuat )
-- phew, all we have to do now is rotate the wheel! rotAng
-- represents how far around the axis to rotate
if num > 2 then
rotQuat = Q.FromEuler( rad( -v.rotAng ), 0, rad( suspensionOffset * 2 ) )
else
rotQuat = Q.FromEuler( rad( v.rotAng ), 0, rad( suspensionOffset * 2 ) )
end
-- note that the wheels on one side of the car rotate in the opposite
-- direction from the ones on the other side and we factor in the tilt
-- amount at the same time
-- update the rotation abgle for next time, this is a simple calculation,
-- no wheel spin I'm afraid (well not yet anyhow)
v.rotAng = v.rotAng - v.speed / 10
if v.rotAng < -180 then
v.rotAng = v.rotAng + 360
elseif v.rotAng > 180 then
v.rotAng = v.rotAng - 360
end
-- now multiply with our earlier quaternion to give the final
-- representation
finQuat = Q.Mul( finQuat, rotQuat )
-- and convert back to Euler angles so we can tell GG
local xA, yA, zA = Q.ToEuler( finQuat )
ResetRotation( v.wheels[num].Ent, deg( xA ), deg( yA ), deg( zA ) )
end
Short break then I'll continue, need some liquid refreshment!
Been there, done that, got all the T-Shirts!