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.

440 lines
11 KiB

  1. // Require a character controller to be attached to the same game object
  2. @script RequireComponent(CharacterController)
  3. public var idleAnimation : AnimationClip;
  4. public var walkAnimation : AnimationClip;
  5. public var runAnimation : AnimationClip;
  6. public var jumpPoseAnimation : AnimationClip;
  7. public var walkMaxAnimationSpeed : float = 0.75;
  8. public var trotMaxAnimationSpeed : float = 1.0;
  9. public var runMaxAnimationSpeed : float = 1.0;
  10. public var jumpAnimationSpeed : float = 1.15;
  11. public var landAnimationSpeed : float = 1.0;
  12. private var _animation : Animation;
  13. enum CharacterState {
  14. Idle = 0,
  15. Walking = 1,
  16. Trotting = 2,
  17. Running = 3,
  18. Jumping = 4,
  19. }
  20. private var _characterState : CharacterState;
  21. // The speed when walking
  22. var walkSpeed = 2.0;
  23. // after trotAfterSeconds of walking we trot with trotSpeed
  24. var trotSpeed = 4.0;
  25. // when pressing "Fire3" button (cmd) we start running
  26. var runSpeed = 6.0;
  27. var inAirControlAcceleration = 3.0;
  28. // How high do we jump when pressing jump and letting go immediately
  29. var jumpHeight = 0.5;
  30. // The gravity for the character
  31. var gravity = 20.0;
  32. // The gravity in controlled descent mode
  33. var speedSmoothing = 10.0;
  34. var rotateSpeed = 500.0;
  35. var trotAfterSeconds = 3.0;
  36. var canJump = true;
  37. private var jumpRepeatTime = 0.05;
  38. private var jumpTimeout = 0.15;
  39. private var groundedTimeout = 0.25;
  40. // The camera doesnt start following the target immediately but waits for a split second to avoid too much waving around.
  41. private var lockCameraTimer = 0.0;
  42. // The current move direction in x-z
  43. private var moveDirection = Vector3.zero;
  44. // The current vertical speed
  45. private var verticalSpeed = 0.0;
  46. // The current x-z move speed
  47. private var moveSpeed = 0.0;
  48. // The last collision flags returned from controller.Move
  49. private var collisionFlags : CollisionFlags;
  50. // Are we jumping? (Initiated with jump button and not grounded yet)
  51. private var jumping = false;
  52. private var jumpingReachedApex = false;
  53. // Are we moving backwards (This locks the camera to not do a 180 degree spin)
  54. private var movingBack = false;
  55. // Is the user pressing any keys?
  56. private var isMoving = false;
  57. // When did the user start walking (Used for going into trot after a while)
  58. private var walkTimeStart = 0.0;
  59. // Last time the jump button was clicked down
  60. private var lastJumpButtonTime = -10.0;
  61. // Last time we performed a jump
  62. private var lastJumpTime = -1.0;
  63. // the height we jumped from (Used to determine for how long to apply extra jump power after jumping.)
  64. private var lastJumpStartHeight = 0.0;
  65. private var inAirVelocity = Vector3.zero;
  66. private var lastGroundedTime = 0.0;
  67. private var isControllable = true;
  68. function Awake ()
  69. {
  70. moveDirection = transform.TransformDirection(Vector3.forward);
  71. _animation = GetComponent(Animation);
  72. if(!_animation)
  73. Debug.Log("The character you would like to control doesn't have animations. Moving her might look weird.");
  74. /*
  75. public var idleAnimation : AnimationClip;
  76. public var walkAnimation : AnimationClip;
  77. public var runAnimation : AnimationClip;
  78. public var jumpPoseAnimation : AnimationClip;
  79. */
  80. if(!idleAnimation) {
  81. _animation = null;
  82. Debug.Log("No idle animation found. Turning off animations.");
  83. }
  84. if(!walkAnimation) {
  85. _animation = null;
  86. Debug.Log("No walk animation found. Turning off animations.");
  87. }
  88. if(!runAnimation) {
  89. _animation = null;
  90. Debug.Log("No run animation found. Turning off animations.");
  91. }
  92. if(!jumpPoseAnimation && canJump) {
  93. _animation = null;
  94. Debug.Log("No jump animation found and the character has canJump enabled. Turning off animations.");
  95. }
  96. }
  97. function UpdateSmoothedMovementDirection ()
  98. {
  99. var cameraTransform = Camera.main.transform;
  100. var grounded = IsGrounded();
  101. // Forward vector relative to the camera along the x-z plane
  102. var forward = cameraTransform.TransformDirection(Vector3.forward);
  103. forward.y = 0;
  104. forward = forward.normalized;
  105. // Right vector relative to the camera
  106. // Always orthogonal to the forward vector
  107. var right = Vector3(forward.z, 0, -forward.x);
  108. var v = Input.GetAxisRaw("Vertical");
  109. var h = Input.GetAxisRaw("Horizontal");
  110. // Are we moving backwards or looking backwards
  111. if (v < -0.2)
  112. movingBack = true;
  113. else
  114. movingBack = false;
  115. var wasMoving = isMoving;
  116. isMoving = Mathf.Abs (h) > 0.1 || Mathf.Abs (v) > 0.1;
  117. // Target direction relative to the camera
  118. var targetDirection = h * right + v * forward;
  119. // Grounded controls
  120. if (grounded)
  121. {
  122. // Lock camera for short period when transitioning moving & standing still
  123. lockCameraTimer += Time.deltaTime;
  124. if (isMoving != wasMoving)
  125. lockCameraTimer = 0.0;
  126. // We store speed and direction seperately,
  127. // so that when the character stands still we still have a valid forward direction
  128. // moveDirection is always normalized, and we only update it if there is user input.
  129. if (targetDirection != Vector3.zero)
  130. {
  131. // If we are really slow, just snap to the target direction
  132. if (moveSpeed < walkSpeed * 0.9 && grounded)
  133. {
  134. moveDirection = targetDirection.normalized;
  135. }
  136. // Otherwise smoothly turn towards it
  137. else
  138. {
  139. moveDirection = Vector3.RotateTowards(moveDirection, targetDirection, rotateSpeed * Mathf.Deg2Rad * Time.deltaTime, 1000);
  140. moveDirection = moveDirection.normalized;
  141. }
  142. }
  143. // Smooth the speed based on the current target direction
  144. var curSmooth = speedSmoothing * Time.deltaTime;
  145. // Choose target speed
  146. //* We want to support analog input but make sure you cant walk faster diagonally than just forward or sideways
  147. var targetSpeed = Mathf.Min(targetDirection.magnitude, 1.0);
  148. _characterState = CharacterState.Idle;
  149. // Pick speed modifier
  150. if (Input.GetKey (KeyCode.LeftShift) || Input.GetKey (KeyCode.RightShift))
  151. {
  152. targetSpeed *= runSpeed;
  153. _characterState = CharacterState.Running;
  154. }
  155. else if (Time.time - trotAfterSeconds > walkTimeStart)
  156. {
  157. targetSpeed *= trotSpeed;
  158. _characterState = CharacterState.Trotting;
  159. }
  160. else
  161. {
  162. targetSpeed *= walkSpeed;
  163. _characterState = CharacterState.Walking;
  164. }
  165. moveSpeed = Mathf.Lerp(moveSpeed, targetSpeed, curSmooth);
  166. // Reset walk time start when we slow down
  167. if (moveSpeed < walkSpeed * 0.3)
  168. walkTimeStart = Time.time;
  169. }
  170. // In air controls
  171. else
  172. {
  173. // Lock camera while in air
  174. if (jumping)
  175. lockCameraTimer = 0.0;
  176. if (isMoving)
  177. inAirVelocity += targetDirection.normalized * Time.deltaTime * inAirControlAcceleration;
  178. }
  179. }
  180. function ApplyJumping ()
  181. {
  182. // Prevent jumping too fast after each other
  183. if (lastJumpTime + jumpRepeatTime > Time.time)
  184. return;
  185. if (IsGrounded()) {
  186. // Jump
  187. // - Only when pressing the button down
  188. // - With a timeout so you can press the button slightly before landing
  189. if (canJump && Time.time < lastJumpButtonTime + jumpTimeout) {
  190. verticalSpeed = CalculateJumpVerticalSpeed (jumpHeight);
  191. SendMessage("DidJump", SendMessageOptions.DontRequireReceiver);
  192. }
  193. }
  194. }
  195. function ApplyGravity ()
  196. {
  197. if (isControllable) // don't move player at all if not controllable.
  198. {
  199. // Apply gravity
  200. var jumpButton = Input.GetButton("Jump");
  201. // When we reach the apex of the jump we send out a message
  202. if (jumping && !jumpingReachedApex && verticalSpeed <= 0.0)
  203. {
  204. jumpingReachedApex = true;
  205. SendMessage("DidJumpReachApex", SendMessageOptions.DontRequireReceiver);
  206. }
  207. if (IsGrounded ())
  208. verticalSpeed = 0.0;
  209. else
  210. verticalSpeed -= gravity * Time.deltaTime;
  211. }
  212. }
  213. function CalculateJumpVerticalSpeed (targetJumpHeight : float)
  214. {
  215. // From the jump height and gravity we deduce the upwards speed
  216. // for the character to reach at the apex.
  217. return Mathf.Sqrt(2 * targetJumpHeight * gravity);
  218. }
  219. function DidJump ()
  220. {
  221. jumping = true;
  222. jumpingReachedApex = false;
  223. lastJumpTime = Time.time;
  224. lastJumpStartHeight = transform.position.y;
  225. lastJumpButtonTime = -10;
  226. _characterState = CharacterState.Jumping;
  227. }
  228. function Update() {
  229. if (!isControllable)
  230. {
  231. // kill all inputs if not controllable.
  232. Input.ResetInputAxes();
  233. }
  234. if (Input.GetButtonDown ("Jump"))
  235. {
  236. lastJumpButtonTime = Time.time;
  237. }
  238. UpdateSmoothedMovementDirection();
  239. // Apply gravity
  240. // - extra power jump modifies gravity
  241. // - controlledDescent mode modifies gravity
  242. ApplyGravity ();
  243. // Apply jumping logic
  244. ApplyJumping ();
  245. // Calculate actual motion
  246. var movement = moveDirection * moveSpeed + Vector3 (0, verticalSpeed, 0) + inAirVelocity;
  247. movement *= Time.deltaTime;
  248. // Move the controller
  249. var controller : CharacterController = GetComponent(CharacterController);
  250. collisionFlags = controller.Move(movement);
  251. // ANIMATION sector
  252. if(_animation) {
  253. if(_characterState == CharacterState.Jumping)
  254. {
  255. if(!jumpingReachedApex) {
  256. _animation[jumpPoseAnimation.name].speed = jumpAnimationSpeed;
  257. _animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever;
  258. _animation.CrossFade(jumpPoseAnimation.name);
  259. } else {
  260. _animation[jumpPoseAnimation.name].speed = -landAnimationSpeed;
  261. _animation[jumpPoseAnimation.name].wrapMode = WrapMode.ClampForever;
  262. _animation.CrossFade(jumpPoseAnimation.name);
  263. }
  264. }
  265. else
  266. {
  267. if(controller.velocity.sqrMagnitude < 0.1) {
  268. _animation.CrossFade(idleAnimation.name);
  269. }
  270. else
  271. {
  272. if(_characterState == CharacterState.Running) {
  273. _animation[runAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0, runMaxAnimationSpeed);
  274. _animation.CrossFade(runAnimation.name);
  275. }
  276. else if(_characterState == CharacterState.Trotting) {
  277. _animation[walkAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0, trotMaxAnimationSpeed);
  278. _animation.CrossFade(walkAnimation.name);
  279. }
  280. else if(_characterState == CharacterState.Walking) {
  281. _animation[walkAnimation.name].speed = Mathf.Clamp(controller.velocity.magnitude, 0.0, walkMaxAnimationSpeed);
  282. _animation.CrossFade(walkAnimation.name);
  283. }
  284. }
  285. }
  286. }
  287. // ANIMATION sector
  288. // Set rotation to the move direction
  289. if (IsGrounded())
  290. {
  291. transform.rotation = Quaternion.LookRotation(moveDirection);
  292. }
  293. else
  294. {
  295. var xzMove = movement;
  296. xzMove.y = 0;
  297. if (xzMove.sqrMagnitude > 0.001)
  298. {
  299. transform.rotation = Quaternion.LookRotation(xzMove);
  300. }
  301. }
  302. // We are in jump mode but just became grounded
  303. if (IsGrounded())
  304. {
  305. lastGroundedTime = Time.time;
  306. inAirVelocity = Vector3.zero;
  307. if (jumping)
  308. {
  309. jumping = false;
  310. SendMessage("DidLand", SendMessageOptions.DontRequireReceiver);
  311. }
  312. }
  313. }
  314. function OnControllerColliderHit (hit : ControllerColliderHit )
  315. {
  316. // Debug.DrawRay(hit.point, hit.normal);
  317. if (hit.moveDirection.y > 0.01)
  318. return;
  319. }
  320. function GetSpeed () {
  321. return moveSpeed;
  322. }
  323. function IsJumping () {
  324. return jumping;
  325. }
  326. function IsGrounded () {
  327. return (collisionFlags & CollisionFlags.CollidedBelow) != 0;
  328. }
  329. function GetDirection () {
  330. return moveDirection;
  331. }
  332. function IsMovingBackwards () {
  333. return movingBack;
  334. }
  335. function GetLockCameraTimer ()
  336. {
  337. return lockCameraTimer;
  338. }
  339. function IsMoving () : boolean
  340. {
  341. return Mathf.Abs(Input.GetAxisRaw("Vertical")) + Mathf.Abs(Input.GetAxisRaw("Horizontal")) > 0.5;
  342. }
  343. function HasJumpReachedApex ()
  344. {
  345. return jumpingReachedApex;
  346. }
  347. function IsGroundedWithTimeout ()
  348. {
  349. return lastGroundedTime + groundedTimeout > Time.time;
  350. }
  351. function Reset ()
  352. {
  353. gameObject.tag = "Player";
  354. }