208 lines
7.4 KiB
C#
208 lines
7.4 KiB
C#
|
using Player.Interactions;
|
||
|
using UnityEngine;
|
||
|
using Player.Information;
|
||
|
namespace Player.Movement
|
||
|
{
|
||
|
public class PlayerPhysics : MonoBehaviour
|
||
|
{
|
||
|
// measured in meters per second squared
|
||
|
[SerializeField] private Vector3 gravity;
|
||
|
|
||
|
[SerializeField] private float walkingForce;
|
||
|
|
||
|
[SerializeField] private float maxWalkSpeed;
|
||
|
|
||
|
[SerializeField] private float maxRunSpeed;
|
||
|
|
||
|
// measured in N applied when space is pressed
|
||
|
[SerializeField] private float jumpForce;
|
||
|
|
||
|
[SerializeField] private float defaultAirControl;
|
||
|
|
||
|
// the minimum change in speed which will result in damage being taken
|
||
|
[SerializeField] private float speedDamageThreshold;
|
||
|
|
||
|
// the ratio of speed change to damage taken
|
||
|
[SerializeField] private float speedToDamage;
|
||
|
|
||
|
|
||
|
// measured in seconds
|
||
|
[SerializeField] private float coyoteTime;
|
||
|
|
||
|
[SerializeField] private float jumpBuffer;
|
||
|
|
||
|
// current air control ratio experienced by the player
|
||
|
private float airControl;
|
||
|
private float coyoteTimeCounter;
|
||
|
|
||
|
|
||
|
// reference to GrappleHook script
|
||
|
private GrappleHook grappleHook;
|
||
|
|
||
|
// reference to JetPack script
|
||
|
private JetPack jetPack;
|
||
|
private float jumpBufferCounter;
|
||
|
|
||
|
// current maximum input speed of the player
|
||
|
private float maxSpeed;
|
||
|
|
||
|
// referendce to PlayerStats script
|
||
|
private PlayerStats playerStats;
|
||
|
|
||
|
// metrics for ground detection
|
||
|
//private float playerHeight;
|
||
|
//private Vector3 boxDim;
|
||
|
|
||
|
// speed of the player in the previous frame
|
||
|
private float prevFrameSpeed;
|
||
|
|
||
|
private Rigidbody rb;
|
||
|
|
||
|
public void Reset()
|
||
|
{
|
||
|
prevFrameSpeed = 0f;
|
||
|
rb.velocity = Vector3.zero;
|
||
|
grappleHook.ReleaseGrapple();
|
||
|
jetPack.ResetThrust();
|
||
|
}
|
||
|
|
||
|
// Start is called before the first frame update
|
||
|
private void Start()
|
||
|
{
|
||
|
rb = gameObject.GetComponent<Rigidbody>();
|
||
|
|
||
|
// ground detection constants
|
||
|
//playerHeight = (transform.localScale.y / 2f);
|
||
|
//Vector3 boxDim = transform.localScale;
|
||
|
//boxDim = new Vector3(boxDim.x - 0.5f, boxDim.y + 0.5f, boxDim.z - 0.5f);
|
||
|
|
||
|
maxSpeed = maxWalkSpeed;
|
||
|
airControl = defaultAirControl;
|
||
|
|
||
|
grappleHook = gameObject.GetComponent<GrappleHook>();
|
||
|
jetPack = gameObject.GetComponent<JetPack>();
|
||
|
playerStats = gameObject.GetComponent<PlayerStats>();
|
||
|
prevFrameSpeed = 0f;
|
||
|
}
|
||
|
|
||
|
// Update is called once per frame
|
||
|
private void Update()
|
||
|
{
|
||
|
var grounded = isGrounded();
|
||
|
|
||
|
// coyote time manager
|
||
|
if (grounded)
|
||
|
coyoteTimeCounter = coyoteTime;
|
||
|
else
|
||
|
coyoteTimeCounter -= Time.deltaTime;
|
||
|
|
||
|
// jump buffer manager
|
||
|
if (Input.GetButtonDown("Jump") )
|
||
|
jumpBufferCounter = jumpBuffer;
|
||
|
else
|
||
|
jumpBufferCounter -= Time.deltaTime;
|
||
|
|
||
|
//Debug.Log("Coyote: " + coyoteTimeCounter + ". Buffer: " + jumpBufferCounter);
|
||
|
|
||
|
// if jump key is pressed
|
||
|
if (coyoteTimeCounter > 0f && jumpBufferCounter > 0f)
|
||
|
{
|
||
|
Debug.Log("jump");
|
||
|
// apply an upward force to the player
|
||
|
rb.AddForce(new Vector3(0f, jumpForce, 0f));
|
||
|
|
||
|
coyoteTimeCounter = 0f;
|
||
|
jumpBufferCounter = 0f;
|
||
|
}
|
||
|
|
||
|
// change current max speed depending on sprinting or not
|
||
|
if (Input.GetKey(KeyCode.LeftShift) && grounded )
|
||
|
maxSpeed = maxRunSpeed;
|
||
|
else
|
||
|
maxSpeed = maxWalkSpeed;
|
||
|
}
|
||
|
|
||
|
private void FixedUpdate()
|
||
|
{
|
||
|
// get the input values for player movement
|
||
|
var movement = GetMoveInputs();
|
||
|
// calculate the velocity change of the player based on input
|
||
|
movement = movement.normalized * walkingForce;
|
||
|
|
||
|
// scale movement force if not on ground
|
||
|
if (!isGrounded()) movement *= airControl;
|
||
|
|
||
|
var relativeMove = transform.right * movement.x + transform.forward * movement.z;
|
||
|
var flatCurVelocity = Vector3.ProjectOnPlane(rb.velocity, transform.up);
|
||
|
|
||
|
// calculate the velocity the player would have when adding input velocity to it
|
||
|
var nextVelocity = flatCurVelocity + relativeMove * Time.deltaTime;
|
||
|
|
||
|
// check if the player's next velocity has a magnitude above walking speed
|
||
|
if (nextVelocity.magnitude > maxSpeed)
|
||
|
{
|
||
|
// if the player is currently moving below their maxSpeed and trying to accelerate up to it
|
||
|
if (flatCurVelocity.magnitude < maxSpeed)
|
||
|
// scale the player's next velocity to be equal to their maxSpeed
|
||
|
nextVelocity = nextVelocity.normalized * maxSpeed;
|
||
|
else
|
||
|
// else, scale the player's next velocity to equal their current speed
|
||
|
nextVelocity = nextVelocity.normalized * flatCurVelocity.magnitude;
|
||
|
}
|
||
|
|
||
|
// set the player's current velocity to their next velocity in the xz-plane
|
||
|
rb.velocity = new Vector3(nextVelocity.x, rb.velocity.y, nextVelocity.z);
|
||
|
|
||
|
// apply the force of a potential grapple hook to the player
|
||
|
rb.AddForce(grappleHook.PullForce(transform.position));
|
||
|
|
||
|
// apply the force of a potential jetpack to the player
|
||
|
rb.AddForce(jetPack.ThrustForce());
|
||
|
|
||
|
// apply the force of gravity to the player
|
||
|
rb.AddForce(gravity, ForceMode.Acceleration);
|
||
|
|
||
|
// calculate the change in player speed this frame
|
||
|
var deltaSpeed = Mathf.Abs(rb.velocity.magnitude - prevFrameSpeed);
|
||
|
|
||
|
// apply force damage to player depending on change in speed
|
||
|
if (deltaSpeed > speedDamageThreshold)
|
||
|
//Debug.Log(deltaSpeed - speedDamageThreshold);
|
||
|
playerStats.ChangeHealth(-speedToDamage * (deltaSpeed - speedDamageThreshold));
|
||
|
// update speed record for next frame
|
||
|
prevFrameSpeed = rb.velocity.magnitude;
|
||
|
|
||
|
//Debug.Log(isGrounded());
|
||
|
}
|
||
|
|
||
|
private void OnTriggerEnter(Collider other)
|
||
|
{
|
||
|
var tp = other.gameObject.GetComponent<TraversalProperties>();
|
||
|
if (tp != null && tp.lethalToEnter) playerStats.Respawn();
|
||
|
}
|
||
|
|
||
|
public Vector3 GetMoveInputs()
|
||
|
{
|
||
|
var xzMove = Vector3.zero;
|
||
|
if (Input.GetKey(KeyCode.W)) xzMove.z += 1f;
|
||
|
if (Input.GetKey(KeyCode.S)) xzMove.z += -1f;
|
||
|
if (Input.GetKey(KeyCode.D)) xzMove.x += 1f;
|
||
|
if (Input.GetKey(KeyCode.A)) xzMove.x += -1f;
|
||
|
return xzMove;
|
||
|
}
|
||
|
|
||
|
public bool isGrounded()
|
||
|
{
|
||
|
// Raycast using ray
|
||
|
//return Physics.Raycast(transform.position, -Vector3.up, playerHeight + 0.1f);
|
||
|
|
||
|
// Raycast using box
|
||
|
//Vector3 boxCenter = transform.position - new Vector3(0f, playerHeight, 0f);
|
||
|
//return Physics.CheckBox(boxCenter, boxDim);
|
||
|
|
||
|
// Raycast using box hardcoded
|
||
|
var boxCenter = transform.position - new Vector3(0f, 0.5f, 0f);
|
||
|
return Physics.CheckBox(boxCenter, new Vector3(0.25f, 0.52f, 0.25f));
|
||
|
}
|
||
|
}
|
||
|
}
|