Assignment for RMIT Mixed Reality in 2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

230 lines
6.7 KiB

  1. var cameraTransform : Transform;
  2. private var _target : Transform;
  3. // The distance in the x-z plane to the target
  4. var distance = 7.0;
  5. // the height we want the camera to be above the target
  6. var height = 3.0;
  7. var angularSmoothLag = 0.3;
  8. var angularMaxSpeed = 15.0;
  9. var heightSmoothLag = 0.3;
  10. var snapSmoothLag = 0.2;
  11. var snapMaxSpeed = 720.0;
  12. var clampHeadPositionScreenSpace = 0.75;
  13. var lockCameraTimeout = 0.2;
  14. private var headOffset = Vector3.zero;
  15. private var centerOffset = Vector3.zero;
  16. private var heightVelocity = 0.0;
  17. private var angleVelocity = 0.0;
  18. private var snap = false;
  19. private var controller : ThirdPersonController;
  20. private var targetHeight = 100000.0;
  21. function Awake ()
  22. {
  23. if(!cameraTransform && Camera.main)
  24. cameraTransform = Camera.main.transform;
  25. if(!cameraTransform) {
  26. Debug.Log("Please assign a camera to the ThirdPersonCamera script.");
  27. enabled = false;
  28. }
  29. _target = transform;
  30. if (_target)
  31. {
  32. controller = _target.GetComponent(ThirdPersonController);
  33. }
  34. if (controller)
  35. {
  36. var characterController : CharacterController = _target.GetComponent.<Collider>();
  37. centerOffset = characterController.bounds.center - _target.position;
  38. headOffset = centerOffset;
  39. headOffset.y = characterController.bounds.max.y - _target.position.y;
  40. }
  41. else
  42. Debug.Log("Please assign a target to the camera that has a ThirdPersonController script attached.");
  43. Cut(_target, centerOffset);
  44. }
  45. function DebugDrawStuff ()
  46. {
  47. Debug.DrawLine(_target.position, _target.position + headOffset);
  48. }
  49. function AngleDistance (a : float, b : float)
  50. {
  51. a = Mathf.Repeat(a, 360);
  52. b = Mathf.Repeat(b, 360);
  53. return Mathf.Abs(b - a);
  54. }
  55. function Apply (dummyTarget : Transform, dummyCenter : Vector3)
  56. {
  57. // Early out if we don't have a target
  58. if (!controller)
  59. return;
  60. var targetCenter = _target.position + centerOffset;
  61. var targetHead = _target.position + headOffset;
  62. // DebugDrawStuff();
  63. // Calculate the current & target rotation angles
  64. var originalTargetAngle = _target.eulerAngles.y;
  65. var currentAngle = cameraTransform.eulerAngles.y;
  66. // Adjust real target angle when camera is locked
  67. var targetAngle = originalTargetAngle;
  68. // When pressing Fire2 (alt) the camera will snap to the target direction real quick.
  69. // It will stop snapping when it reaches the target
  70. if (Input.GetButton("Fire2"))
  71. snap = true;
  72. if (snap)
  73. {
  74. // We are close to the target, so we can stop snapping now!
  75. if (AngleDistance (currentAngle, originalTargetAngle) < 3.0)
  76. snap = false;
  77. currentAngle = Mathf.SmoothDampAngle(currentAngle, targetAngle, angleVelocity, snapSmoothLag, snapMaxSpeed);
  78. }
  79. // Normal camera motion
  80. else
  81. {
  82. if (controller.GetLockCameraTimer () < lockCameraTimeout)
  83. {
  84. targetAngle = currentAngle;
  85. }
  86. // Lock the camera when moving backwards!
  87. // * It is really confusing to do 180 degree spins when turning around.
  88. if (AngleDistance (currentAngle, targetAngle) > 160 && controller.IsMovingBackwards ())
  89. targetAngle += 180;
  90. currentAngle = Mathf.SmoothDampAngle(currentAngle, targetAngle, angleVelocity, angularSmoothLag, angularMaxSpeed);
  91. }
  92. // When jumping don't move camera upwards but only down!
  93. if (controller.IsJumping ())
  94. {
  95. // We'd be moving the camera upwards, do that only if it's really high
  96. var newTargetHeight = targetCenter.y + height;
  97. if (newTargetHeight < targetHeight || newTargetHeight - targetHeight > 5)
  98. targetHeight = targetCenter.y + height;
  99. }
  100. // When walking always update the target height
  101. else
  102. {
  103. targetHeight = targetCenter.y + height;
  104. }
  105. // Damp the height
  106. var currentHeight = cameraTransform.position.y;
  107. currentHeight = Mathf.SmoothDamp (currentHeight, targetHeight, heightVelocity, heightSmoothLag);
  108. // Convert the angle into a rotation, by which we then reposition the camera
  109. var currentRotation = Quaternion.Euler (0, currentAngle, 0);
  110. // Set the position of the camera on the x-z plane to:
  111. // distance meters behind the target
  112. cameraTransform.position = targetCenter;
  113. cameraTransform.position += currentRotation * Vector3.back * distance;
  114. // Set the height of the camera
  115. cameraTransform.position.y = currentHeight;
  116. // Always look at the target
  117. SetUpRotation(targetCenter, targetHead);
  118. }
  119. function LateUpdate () {
  120. Apply (transform, Vector3.zero);
  121. }
  122. function Cut (dummyTarget : Transform, dummyCenter : Vector3)
  123. {
  124. var oldHeightSmooth = heightSmoothLag;
  125. var oldSnapMaxSpeed = snapMaxSpeed;
  126. var oldSnapSmooth = snapSmoothLag;
  127. snapMaxSpeed = 10000;
  128. snapSmoothLag = 0.001;
  129. heightSmoothLag = 0.001;
  130. snap = true;
  131. Apply (transform, Vector3.zero);
  132. heightSmoothLag = oldHeightSmooth;
  133. snapMaxSpeed = oldSnapMaxSpeed;
  134. snapSmoothLag = oldSnapSmooth;
  135. }
  136. function SetUpRotation (centerPos : Vector3, headPos : Vector3)
  137. {
  138. // Now it's getting hairy. The devil is in the details here, the big issue is jumping of course.
  139. // * When jumping up and down we don't want to center the guy in screen space.
  140. // This is important to give a feel for how high you jump and avoiding large camera movements.
  141. //
  142. // * At the same time we dont want him to ever go out of screen and we want all rotations to be totally smooth.
  143. //
  144. // So here is what we will do:
  145. //
  146. // 1. We first find the rotation around the y axis. Thus he is always centered on the y-axis
  147. // 2. When grounded we make him be centered
  148. // 3. When jumping we keep the camera rotation but rotate the camera to get him back into view if his head is above some threshold
  149. // 4. When landing we smoothly interpolate towards centering him on screen
  150. var cameraPos = cameraTransform.position;
  151. var offsetToCenter = centerPos - cameraPos;
  152. // Generate base rotation only around y-axis
  153. var yRotation = Quaternion.LookRotation(Vector3(offsetToCenter.x, 0, offsetToCenter.z));
  154. var relativeOffset = Vector3.forward * distance + Vector3.down * height;
  155. cameraTransform.rotation = yRotation * Quaternion.LookRotation(relativeOffset);
  156. // Calculate the projected center position and top position in world space
  157. var centerRay = cameraTransform.GetComponent.<Camera>().ViewportPointToRay(Vector3(.5, 0.5, 1));
  158. var topRay = cameraTransform.GetComponent.<Camera>().ViewportPointToRay(Vector3(.5, clampHeadPositionScreenSpace, 1));
  159. var centerRayPos = centerRay.GetPoint(distance);
  160. var topRayPos = topRay.GetPoint(distance);
  161. var centerToTopAngle = Vector3.Angle(centerRay.direction, topRay.direction);
  162. var heightToAngle = centerToTopAngle / (centerRayPos.y - topRayPos.y);
  163. var extraLookAngle = heightToAngle * (centerRayPos.y - centerPos.y);
  164. if (extraLookAngle < centerToTopAngle)
  165. {
  166. extraLookAngle = 0;
  167. }
  168. else
  169. {
  170. extraLookAngle = extraLookAngle - centerToTopAngle;
  171. cameraTransform.rotation *= Quaternion.Euler(-extraLookAngle, 0, 0);
  172. }
  173. }
  174. function GetCenterOffset ()
  175. {
  176. return centerOffset;
  177. }