Revs on the BBC Micro

# Driving model: ApplyDrivingModel

```       Name: ApplyDrivingModel                                       [Show more]
Type: Subroutine
Category: Driving model
Summary: Apply the driving model to the player's car
Deep dive: An overview of the driving model
The core driving model
Context: See this subroutine in context in the source code
References: This subroutine is called as follows:
* MainDrivingLoop (Part 2 of 5) calls ApplyDrivingModel

.ApplyDrivingModel

LDA playerYawAngleHi   \ Set (A X) = (playerYawAngleHi playerYawAngleLo)
LDX playerYawAngleLo

JSR GetRotationMatrix  \ Calculate the rotation matrix for rotating the
\ player's yaw angle into the global 3D coordinate
\ system, as follows:
\
\   [ cosYawAngle   0   -sinYawAngle ]
\   [      0        1         0      ]
\   [ sinYawAngle   0    cosYawAngle ]

JSR RotateCoordToCar   \ Rotate the player's delta vector from the 3D world
\ coordinate system to the frame of reference of the
\ player's car, putting the result into:
\
\   [ xVelocity ]
\   [     -     ]
\   [ zVelocity ]
\
\ We ignore the y-coordinate as the calculations are
\ all done along the ground

LDA xVelocityLo        \ Set (xPrevVelocityHi xPrevVelocityLo)
STA xPrevVelocityLo    \           = (xVelocityHi xVelocityLo)
LDA xVelocityHi
STA xPrevVelocityHi

LDA zVelocityLo        \ Set (A T) = (zVelocityHi zVelocityLo)
STA T
LDA zVelocityHi

JSR Absolute16Bit      \ Set (A T) = |A T|
\           = |zVelocity|

STA playerSpeedHi      \ Set (playerSpeedHi playerSpeedLo) = (A T)
LDA T                  \                                   = |zVelocity|
STA playerSpeedLo

LDY playerSpeedHi      \ Set Y to the high byte of (playerSpeedHi
\ playerSpeedLo)

BNE dmod1              \ If the high byte is non-zero, jump to dmod1 to skip
\ the following

AND #%11110000         \ A contains playerSpeedLo, so this sets Y to the high
TAY                    \ nibble of the low byte of (playerSpeedHi
\ playerSpeedLo)

.dmod1

STY playerMoving       \ Store Y in playerMoving, which is zero if the player
\ is not moving, non-zero if they are, so this denotes
\ the player as moving if (playerSpeedHi playerSpeedLo)
\ is non-zero, ignoring the bottom nibble of the
\ low byte

JSR ApplySpinYaw       \ Calculate the following:
\
\   xVelocity = xVelocity - (spinYawAngle * 0.34)
\
\   xSpinVelocity = spinYawAngle * 0.52

JSR ApplyGrassOrTrack  \ Apply the effects of driving and braking, depending on
\ the current driving surface (grass or track)

JSR ApplyEngine        \ Apply the effects of the engine

LDX #1                 \ Set X = 1, so the call to ApplyTyresAndSkids processes
\ the rear tyres

JSR ApplyTyresAndSkids \ Calculate the forces on the rear tyres and apply skid
\ forces and sound effects where applicable

LDA xPrevVelocityLo    \ Set (xVelocityHi xVelocityLo) to the x-coordinate of
STA xVelocityLo        \ the velocity vector from the previous iteration of the
LDA xPrevVelocityHi    \ main loop, which we stored in (xPrevVelocityHi
STA xVelocityHi        \ xPrevVelocityLo)

LDA xVelocityLo        \ Set (xVelocityHi xVelocityLo)
CLC                    \                   += (xSpinVelocityHi xSpinVelocityLo)
STA xVelocityLo        \ starting with the low bytes

LDA xVelocityHi        \ And then the high bytes
STA xVelocityHi

JSR ApplySteeringSpeed \ Calculate the following in parallel:
\
\   zVelocity = zVelocity + xVelocity * steering
\
\   xVelocity = xVelocity - zVelocity * steering

LDX #0                 \ Set X = 0, so the call to ApplyTyresAndSkids processes
\ the front tyres

JSR ApplyTyresAndSkids \ Calculate the forces on the front tyres and apply skid
\ forces and sound effects where applicable

JSR ApplySteeringForce \ Calculate the following in parallel:
\
\   xTyreForceNose =   xTyreForceNose
\                    + zTyreForceNose * steering
\
\   zTyreForceNose =   zTyreForceNose
\                    - xTyreForceNose * steering

JSR ScaleTyreForces    \ Calculate the following:
\
\   spinYawDelta = (xTyreForceNose - xTyreForceRear)
\                   * 0.3
\
\   xTyreForceNose = xTyreForceNose >> 2
\
\   xTyreForceRear = xTyreForceRear >> 2
\
\   zTyreForceNose = zTyreForceNose >> 2
\
\   zTyreForceRear = zTyreForceRear >> 2
\
\   xPlayerAccel = (xTyreForceRear * 1.5
\                   + xTyreForceNose) * 1.6
\
\   zPlayerAccel = (zTyreForceRear * 1.5
\                   + zTyreForceNose) * 1.6
\
\   zTyreForceBoth = zPlayerAccelHi

CMP #2
BCC dmod3

\ If we get here then heightAboveTrack >= 2

LDX #2                 \ We now zero the three 16-bit bytes at spinYawDelta,
\ xPlayerAccel and zPlayerAccel, so set a counter in X
\ for the three variables

LDA #0                 \ Set A = 0 to use as the zero value

.dmod2

STA spinYawDeltaLo,X   \ Zero the X-th byte of (spinYawDeltaHi spinYawDeltaLo)
STA spinYawDeltaHi,X

DEX                    \ Decrement the variable counter

BPL dmod2              \ Loop back until we have zeroed all three 16-bit
\ variables

.dmod3

JSR ApplyWingBalance   \ Calculate the following:
\
\   xPlayerAccel =   xPlayerAccel
\                  - scaledSpeed * xPrevVelocityHi
\
\   zPlayerAccel =   zPlayerAccel
\                 - scaledSpeed
\                 * (wingBalance * playerSpeedHi + 2048)
\                 * abs(zVelocity)

JSR RotateCarToCoord   \ Rotate this vector:
\
\   [ xPlayerAccel ]
\   [       -      ]
\   [ zPlayerAccel ]
\
\ from the frame of reference of the player's car into
\ the 3D world coordinate system, putting the result
\ into:
\
\   [ xAcceleration ]
\   [       -       ]
\   [ zAcceleration ]
\
\ We ignore the y-coordinate as the calculations are
\ all done along the ground

JSR UpdateVelocity     \ Calculate the following:
\
\   xPlayerSpeed = xPlayerSpeed + xAcceleration << 5
\
\   zPlayerSpeed = zPlayerSpeed + zAcceleration << 3
\
\   spinYawAngle = spinYawAngle + spinYawDelta << 3

JSR ApplyDeltas        \ Calculate the following:
\
\   xPlayerCoord = xPlayerCoord + xPlayerSpeed * 2
\
\   zPlayerCoord = zPlayerCoord + zPlayerSpeed * 2
\
\   playerYawAngle = playerYawAngle + spinYawAngle

JSR ApplyElevation     \ Calculate changes in the car's elevation

RTS                    \ Return from the subroutine
```