Created
July 17, 2022 08:22
-
-
Save drusepth/4ec93172f67e3421d7c65a96986fa80d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEditor; | |
using UnityEngine; | |
public class HoverboardController : MonoBehaviour | |
{ | |
public float multiplier; // How much force to exert on the ground to keep afloat | |
// This would be super cool to lerp off hoverboard battery level | |
// Potential game loop: find batteries? | |
// Design: we could also put the battery bar [|||||] on the back of the hoverboard | |
// These two attributes would be great to manipulate THPS3-style by introducing multiple boards | |
// that are better/worse at turning, speed, etc | |
public float move_force = 500; | |
public float acceleration_torque = 150; | |
public float turn_torque = 150; | |
public float lean_torque = 500; | |
public float jump_force = 5000f; | |
// TODO use these instead (charge up jump force by crouching) | |
/* | |
public float minimum_jump_force = 50000f; | |
public float crouch_jump_force_increase = 10000f; | |
public float maximum_jump_force = 80000f; | |
*/ | |
public float float_height = 1f; // Distance to ground to be "grounded" | |
public float angular_righting_force = 1f; // TODO implement this for leveling out in the air | |
private Rigidbody body; | |
public Transform[] anchors = new Transform[4]; | |
private RaycastHit[] hits = new RaycastHit[4]; | |
private Camera main_camera; | |
private Transform default_position; | |
void Start() | |
{ | |
body = GetComponent<Rigidbody>(); | |
main_camera = Camera.main; | |
default_position = transform; | |
} | |
void Update() | |
{ | |
HandleJumpInput(); | |
} | |
void FixedUpdate() | |
{ | |
// Apply an upward force from each of the board's 4 corners to keep it "floating" | |
for (int i = 0; i < anchors.Length; i++) | |
ApplyHoverForceAtPoint(anchors[i], hits[i]); | |
HandleForwardBackwardMovement(); | |
HandleTurningMovement(); | |
// When we're in the air, we should slowly right ourselves back to "level" | |
if (IsFullyAirborn()) | |
transform.rotation = Quaternion.Lerp(transform.rotation, default_position.rotation, Time.time * angular_righting_force); | |
} | |
void HandleForwardBackwardMovement() | |
{ | |
float forward_force = Input.GetAxis("Vertical"); | |
// For rad cinematic jumps we switch our "forward" to the camera's "forward" instead of the | |
// player's "forward" when we're fully in the air, which allows for more airtime and better | |
// framing with the character-following camera. | |
if (IsFullyAirborn() && main_camera.transform.position.y > transform.position.y) | |
body.AddForce(forward_force * move_force * main_camera.transform.forward); | |
else | |
body.AddForce(forward_force * move_force * transform.forward); | |
// If we're on the ground, we also tilt the front/back of the board to signal acceleration/deceleration | |
if (IsFullyGrounded()) | |
body.AddTorque(forward_force * acceleration_torque * main_camera.transform.right); | |
} | |
void HandleTurningMovement() | |
{ | |
float turning_force = Input.GetAxis("Horizontal"); | |
body.AddTorque(turning_force * turn_torque * transform.up); | |
// TODO: we should increase the turn_torque when we're in the air for tricks | |
if (IsFullyGrounded()) | |
body.AddTorque(turning_force * lean_torque * -transform.forward); | |
} | |
void HandleJumpInput() | |
{ | |
if (Input.GetKeyUp(KeyCode.Space) && IsFullyGrounded()) | |
body.AddForce(jump_force * transform.up); | |
} | |
void ApplyHoverForceAtPoint(Transform anchor, RaycastHit hit) | |
{ | |
// If this anchor is grounded, apply an upward force to float | |
if (IsGrounded(anchor, out hit)) | |
{ | |
float force = Mathf.Abs(1 / (hit.point.y - anchor.position.y)); | |
body.AddForceAtPosition(transform.up * force * multiplier, anchor.position, ForceMode.Acceleration); | |
} | |
} | |
bool IsGrounded(Transform anchor) => Physics.Raycast(anchor.position, -anchor.up, float_height); | |
bool IsGrounded(Transform anchor, out RaycastHit hit) => Physics.Raycast(anchor.position, -anchor.up, out hit, float_height); | |
bool IsFullyGrounded() | |
{ | |
bool fully_grounded = true; | |
for (int i = 0; i < 4; i++) | |
if (!IsGrounded(anchors[i])) | |
return false; | |
return fully_grounded; | |
} | |
bool IsFullyAirborn() | |
{ | |
bool fully_airborn = true; | |
for (int i = 0; i < 4; i++) | |
if (IsGrounded(anchors[i])) | |
return false; | |
return fully_airborn; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment