TheMuseumProject/Assets/Scripts/Player/Movement/PlayerPhysics.cs

208 lines
7.4 KiB
C#
Raw Normal View History

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));
}
}
}