.MovePlayerOnTrack \ We start by calculating the player's heading within \ the current segment, so we know which direction the \ car is heading in, and therefore how to alter the \ car's position with the track segment LDA edgeYawAngle \ Set A = edgeYawAngle - playerHeading SEC \ SBC playerHeading \ So A contains the yaw angle of the closest segment, \ from the point of view of the player's car JSR Absolute8Bit \ Set A = |A| \ \ So the angle is now like this: \ \ 0 \ | 32 \ | / \ | / \ |/ \ +----- 64 \ |\ \ | \ \ | \ \ | 96 \ 127 CMP #64 \ If A < 64, clear the C flag, if A >= 64, set the C \ flag ROR playerPastSegment \ Store the C flag in bit 7 of playerPastSegment, so \ this will be set if the yaw angle is >= 64, which is \ 90 degrees \ \ So bit 7 will be set if the closest segment is at a \ yaw angle of more than 90 degrees from the point of \ view of the player - in other words, when the player \ has driven past the segment BPL mseg1 \ If bit 7 of playerPastSegment is clear, i.e. the C \ flag is clear, then A < 64 and the player has not gone \ past the closest segment, so jump to mseg1 \ The player has gone past the closest segment, so A is \ in the range 64 to 127, with the higher figure \ indicating that the segment is way behind us, so we \ now flip that around to the range 63 to 0, where 0 \ indicates that the segment is way behind us, and 63 \ indicates that we've just passed it \ \ We use this value later to calculate the player's \ carProgress EOR #%01111111 \ Negate A using two's complement, leaving bit 7 alone CLC \ to leave the result in the range 63 to 0, so the angle ADC #1 \ is now like this: \ \ 0 \ | 32 \ | / \ | / \ |/ \ +----- 64 \ |\ \ | \ \ | \ \ | 32 \ 0 \ \ So the value of A is zero if the player's car is \ pointing straight along the track segment, or 64 if \ the car is pointing sideways, towards the verge .mseg1 PHA \ Store the player's direction in A on the stack, which \ we retrieve below to use when calculating carProgress \ for the player's car \ We now calculate the carRacingLine value for the \ player's car, which is the left-right position within \ the track LDY #186 \ Set A = edgeDistanceLo * (A' / 256) * (186 / 256) JSR GetCarInSegment \ \ where A' is A, scaled by the ScaleCarInSegment routine LDX edgeSegmentPointer \ Set X to the index of the segment within the track \ verge buffer that is closest to the player's car CPX #40 \ If X < 40, then the segment is along the inner edge of BCC mseg2 \ the track, so jump to mseg2 to skip the following \ instruction EOR #&FF \ Set A = ~A .mseg2 LDX currentPlayer \ Set X to the driver number of the current player BIT directionFacing \ Set the sign of A to that of directionFacing, so A JSR Absolute8Bit \ gets negated when we are facing backwards \ The value in A is the updated value of carRacingLine \ for the player, but before we store it, we need to use \ it to calculate the player's drift PHA \ Store A on the stack, so we can retrieve bit below \ when storing it as the updated carRacingLine for the \ player's car \ Next, we set bit 7 of playerDrift according to the \ amount of sideways movement of the player's car, with \ a set bit 7 meaning the player's car is drifting \ sideways by more than 22 in this iteration around the \ main driving loop (where the full track width is 256) SBC carRacingLine,X \ Set A = A - the racing line for the player \ \ So A contains the distance that the car has moved in \ terms of racing line, i.e. left to right BCS mseg3 \ If the subtraction didn't underflow, jump to mseg3 to \ skip the following instruction EOR #&FF \ If we get here, then A < then player's racing line and \ the subtraction underflowed, so set A = ~A to make \ A positive, so A = |A| .mseg3 CMP #22 \ If A < 22, clear the C flag, if A >= 22, set the C \ flag IF _ACORNSOFT OR _4TRACKS ROR playerDrift \ Store the C flag in bit 7 of playerDrift, so this will \ be set if A >= 22 ELIF _SUPERIOR OR _REVSPLUS JSR SetPlayerDriftSup \ Set bit 7 of playerDrift if both A >= 22 and the \ objSectionSegmt for the player is >= 3, so the \ Superior version does not record drift in the first \ three segments of a new track section ENDIF PLA \ Set carRacingLine,X to the second value we stored on STA carRacingLine,X \ the stack above \ Finally, we calculate the carProgress value for the \ player's car, which is the progress within the segment PLA \ Set A to the first value we stored on the stack above, \ which is the player's direction, where A is zero if \ the player's car is pointing straight along the track \ segment, or 64 if the car is pointing sideways, \ towards the verge EOR #&FF \ Set A = 64 - A CLC \ ADC #65 \ This works because ~A = -A - 1, so we have: \ \ A = ~A + 65 \ = -A - 1 + 65 \ = 64 - A \ \ So A is now in the range 0 to 64, where 64 means the \ car is pointing forwards along the segment, and 0 \ means it's pointing sideways LDY #136 \ Set A = edgeDistanceLo * (A' / 256) * (136 / 256) JSR GetCarInSegment \ \ where A' is A, scaled by the ScaleCarInSegment routine ASL A \ Set A = A * 2 ASL A BIT playerPastSegment \ If bit 7 of playerPastSegment is set, jump to mseg4 BMI mseg4 EOR #&FF \ Set A = ~A .mseg4 STA carProgress,X \ Set the car's progress to A RTS \ Return from the subroutineName: MovePlayerOnTrack [Show more] Type: Subroutine Category: Car geometry Summary: Update the position of the player's car within the current track segment Deep dive: Placing cars on the trackContext: See this subroutine in context in the source code References: This subroutine is called as follows: * MainDrivingLoop (Part 2 of 5) calls MovePlayerOnTrack
This routine sets the racing line and progress for the player's car.
[X]
Subroutine Absolute8Bit (category: Maths (Arithmetic))
Calculate the absolute value (modulus) of an 8-bit number
[X]
Subroutine GetCarInSegment (category: Car geometry)
Calculate the player car's position within the current segment
[X]
Subroutine SetPlayerDriftSup (category: Car geometry)
Record player drift, but only if the player is not in the first three segments of a track section
[X]
Variable carProgress in workspace Stack variables
Lowest byte of each car's progress through the segment it's in
[X]
Variable carRacingLine in workspace Stack variables
Each car's position on the track in the x-axis
[X]
Variable currentPlayer in workspace Zero page
The number of the current player
[X]
Variable directionFacing in workspace Zero page
The direction that our car is facing
[X]
Variable edgeSegmentPointer in workspace Zero page
The index of the segment within the track verge buffer that is closest to the player's car
[X]
Variable edgeYawAngle in workspace Zero page
The yaw angle of the track segment that is closest to the player's car, from the point of view of the car
[X]
Label mseg1 is local to this routine
[X]
Label mseg2 is local to this routine
[X]
Label mseg3 is local to this routine
[X]
Label mseg4 is local to this routine
[X]
Variable playerDrift (category: Driving model)
Records whether the player's car is moving sideways by a significant amount
[X]
Variable playerHeading in workspace Zero page
The player's yaw angle, relative to the direction of the track, where a heading of 0 means the player is pointing straight along the track
[X]
Variable playerPastSegment in workspace Zero page
Determines whether the player has gone past the closest segment to the player (i.e. whether the relative yaw angle of the segment is greater than 90 degrees)