Skip to navigation

Revs on the BBC Micro

Car geometry: MovePlayerOnTrack

Name: 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 track
Context: 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.
.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 subroutine