.BuildRoadSign LDX currentPlayer \ Set X to the driver number of the current player LDY objTrackSection,X \ Set Y to the track section number * 8 for the current \ player LDA trackSectionData,Y \ Set A to bits 4-7 of the trackSectionData for the LSR A \ track section, shifted into bits 0-3, so A contains LSR A \ the number of the sign for this section (0 to 15) LSR A LSR A STA thisSignNumber \ Store the sign number in thisSignNumber, so we can \ retrieve it below CMP previousSignNumber \ If previousSignNumber doesn't already contain this BNE sign1 \ sign number, jump to sign1 to skip the following \ We get here if we are calling BuildRoadSign again for \ the same sign number (we set previousSignNumber to \ the current sign number later in the routine) \ \ This ensures that we display signs at the start of \ sections that have a different value in bits 4-7 of \ trackSectionData compared to the previous section, so \ signs appear when we move into a section with a new \ value in bits 4-7 of the trackSectionData (and that \ value is the number of the sign to show) ADC #0 \ Increment the sign number in A (we know the C flag is \ set, as the above comparison was equal) AND #15 \ Restrict the result to the range 0 to 15, i.e. set A \ to A mod 16 .sign1 TAX \ Set X to the sign number, which will either be the \ sign number from trackSectionData for this section, or \ the sign number plus 1 \ We now draw sign number X, by fetching the track sign \ vector, adding it to the track section coordinate to \ get the sign's 3D coordinates, and subtracting the \ player's coordinates to get the sign's vector relative \ to the player (i.e. relative to the camera) \ \ We then calculate the yaw and pitch angles and store \ them in object 23, so it can be drawn by the call to \ DrawCarOrSign from the main driving loop LDY #2 \ Set Y = 2, so the call to AddScaledVector scales by \ 2 ^ (8 - Y) = 2 ^ 6 STY W \ Set W = 2, which gets decremented through each call \ to AddScaledVector as we work through each axis, so it \ stores the results in each axis of xRoadSignCoord in \ turn LDA zTrackSignVector,X \ Set A to the 3D z-coordinate of the track sign vector JSR AddScaledVector \ Set zRoadSignCoord \ = zPlayerCoord - zTrackSignVector * 2 ^ 6 LDY #4 \ Set Y = 4, so the call to AddScaledVector scales by \ 2 ^ (8 - Y) = 2 ^ 4 LDA yTrackSignVector,X \ Set A to the 3D y-coordinate of the track sign vector JSR AddScaledVector \ Set yRoadSignCoord \ = yPlayerCoord - yTrackSignVector * 2 ^ 4 LDY #2 \ Set Y = 2, so the call to AddScaledVector scales by \ 2 ^ (8 - Y) = 2 ^ 6 LDA xTrackSignVector,X \ Set A to the 3D x-coordinate of the track sign vector JSR AddScaledVector \ Set xRoadSignCoord \ = xPlayerCoord - xTrackSignVector * 2 ^ 6 \ We now have: \ \ [ xRoadSignCoord ] [ xPlayerCoord ] \ [ yRoadSignCoord ] = [ yPlayerCoord ] \ [ zRoadSignCoord ] [ zPlayerCoord ] \ \ [ xTrackSignVector * 2 ^ 6 ] \ - [ yTrackSignVector * 2 ^ 4 ] \ [ zTrackSignVector * 2 ^ 6 ] LDA trackSignData,X \ Set objectType to the object type for road sign X, AND #%00000111 \ which comes from bits 0-2 of trackSignData, and CLC \ gets 7 added to get the range 7 to 12 ADC #7 STA objectType LDA trackSignData,X \ Set Y to the track section number for road sign X, AND #%11111000 \ which comes from bits 3-7 of trackSignData TAY LDX #&FD \ Set X = &FD so the calls to GetSectionCoord, \ GetObjYawAngle and GetObjPitchAngle use xCoord2, \ yCoord2 and zCoord2 JSR GetSectionCoord \ Copy the first trackSectionI coordinate for track \ section Y into xCoord2, so xCoord2 contains the 3D \ coordinates of the inside track for the start of this \ track section, i.e. \ \ [ xCoord2 ] [ xTrackSectionI ] \ [ yCoord2 ] = [ yTrackSectionI ] \ [ zCoord2 ] [ zTrackSectionI ] LDY #6 \ Set Y = 6 so the call to GetObjYawAngle uses \ xRoadSignCoord for the second variable, so we \ calculate the yaw and pitch angles for an object at \ the following 3D coordinates (if we just consider the \ x-axis, for clarity): \ \ xCoord2 - xRoadSignCoord \ = xTrackSectionI - (xPlayerCoord - xTrackSignVector) \ = xTrackSectionI - xPlayerCoord + xTrackSignVector \ = xTrackSectionI + xTrackSignVector - xPlayerCoord \ \ The xPlayerCoord vector contains the 3D coordinates \ of the player's car, so the above gives us the vector \ from the player's car to the sign \ \ So this is the vector we use to calculate the object's \ angles, to show the sign in the correct place by the \ side of the track from the viewpoint of the player JSR GetObjYawAngle \ Calculate the object's yaw angle, returning it in \ (JJ II) LDA II \ Store the yaw angle from (JJ II) in (objYawAngleHi+23 STA objYawAngleLo+23 \ objYawAngleLo+23), so we use object 23 to store the LDA JJ \ sign object STA objYawAngleHi+23 \ Now that the sign object has been built and the angles \ calculated, we can check for any collisions between \ the player and the sign SEC \ Set A = JJ - playerYawAngleHi SBC playerYawAngleHi JSR Absolute8Bit \ Set A = |A| \ = |JJ - playerYawAngleHi| \ \ So A contains the screen distance between the player \ and the sign in the x-axis CMP #64 \ If A < 64, jump to sign2 to skip the following BCC sign2 LDY thisSignNumber \ Set previousSignNumber to the sign number from the STY previousSignNumber \ trackSectionData, so the next time we display a sign \ it will be the next sign .sign2 LDY #37 \ Set Y = 37 to use as the collision distance in the \ call to CheckForContact below CMP #110 \ If A < 110, jump to sign3 to skip the following BCC sign3 LDY #80 \ Set Y = 80 to use as the collision distance in the \ call to CheckForContact below .sign3 LDA #23 \ Set objectNumber = 23, so if we are colliding with the STA objectNumber \ sign, CheckForContact sets collisionDriver to object \ 23 (which is now the sign object) JSR CheckForContact \ Check to see if the object and the player's car are \ close enough for contact, specifically if they are \ within a distance of Y from each other \ The final step is to calculate the object's pitch \ angle, and then we are done building the sign object LDY #6 \ Set Y = 6 so the call to GetObjPitchAngle uses \ xRoadSignCoord JSR GetObjPitchAngle \ Calculate the object's pitch angle, returning it \ in A and LL \ \ If the object is not visible on-screen, the C flag is \ set, which will hide the object in the following call \ to SetObjectDetails JSR SetObjectDetails \ Set the object's visibility, scale and type RTS \ Return from the subroutineName: BuildRoadSign [Show more] Type: Subroutine Category: 3D objects Summary: Create an object for the road sign Deep dive: Road signsContext: See this subroutine in context in the source code References: This subroutine is called as follows: * MainDrivingLoop (Part 2 of 5) calls BuildRoadSign
[X]
Subroutine Absolute8Bit (category: Maths (Arithmetic))
Calculate the absolute value (modulus) of an 8-bit number
[X]
Subroutine AddScaledVector (category: Maths (Geometry))
Add a scaled vector to another vector, one axis at a time
[X]
Subroutine CheckForContact (category: Car geometry)
Check to see if the object is close enough to the player car to make contact
[X]
Subroutine GetObjPitchAngle (category: 3D objects)
Calculate an object's pitch angle
[X]
Subroutine GetObjYawAngle (Part 1 of 4) (category: 3D objects)
Calculate an object's yaw angle
[X]
Subroutine GetSectionCoord (category: Track geometry)
Copy a three-part 16-bit coordinate from the track section data
[X]
Subroutine SetObjectDetails (category: 3D objects)
Set an object's visibility, scale and type
[X]
Variable currentPlayer in workspace Zero page
The number of the current player
[X]
Variable objTrackSection in workspace Main variable workspace
The number of the track section * 8 for each object
[X]
Variable objYawAngleHi in workspace Main variable workspace
High byte of each object's yaw angle
[X]
Variable objYawAngleLo in workspace Main variable workspace
Low byte of each object's yaw angle
[X]
Variable objectNumber in workspace Zero page
The object number of the four-part car we are drawing
[X]
Variable objectType in workspace Zero page
The type of object to draw (0 to 12)
[X]
Variable playerYawAngleHi in workspace Zero page
High byte of the player's yaw angle
[X]
Variable previousSignNumber (category: Track geometry)
Stores the number of the sign from the previous call to the BuildRoadSign routine
[X]
Label sign1 is local to this routine
[X]
Label sign2 is local to this routine
[X]
Label sign3 is local to this routine
[X]
Variable thisSignNumber in workspace Zero page
The sign number that we are currently building
[X]
Variable trackSectionData in workspace trackData
Various data for the track section
[X]
Variable trackSignData in workspace trackData
Base coordinates and object types for 16 road signs
[X]
Variable xTrackSignVector in workspace trackData
The x-coordinate of the track sign vector for each sign, to be scaled and added to the inner track section vector for the sign
[X]
Variable yTrackSignVector in workspace trackData
The y-coordinate of the track sign vector for each sign, to be scaled and added to the inner track section vector for the sign
[X]
Variable zTrackSignVector in workspace trackData
The z-coordinate of the track sign vector for each sign, to be scaled and added to the inner track section vector for the sign