Skip to navigation

3D objects: GetObjectAngles

Name: GetObjectAngles [Show more] Type: Subroutine Category: 3D objects Summary: Calculate the angles and distances of the vector from the viewer to a specific object
Context: See this subroutine in context in the source code References: This subroutine is called as follows: * CheckEnemyGaze (Part 1 of 2) calls GetObjectAngles * DrawObject calls GetObjectAngles * GetObjVisibility calls GetObjectAngles

This routine calculates the following for an object: 1. objTypeToAnalyse: Set to the type of the object we are analysing. 2. xDelta(Hi Lo), yDelta(Hi Lo), zDelta(Hi Lo): Calculate the difference (the delta) in all three axes between the viewer and the object we are analysing, to give us the 3D vector from the viewer to the object. 3. angle(Hi Lo): Calculate the angle of the hypotenuse of the triangle formed by the x-axis and z-axis, which is the projection of the 3D vector from the viewer to the object down onto the ground plane (so imagine a light shining down from above, casting the vector's shadow onto the y = 0 plane, and that's the hypotenuse). 4. hypotenuse(Hi Lo): Set to the length of the hypotenuse in the above triangle, so that's the length of the 3D vector from the viewer to the object when projected down onto the ground plane. 5. objectViewYaw(Hi Lo): The angle of the hypotenuse is the yaw angle of the 3D vector from the viewer to the object we are analysing. We subtract the viewer's yaw angle and the yaw adjustment, and add half a screen width to get the yaw angle delta from the viewer's gaze to the object, relative to the viewer's gaze, i.e. the screen). This gives us the yaw angle relative to the view. You can think of this as the screen x-coordinate of the object, or how far the object appears from the left edge of the screen. 6. objectGazeYaw(Hi Lo): Set to the object's gaze relative to the viewer's gaze. 7. If this is the landscape preview, rotate the object to face forwards and scale it so it looks good. 8. Set objectAdjacent(Hi Lo) to hypotenuse(Hi Lo) so it can be used as the length of the adjacent side in the vertical right-angled triangle with the projected vector along the bottom and the vector from the viewer to the object as the hypotenuse. 9. Set objectOpposite(Hi Lo) to the length of the opposite side in the vertical right-angled triangle with the projected vector along the bottom and the vector from the viewer to the object as the hypotenuse.
Arguments: Y The number of the object to be analysed viewType Landscape preview flag: * Zero = this is the landscape preview, so rotate all the objects in the preview to face the viewer * Non-zero = this is not the landscape preview, so leave the objects alone viewingObject The viewing object
RTS \ This instruction appears to be unused .GetObjectAngles STY objectToAnalyse \ Set objectToAnalyse to the number of the object being \ analysed LDA objectTypes,Y \ Set objTypeToAnalyse to the type of the object being STA objTypeToAnalyse \ analysed \ We start by calculating the difference (the delta) in \ all three axes between the viewer and the object we \ are analysing, to give us the 3D vector from the \ viewer to the object LDX viewingObject \ Set X to the object number of the viewer JSR GetHorizontalDelta \ Calculate the following: \ \ xDelta(Hi Lo) = x-coordinate of object #Y \ - x-coordinate of object #X \ - xTitleOffset \ \ xDeltaAbsoluteHi = |xDeltaAbsoluteHi| \ \ zDelta(Hi Lo) = z-coordinate of object #Y \ - z-coordinate of object #X \ \ zDeltaAbsoluteHi = |zDeltaHi| \ \ So this calculates the difference in both horizontal \ axes between object #X (the viewer) and object #Y (the \ object being analysed) \ \ Note that xTitleOffset is zero during gameplay, and is \ only non-zero when we are drawing large 3D text on the \ title screen JSR GetVerticalDelta \ Calculate the following: \ \ yDelta(Hi Lo) = y-coordinate of object #Y \ - y-coordinate of object #X \ \ So this calculates the difference in altitude between \ object #X (the viewer) and object #Y (the object being \ analysed) \ We now have deltas for all three axes, so we now can \ calculate the angle of the hypotenuse of the triangle \ formed by the x-axis and z-axis, which is the \ projection of the 3D vector from the viewer to the \ object down onto the ground plane (so imagine a light \ shining down from above, casting the vector's shadow \ onto the y = 0 plane - that's the hypotenuse) JSR GetHypotenuseAngle \ Calculate the angle of the hypotenuse in the triangle \ with the following non-hypotenuse sides: \ \ * xDelta(Hi Lo) \ \ * zDelta(Hi Lo) \ \ and return the angle in angle(Hi Lo), the tangent in \ angleTangent, the length of the longer side in \ a(Hi Lo) and the length of the shorter side in \ b(Hi Lo) \ The angle of the hypotenuse is the yaw angle of the \ 3D vector from the viewer to the object we are \ analysing \ \ We also subtract the following: \ \ * objectYawAngle,X from the high byte so the result \ is the relative yaw angle from object #X (the \ viewer's gaze) to the object \ \ * yawAdjustmentLo from the low byte so if we are \ drawing an object for updating, we include the \ correct yaw offset to enable the object to be \ drawn flush with the left edge of the screen \ buffer (see the DrawUpdatedObject routine) \ \ and add the following: \ \ * (10 0) to add half a screen width (as the screen \ is 20 yaw angles wide) \ \ So the result in objectViewYaw(Hi Lo) is the yaw angle \ delta from the viewer's gaze to the object, plus \ adjustments and half a screen, to give us the yaw \ angle relative to the view \ \ You can think of this as the screen x-coordinate of \ the object, or how far the object appears from the \ left edge of the screen LDX viewingObject \ Set X to the object number of the viewer LDA angleLo \ Set objectViewYaw(Hi Lo) = SEC \ angle(Hi Lo) - (0 yawAdjustmentLo) SBC yawAdjustmentLo \ - (objectYawAngle,X 0) STA objectViewYawLo \ + (10 0) LDA angleHi SBC objectYawAngle,X CLC ADC #10 STA objectViewYawHi LDY objectToAnalyse \ Set Y to the number of the object being analysed LDA #0 \ Set objectGazeYaw(Hi Lo) = SEC \ (objectYawAngle,Y 0) - angle(Hi Lo) SBC angleLo \ STA objectGazeYawLo \ This is the difference in yaw angles between the LDA objectYawAngle,Y \ hypotenuse (i.e. the viewer's gaze) and the direction SBC angleHi \ in which the object is facing (i.e. the object's gaze STA objectGazeYawHi \ to wherever it is looking), so that's the object's \ gaze relative to the viewer's gaze JSR GetHypotenuse \ Calculate the length of the hypotenuse in the triangle \ with side lengths of a(Hi Lo) and b(Hi Lo) and angle \ angleTangent, which the call to GetHypotenuseAngle set \ to the values for the projection of the 3D vector from \ the viewer to the object down onto the ground plane \ \ The hypotenuse length is returned in hypotenuse(Hi Lo) LDA viewType \ If viewType is non-zero then this is not the landscape BNE oang1 \ preview, so jump to oang1 to skip the following \ This is the landscape preview, so we rotate the object \ to face towards the back of the landscape, so the \ Sentinel and sentries all neatly look out of the \ screen in the preview LDA #128 \ Set objectGazeYaw(Hi Lo) = (128 0) STA objectGazeYawHi \ LDA #0 \ The degree system in the Sentinel looks like this: STA objectGazeYawLo \ \ 0 \ -32 | +32 Overhead view of object \ \ | / \ \ | / 0 = looking straight ahead \ \|/ +64 = looking sharp right \ -64 -----+----- +64 -64 = looking sharp left \ /|\ \ / | \ \ / | \ \ -96 | +96 \ 128 \ \ So this makes the object face directly out of the \ screen CPY #63 \ If we are analysing object #63, then this is either BEQ oang1 \ a block of 3D text or the Sentinel's tower, and the \ landscape preview doesn't use 3D text so it must be \ the Sentinel's tower, so jump to oang1 to skip the \ following \ \ This ensures that all objects apart from the tower \ are drawn at double size, so they stand out more \ clearly in the landscape preview (the tower is the \ biggest object by far, so doubling its size would \ make it too large) LSR hypotenuseHi \ Halve the hypotenuse length to make the object appear ROR hypotenuseLo \ to be half the distance away, so it is drawn at twice \ the size SEC \ Halve the object's altitude in yDelta(Hi Lo) for the ROR yDeltaHi \ same reason ROR yDeltaLo \ \ Because this is the landscape view, the viewer is very \ high above the landscape (as well as a long way in \ front of the front edge), so we know that \ yDelta(Hi Lo) will be negative, as it's calculated as \ the altitude of the object being analysed minus the \ altitude of the viewer, and the latter is higher than \ any object on the landscape \ \ So we can halve the value of yDelta(Hi Lo) by shifting \ a set bit into the top end of yDeltaHi, so we keep the \ sign correct LDA yDeltaLo \ Set yDelta(Hi Lo) = yDelta(Hi Lo) + 112 CLC \ ADC #112 \ Starting with the low bytes STA yDeltaLo BCC oang1 \ And then the high byte INC yDeltaHi \ \ This moves the Sentinel and sentries up so they stand \ out more clearly in the landscape preview, as \ otherwise they would appear to be sinking into the \ landscape rather than perching on top of it .oang1 LDA hypotenuseLo \ Set objectAdjacent(Hi Lo) to the length of the STA objectAdjacentLo \ hypotenuse, which is the length of the adjacent side LDA hypotenuseHi \ in the right-angled triangle with the vector from the STA objectAdjacentHi \ viewer to the object as the hypotenuse LDA yDeltaLo \ Set objectOpposite(Hi Lo) to the height of the object STA objectOppositeLo \ relative to the viewer, which is the length of the LDA yDeltaHi \ opposite side in the right-angled triangle with the STA objectOppositeHi \ vector from the viewer to the object as the hypotenuse RTS \ Return from the subroutine