PageRenderTime 24ms CodeModel.GetById 17ms RepoModel.GetById 0ms app.codeStats 1ms

/PlatformerProject/PlatformerProject/Scripts/2D/Character Controls/PlatformerController.cs

https://bitbucket.org/argylelabcoat/unity-platformerscripts
C# | 373 lines | 236 code | 74 blank | 63 comment | 41 complexity | 0c9648ac851248eb3fbe8e0a146fd66e MD5 | raw file
  1. using UnityEngine;
  2. using System.Collections;
  3. [RequireComponent (typeof(CharacterController))]
  4. [AddComponentMenu ("2D Platformer/Platformer Controller")]
  5. public class PlatformerController : MonoBehaviour
  6. {
  7. // Does this script currently respond to Input?
  8. public bool canControl = true;
  9. // The character will spawn at spawnPoint's position when needed. This could be changed via a script at runtime to implement, e.g. waypoints/savepoints.
  10. public Transform spawnPoint;
  11. public PlatformerControllerMovement movement = new PlatformerControllerMovement();
  12. public PlatformerControllerJumping jump = new PlatformerControllerJumping();
  13. public CharacterController controller;
  14. // Moving platform support.
  15. public Transform activePlatform;
  16. public Vector3 activeLocalPlatformPoint;
  17. public Vector3 activeGlobalPlatformPoint;
  18. public Vector3 lastPlatformVelocity;
  19. // This is used to keep track of special effects in UpdateEffects();
  20. bool areEmittersOn = false;
  21. // cache oft-used components
  22. Transform _transform;
  23. void Awake()
  24. {
  25. _transform = transform;
  26. movement.direction = _transform.TransformDirection(Vector3.forward);
  27. controller = GetComponent<CharacterController>();
  28. Spawn();
  29. }
  30. void Spawn()
  31. {
  32. // reset the character's speed
  33. movement.verticalSpeed = 0.0f;
  34. movement.speed = 0.0f;
  35. // reset the character's position to the spawnPoint
  36. _transform.position = spawnPoint.position;
  37. }
  38. void OnDeath()
  39. {
  40. Spawn();
  41. }
  42. void UpdateSmoothedMovementDirection()
  43. {
  44. float h = Input.GetAxisRaw("Horizontal");
  45. if (!canControl)
  46. h = 0.0f;
  47. movement.isMoving = Mathf.Abs(h) > 0.1f;
  48. if (movement.isMoving)
  49. {
  50. movement.direction = new Vector3(h, 0, 0);
  51. // sliding pseudo-code:
  52. // if(sliding_btn is down)
  53. // {
  54. // if(h == lastUpdate.h)
  55. // {
  56. // weAreSliding = true
  57. // if( slidingTime > howLongASlideLasts )
  58. // {
  59. // movement.direction = Vector3.zero;
  60. // weAreSliding = false
  61. // }
  62. // }
  63. // else
  64. // weAreSliding = false
  65. // }
  66. }
  67. // Ground controls
  68. if (controller.isGrounded)
  69. {
  70. // Smooth the sped based on the current target direction
  71. float curSmooth = movement.speedSmoothing * Time.deltaTime;
  72. // choose target speed
  73. float targetSpeed = Mathf.Min(Mathf.Abs(h), 1.0f);
  74. // This is where I'd put in speed adjustments for additional movements (ground)
  75. // for sliding for instance, we need to check for a button
  76. // then modify the speed
  77. // Pick speed modifier
  78. if (Input.GetButton("Fire2") && canControl)
  79. {
  80. targetSpeed *= movement.runSpeed;
  81. }
  82. else
  83. {
  84. targetSpeed *= movement.walkSpeed;
  85. }
  86. movement.speed = Mathf.Lerp(movement.speed, targetSpeed, curSmooth);
  87. movement.hangTime = 0.0f;
  88. }
  89. else // not grounded (in the air)
  90. {
  91. // In Air Controls
  92. movement.hangTime += Time.deltaTime;
  93. if (movement.isMoving)
  94. movement.inAirVelocity += new Vector3(Mathf.Sign(h), 0, 0) * Time.deltaTime;
  95. }
  96. }
  97. void FixedUpdate()
  98. {
  99. // force us to 2 Dimensions
  100. Vector3 p = _transform.position;
  101. p.z = 0;
  102. _transform.position = p;
  103. }
  104. void ApplyJumping()
  105. {
  106. // Prevent Jumping too fast after each other
  107. if (jump.lastTime + jump.repeatTime > Time.time)
  108. return;
  109. if (controller.isGrounded)
  110. {
  111. // Jump
  112. // - Only when pessing the button down
  113. // - With a timeout so you can press the button slightly before landing
  114. if (jump.enabled && Time.time < jump.lastButtonTime + jump.timeout)
  115. {
  116. movement.verticalSpeed = CalculateJumpVerticalSpeed(jump.height);
  117. movement.inAirVelocity = lastPlatformVelocity;
  118. SendMessage("DidJump", SendMessageOptions.DontRequireReceiver);
  119. }
  120. }
  121. }
  122. void ApplyGravity()
  123. {
  124. // Apply Gravity
  125. bool jumpButton = Input.GetButton("Jump");
  126. if (!canControl)
  127. jumpButton = false;
  128. // When we reach the apex of the jump we send out a message
  129. if (jump.jumping && !jump.reachedApex && movement.verticalSpeed <= 0.0f)
  130. {
  131. jump.reachedApex = true;
  132. SendMessage("DidJumpReachApex", SendMessageOptions.DontRequireReceiver);
  133. }
  134. // * When jumping up we don't apply gravity for some time when the user is holding the jump button
  135. // This gives more control over jump height by pressing the button longer
  136. bool extraPowerJump = jump.jumping && movement.verticalSpeed > 0.0f && jumpButton && transform.position.y < jump.lastStartHeight + jump.extraHeight && !IsTouchingCeiling;
  137. if (extraPowerJump)
  138. return;
  139. else if (controller.isGrounded)
  140. movement.verticalSpeed = -movement.gravity * Time.deltaTime;
  141. else
  142. movement.verticalSpeed -= movement.gravity * Time.deltaTime;
  143. // Make sure we don't fall any faster than maxFallSpeed. This gives our character a terminal velocity.
  144. movement.verticalSpeed = Mathf.Max(movement.verticalSpeed, -movement.maxFallSpeed);
  145. }
  146. float CalculateJumpVerticalSpeed(float targetJumpHeight)
  147. {
  148. // From the jump height and gravity we deduce the upwards speed
  149. // for the character to reach at the apex.
  150. return Mathf.Sqrt(2 * targetJumpHeight * movement.gravity);
  151. }
  152. void DidJump()
  153. {
  154. jump.jumping = true;
  155. jump.reachedApex = false;
  156. jump.lastTime = Time.time;
  157. jump.lastStartHeight = transform.position.y;
  158. jump.lastButtonTime = -10;
  159. }
  160. void UpdateEffects ()
  161. {
  162. bool wereEmittersOn = areEmittersOn;
  163. areEmittersOn = jump.jumping && movement.verticalSpeed > 0.0;
  164. // By comparing the previous value of areEmittersOn to the new one, we will only update the particle emitters when needed
  165. if (wereEmittersOn != areEmittersOn)
  166. {
  167. foreach(ParticleEmitter emitter in GetComponentsInChildren<ParticleEmitter> ())
  168. {
  169. emitter.emit = areEmittersOn;
  170. }
  171. }
  172. }
  173. void Update ()
  174. {
  175. Vector3 lastPosition;
  176. if (Input.GetButtonDown ("Jump") && canControl)
  177. {
  178. jump.lastButtonTime = Time.time;
  179. }
  180. UpdateSmoothedMovementDirection();
  181. // Apply gravity
  182. // - extra power jump modifies gravity
  183. ApplyGravity ();
  184. // Apply jumping logic
  185. ApplyJumping ();
  186. // Moving platform support
  187. if (activePlatform != null)
  188. {
  189. Vector3 newGlobalPlatformPoint = activePlatform.TransformPoint(activeLocalPlatformPoint);
  190. Vector3 moveDistance = (newGlobalPlatformPoint - activeGlobalPlatformPoint);
  191. _transform.position = _transform.position + moveDistance;
  192. lastPlatformVelocity = (newGlobalPlatformPoint - activeGlobalPlatformPoint) / Time.deltaTime;
  193. }
  194. else
  195. {
  196. lastPlatformVelocity = Vector3.zero;
  197. }
  198. activePlatform = null;
  199. // Save lastPosition for velocity calculation.
  200. lastPosition = _transform.position;
  201. // Calculate actual motion
  202. Vector3 currentMovementOffset = movement.direction * movement.speed + new Vector3 (0, movement.verticalSpeed, 0) + movement.inAirVelocity;
  203. // We always want the movement to be framerate independent. Multiplying by Time.deltaTime does this.
  204. currentMovementOffset *= Time.deltaTime;
  205. // Move our character!
  206. movement.collisionFlags = controller.Move (currentMovementOffset);
  207. // Calculate the velocity based on the current and previous position.
  208. // This means our velocity will only be the amount the character actually moved as a result of collisions.
  209. movement.velocity = (_transform.position - lastPosition) / Time.deltaTime;
  210. // Moving platforms support
  211. if (activePlatform != null) {
  212. activeGlobalPlatformPoint = transform.position;
  213. activeLocalPlatformPoint = activePlatform.InverseTransformPoint (transform.position);
  214. }
  215. // Set rotation to the move direction
  216. if (movement.direction.sqrMagnitude > 0.01)
  217. _transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(movement.direction), Time.deltaTime * movement.rotationSmoothing);
  218. // We are in jump mode but just became grounded
  219. if (controller.isGrounded)
  220. {
  221. movement.inAirVelocity = Vector3.zero;
  222. if (jump.jumping)
  223. {
  224. jump.jumping = false;
  225. SendMessage ("DidLand", SendMessageOptions.DontRequireReceiver);
  226. Vector3 jumpMoveDirection = movement.direction * movement.speed + movement.inAirVelocity;
  227. if (jumpMoveDirection.sqrMagnitude > 0.01)
  228. movement.direction = jumpMoveDirection.normalized;
  229. }
  230. }
  231. // Update special effects like rocket pack particle effects
  232. UpdateEffects ();
  233. }
  234. void OnControllerColliderHit (ControllerColliderHit hit)
  235. {
  236. Debug.Log("wtf? normal: " + hit.normal + ", direction: " + hit.moveDirection);
  237. if (hit.normal.y < -0.9f)
  238. {
  239. Debug.Log(hit.collider.gameObject.name);
  240. //controller.collider
  241. Physics.IgnoreCollision(hit.controller.collider, hit.collider, true);
  242. return;
  243. }
  244. if (hit.moveDirection.y > 0.01f)
  245. {
  246. Debug.Log(hit.collider.gameObject.name);
  247. //controller.collider
  248. Physics.IgnoreCollision(hit.controller.collider, hit.collider,true);
  249. return;
  250. }
  251. // Make sure we are really standing on a straight platform
  252. // Not on the underside of one and not falling down from it either!
  253. if (hit.moveDirection.y < -0.9f && hit.normal.y > 0.9f)
  254. {
  255. activePlatform = hit.collider.transform;
  256. }
  257. }
  258. public void Reset()
  259. {
  260. ////jump = new PlatformerControllerJumping();
  261. ////movement = new PlatformerControllerMovement();
  262. gameObject.tag = "Player";
  263. }
  264. #region props
  265. public float Speed
  266. {
  267. get{return movement.speed;}
  268. }
  269. public Vector3 Velocity
  270. {
  271. get{return movement.velocity;}
  272. }
  273. public bool IsMoving
  274. {
  275. get { return movement.isMoving; }
  276. }
  277. public bool IsJumping
  278. {
  279. get { return jump.jumping; }
  280. }
  281. public bool IsTouchingCeiling
  282. {
  283. get { return (movement.collisionFlags & CollisionFlags.CollidedAbove) != 0;}
  284. }
  285. public Vector3 Direction
  286. {
  287. get { return movement.direction; }
  288. }
  289. public float HangTime
  290. {
  291. get{return movement.hangTime; }
  292. }
  293. public bool Controllable
  294. {
  295. set { canControl = value; }
  296. get { return canControl; }
  297. }
  298. #endregion
  299. }