You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
178 lines
6.3 KiB
C#
178 lines
6.3 KiB
C#
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
|
|
[RequireComponent(typeof(MoveController))]
|
|
[RequireComponent(typeof(BoxCollider2D))]
|
|
public class PlayerController : MonoBehaviour {
|
|
public float jumpHeight = 4f;
|
|
public float timeToJumpApex = 0.4f;
|
|
public float moveSpeed = 6f;
|
|
public float maxFallSpeed = -20f;
|
|
public float timeToMaxRunSpeed = 0.15f;
|
|
public float timeToMaxAirmoveSpeed = 0.25f;
|
|
public float floatTime = 0.025f; // amount of time spent at max jump height before falling again
|
|
public float coyoteTime = 0.025f;
|
|
|
|
// this has to be public to be readable by the display, which is a code
|
|
// smell.
|
|
public JumpState jumpState;
|
|
private float jumpStateStart;
|
|
|
|
private float jumpVelocity = 8f;
|
|
private float gravity = -20f;
|
|
private Vector3 velocity;
|
|
private MoveController moveController;
|
|
private float velocityXSmoothing;
|
|
|
|
void Start() {
|
|
setJumpState(JumpState.Falling);
|
|
moveController = GetComponent<MoveController>();
|
|
gravity = -(2* jumpHeight) / Mathf.Pow(timeToJumpApex, 2);
|
|
jumpVelocity = Mathf.Abs(gravity) * timeToJumpApex;
|
|
}
|
|
|
|
void Update() {
|
|
Vector2 input = new Vector2(Input.GetAxisRaw("Horizontal"), Input.GetAxisRaw("Vertical"));
|
|
float targetX = input.x * moveSpeed;
|
|
Vector3 initialVelocity = velocity;
|
|
|
|
if (moveController.collisions.above) {
|
|
velocity.y = 0;
|
|
}
|
|
|
|
if (moveController.collisions.left || moveController.collisions.right) {
|
|
velocity.x = 0;
|
|
}
|
|
|
|
switch (jumpState) {
|
|
case JumpState.Grounded:
|
|
if (Input.GetButtonDown("Jump")) {
|
|
setJumpState(JumpState.Ascending);
|
|
velocity.y = jumpVelocity;
|
|
} else {
|
|
velocity.y = gravity * Time.deltaTime;
|
|
}
|
|
velocity.x = Mathf.SmoothDamp(velocity.x, targetX, ref velocityXSmoothing, timeToMaxRunSpeed);
|
|
break;
|
|
|
|
// case JumpState.Ascending:
|
|
// velocity.x = Mathf.SmoothDamp(velocity.x, targetX, ref velocityXSmoothing, timeToMaxAirmoveSpeed);
|
|
// velocity.y += gravity * Time.deltaTime;
|
|
// if (velocity.y < maxFallSpeed) {
|
|
// velocity.y = maxFallSpeed;
|
|
// }
|
|
|
|
// // if we were rising in the last frame but will be falling in this
|
|
// // frame, we should zero out the velocity to float instead.
|
|
// if (initialVelocity.y >= 0 && velocity.y <= 0) {
|
|
// velocity.y = 0;
|
|
// setJumpState(JumpState.Apex);
|
|
// }
|
|
// break;
|
|
|
|
case JumpState.Apex:
|
|
velocity.x = Mathf.SmoothDamp(velocity.x, targetX, ref velocityXSmoothing, timeToMaxAirmoveSpeed);
|
|
float timeFloating = Time.time - jumpStateStart;
|
|
float floatTimeRemaining = floatTime - timeFloating;
|
|
if (floatTimeRemaining < 0) {
|
|
velocity.y += gravity * -floatTimeRemaining;
|
|
setJumpState(JumpState.Descending);
|
|
} else {
|
|
velocity.y = 0;
|
|
}
|
|
break;
|
|
|
|
case JumpState.CoyoteTime:
|
|
velocity.x = Mathf.SmoothDamp(velocity.x, targetX, ref velocityXSmoothing, timeToMaxRunSpeed);
|
|
if (Input.GetButtonDown("Jump")) {
|
|
setJumpState(JumpState.Ascending);
|
|
velocity.y = jumpVelocity;
|
|
} else {
|
|
float elapsedCoyoteTime = Time.time - jumpStateStart;
|
|
float coyoteTimeRemaining = coyoteTime - elapsedCoyoteTime;
|
|
if (coyoteTimeRemaining < 0) {
|
|
velocity.y += gravity * -coyoteTimeRemaining;
|
|
setJumpState(JumpState.Falling);
|
|
} else {
|
|
velocity.y = 0;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
velocity.x = Mathf.SmoothDamp(velocity.x, targetX, ref velocityXSmoothing, timeToMaxAirmoveSpeed);
|
|
velocity.y += gravity * Time.deltaTime;
|
|
if (velocity.y < maxFallSpeed) {
|
|
velocity.y = maxFallSpeed;
|
|
}
|
|
|
|
// if we were rising in the last frame but will be falling in this
|
|
// frame, we should zero out the velocity to float instead.
|
|
if (initialVelocity.y >= 0 && velocity.y <= 0) {
|
|
velocity.y = 0;
|
|
setJumpState(JumpState.Apex);
|
|
}
|
|
break;
|
|
}
|
|
|
|
moveController.Move(velocity * Time.deltaTime);
|
|
if (jumpState == JumpState.Grounded && !moveController.isGrounded) {
|
|
setJumpState(JumpState.CoyoteTime);
|
|
}
|
|
if (jumpState != JumpState.Grounded && moveController.isGrounded) {
|
|
setJumpState(JumpState.Grounded);
|
|
}
|
|
}
|
|
|
|
void OnDestroy() {
|
|
}
|
|
|
|
void OnCollisionEnter(Collision other) {
|
|
}
|
|
|
|
void OnTriggerEnter(Collider other) {
|
|
}
|
|
|
|
void setJumpState(JumpState state) {
|
|
jumpState = state;
|
|
jumpStateStart = Time.time;
|
|
}
|
|
|
|
/*
|
|
|
|
Possible JumpState transitions:
|
|
|
|
Grounded -> Ascending : a normal jump
|
|
Grounded -> CoyoteTime : player has walked off ledge
|
|
CoyoteTime -> Ascending : player has jumped after leaving a ledge
|
|
CoyoteTime -> Falling : player has walked off of a ledge and is now falling
|
|
Ascending -> Apex : player has reached the top of their jump normally
|
|
Apex -> Descending : player has reached the top of their jump and is now falling
|
|
|
|
*/
|
|
public enum JumpState {
|
|
// The player is on the ground
|
|
Grounded,
|
|
|
|
// The player has not jumped; they have walked off of a platform without
|
|
// jumping
|
|
CoyoteTime,
|
|
|
|
// The player is rising in a jump
|
|
Ascending,
|
|
|
|
// The player has reached the apex of their jump, where they will
|
|
// briefly remain to give a feeling of lightness
|
|
Apex,
|
|
|
|
// The player, having jumped, is in a controlled descent following the
|
|
// jump
|
|
Descending,
|
|
|
|
// The player is descending but without control; they are falling but
|
|
// did not initially jump.
|
|
Falling,
|
|
}
|
|
}
|