Files
spacerace/Assets/Src/ShipControls.cs
T
2023-08-09 17:23:19 +10:00

220 lines
7.5 KiB
C#
Executable File

using System;
using UnityEngine;
using UnityEngine.InputSystem;
public class ShipControls : MonoBehaviour, SpaceRaceInput.IShipActions {
public Camera aim;
public Timing timing;
public PowerUnit powerUnit = new();
SpaceRaceInput input;
InputAction lookAction;
InputAction accelerateAction;
InputAction decelerateAction;
Rigidbody rigidBody;
Vector3 initialPosition;
Vector3 initialForce;
Quaternion initialAim;
ForceMode forceMode;
Vector3 thrust;
Vector3 strafe;
// Camera Controls
float camPitch;
float camYaw;
float clampAngle = 90.0f;
void Start() {
Cursor.lockState = CursorLockMode.Locked;
rigidBody = GetComponent<Rigidbody>();
// just stop the body from being affected by rotation for now
// until the 3p camera is in to explain why
rigidBody.freezeRotation = true;
initialPosition = rigidBody.transform.position;
initialAim = rigidBody.transform.rotation;
initialForce = Vector3.forward;
thrust = Vector3.zero;
strafe = Vector3.zero;
camPitch = initialAim.eulerAngles.x;
camYaw = initialAim.eulerAngles.y;
forceMode = ForceMode.Acceleration;
if (input == null) {
input = new SpaceRaceInput();
input.ship.SetCallbacks(this);
}
input.ship.Enable();
lookAction = input.FindAction("look");
accelerateAction = input.FindAction("accelerate");
decelerateAction = input.FindAction("decelerate");
Respawn();
}
void OnDestroy() {
input.ship.RemoveCallbacks(this);
}
// to minimise input lag we poll for the thrust vector every frame and set it
// same with the camera, we always look around
void Update() {
UpdateCamera();
thrust = getThrust();
}
void FixedUpdate() {
// when you hit the trigger... GO
// needs to be done here in fixedUpdate because otherwise the input is checked on every frame
// so they will have already hit the button before this tick and they actually start moving
// aka ripoff
bool shouldStartTimer = !timing.timerEnabled && (thrust != Vector3.zero || strafe != Vector3.zero);
if (shouldStartTimer)
timing.StartTimer();
// the ship being propelled forward
// this is in world space because of the xform from the camera pos
//
rigidBody.AddForce(thrust, forceMode);
// moving side to side
// this is relative because it's easy to just multiply by the strafe vector
rigidBody.AddRelativeForce(strafe, forceMode);
// rotating towards the camera's orientation
// not being done by a force because of strange behaviour
// needs investigation
float step = powerUnit.Stabilisation * Time.fixedDeltaTime;
// stop the ship jiggling because of micro camera movement
if (Quaternion.Angle(aim.transform.rotation, rigidBody.rotation) > 1f)
rigidBody.rotation = Quaternion.RotateTowards(transform.rotation, aim.transform.rotation, step);
powerUnit.ShieldsRegenerate();
}
void UpdateCamera() {
// there's some hokey scaling that went on with the old input
// we were originally using
// in the action mapping the mouse is scaled by 0.05
// delta *= 0.5f; // Account for scaling applied directly in Windows code by old input system.
// delta *= 0.1f; // Account for sensitivity setting on old Mouse X and Y axes.
// def needs to be configurable
Vector2 lookDelta = lookAction.ReadValue<Vector2>();
camYaw += lookDelta.x;
camPitch -= lookDelta.y;
camPitch = Mathf.Clamp(camPitch, -clampAngle, clampAngle);
aim.transform.eulerAngles = new Vector3(camPitch, camYaw, 0.0f);
}
public void OnStrafe(InputAction.CallbackContext ctx) {
Vector2 str = ctx.ReadValue<Vector2>();
strafe = new Vector3(str.x, str.y, 0f) * powerUnit.Strafing;
}
// if you are decelerating you can't accelerate as well
// otherwise you can flip the ship around and
// decelerate + accelerate against the velocity vector
// aka cheating?
Vector3 getThrust() {
float accelerateInput = accelerateAction.ReadValue<float>();
float decelerateInput = decelerateAction.ReadValue<float>();
// decelerates the ship against the direction it is moving
if (decelerateInput > 0f) {
// the velocity is already in world space so we just invert it
return rigidBody.velocity.normalized * -1f * powerUnit.Deceleration * decelerateInput;
}
// thrust in the direction of the camera
if (accelerateInput > 0f)
// transform from the camera's forward vector into world space
return aim.transform.TransformDirection(Vector3.forward) * powerUnit.Acceleration * accelerateInput;
return Vector3.zero;
}
public void OnQuit(InputAction.CallbackContext ctx) {
Application.Quit();
}
public void OnRespawn(InputAction.CallbackContext ctx) {
Respawn();
}
public void Respawn() {
// IMPORTANT
// stop the timer before we move the ship or anything
// otherwise it might generate a checkpoint time
// for the final sector
timing.StopTimer();
thrust = new Vector3(0.0f, 0.0f, 0.0f);
transform.position = initialPosition;
rigidBody.transform.forward = initialForce;
rigidBody.velocity = new Vector3(0f, 0f, 0f);
rigidBody.angularVelocity = new Vector3(0f, 0f, 0f);
rigidBody.transform.rotation = initialAim;
aim.transform.rotation = initialAim;
camPitch = initialAim.eulerAngles.x;
camYaw = initialAim.eulerAngles.y;
powerUnit.Init();
}
void OnDrawGizmosSelected() {
if (Application.isPlaying == false)
return;
Gizmos.color = Color.red;
Vector3 right = aim.transform.TransformDirection(Vector3.right) * 10;
Gizmos.DrawRay(transform.position, right);
Gizmos.color = Color.green;
Vector3 direction = aim.transform.TransformDirection(Vector3.up) * 10;
Gizmos.DrawRay(transform.position, direction);
Gizmos.color = Color.blue;
Vector3 forward = aim.transform.TransformDirection(Vector3.forward) * 10;
Gizmos.DrawRay(transform.position, forward);
Gizmos.color = Color.yellow;
Vector3 velocity = rigidBody.velocity;
Gizmos.DrawRay(transform.position, velocity);
Gizmos.color = Color.cyan;
Gizmos.DrawRay(transform.position, thrust);
}
public float Speed() {
return rigidBody.velocity.magnitude;
}
public void Damage(float amt, string src) {
Debug.Log($"Damage {amt} from {src}");
bool destroyed = powerUnit.ShieldsReduce(amt);
if (destroyed) {
Debug.Log($"Ddddestroyed by {src}");
Respawn();
}
}
// We don't use these because we poll instead
// the callbacks are only invoked when the value changes
// aka if you hold accelerate it doesn't do what you expect
public void OnAccelerate(InputAction.CallbackContext ctx) { }
public void OnDecelerate(InputAction.CallbackContext ctx) { }
public void OnLook(InputAction.CallbackContext ctx) { }
}