Last active
April 5, 2023 06:38
-
-
Save zalo/d9d423680ca92fcca98b02605f885e12 to your computer and use it in GitHub Desktop.
Physics-Based Unity Player Controller
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 UnityEngine; | |
public class MovingPlatform : MonoBehaviour { | |
public float timeInterval = 5f; | |
public AnimationCurve XMotion; | |
public AnimationCurve YMotion; | |
public AnimationCurve ZMotion; | |
public bool PingPong = true; | |
float platformTime; | |
bool ping = true; | |
Vector3 initialPosition; | |
Quaternion initialRotation; | |
Rigidbody body; | |
void Start () { | |
body = GetComponent<Rigidbody>(); | |
initialPosition = transform.position; | |
initialRotation = transform.rotation; | |
} | |
void FixedUpdate () { | |
if (PingPong) { | |
if (ping) { | |
platformTime += Time.fixedDeltaTime; | |
if (platformTime > timeInterval) { | |
ping = false; | |
platformTime = platformTime - (platformTime - timeInterval); | |
} | |
} else { | |
platformTime -= Time.fixedDeltaTime; | |
if (platformTime < 0f) { | |
ping = true; | |
platformTime *= -1f; | |
} | |
} | |
}else{ | |
ping = true; | |
platformTime = Mathf.Repeat(Time.fixedTime, timeInterval); | |
} | |
Vector3 curPos = evaluatePositionAtTime(platformTime); | |
Vector3 prevPos = evaluatePositionAtTime(platformTime + (Time.fixedDeltaTime * (ping ? -1f : 1f))); | |
body.MovePosition(curPos); | |
body.velocity = ((curPos - prevPos) / Time.fixedDeltaTime); | |
} | |
private void OnDrawGizmosSelected() { | |
if (!Application.isPlaying) { | |
initialPosition = transform.position; | |
initialRotation = transform.rotation; | |
} | |
float step = 0.01f; | |
for(float i = 0f; i<1f; i += step) { | |
Gizmos.color = Color.HSVToRGB(i, 1f, 1f); | |
Gizmos.DrawLine(evaluatePositionAtTime(i*timeInterval), evaluatePositionAtTime((i + step) * timeInterval)); | |
} | |
} | |
Vector3 evaluatePositionAtTime(float time) { | |
return initialPosition + (initialRotation * new Vector3(XMotion.Evaluate(time / timeInterval), YMotion.Evaluate(time / timeInterval), ZMotion.Evaluate(time / timeInterval))); | |
} | |
} |
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
//See this image for set up information: http://i.imgur.com/pzfuzLn.png | |
//Don't forget to freeze the rotation on your rigidbody! | |
using System.Collections; | |
using System.Collections.Generic; | |
using UnityEngine; | |
public class PlayerMovement : MonoBehaviour { | |
Camera cam; | |
Rigidbody body; | |
bool jumpPressed; | |
//Collision State | |
List<Collider> colliding = new List<Collider>(); | |
Collider groundCollider = new Collider(); | |
Rigidbody groundRigidbody = new Rigidbody(); | |
Vector3 groundNormal = Vector3.down; | |
Vector3 groundContactPoint = Vector3.zero; | |
Vector3 groundVelocity = Vector3.zero; | |
//Initialize variables | |
void Start() { | |
cam = GetComponentInChildren<Camera>(); | |
body = GetComponent<Rigidbody>(); | |
} | |
//Movement Handling | |
void FixedUpdate() { | |
//Record the world-space walking movement | |
Vector3 movement = transform.rotation * new Vector3(Input.GetAxisRaw("Horizontal"), 0f, Input.GetAxisRaw("Vertical")).normalized; | |
//If we're currently contacting a wall/ground like object | |
if (groundCollider != null && Vector3.Dot(Vector3.up, groundNormal) > -0.3f) { | |
//Subtract the ground's velocity | |
if (groundRigidbody != null && groundRigidbody.isKinematic) { | |
body.velocity -= groundVelocity; | |
} | |
//Walking along the ground movement | |
if (Vector3.Dot(Vector3.up, groundNormal) > 0.5f) { | |
if (movement != Vector3.zero) { | |
Vector2 XYVel = new Vector2(body.velocity.x, body.velocity.z); | |
XYVel = Mathf.Clamp(XYVel.magnitude, 0f, 3f) * XYVel.normalized; | |
body.velocity = new Vector3(XYVel.x, body.velocity.y, XYVel.y); | |
} else { | |
body.velocity = new Vector3(body.velocity.x * 0.8f, body.velocity.y, body.velocity.z * 0.8f); | |
} | |
body.velocity += movement; | |
} | |
//Handle jumping | |
if (jumpPressed && body.velocity.y <= 0.1f) { body.velocity += Vector3.Slerp(Vector3.up, groundNormal, 0.2f) * 6f; } | |
//Draw some debug info | |
Debug.DrawLine(groundContactPoint, groundContactPoint + groundNormal, Color.blue, 2f); | |
//Add back the ground's velocity | |
if (groundRigidbody != null && groundRigidbody.isKinematic) { | |
groundVelocity = groundRigidbody.GetPointVelocity(groundContactPoint); | |
body.velocity += groundVelocity; | |
} | |
} else { | |
body.velocity += movement * 0.1f; | |
groundVelocity = Vector3.zero; | |
} | |
groundNormal = Vector3.down; | |
groundCollider = null; | |
groundRigidbody = null; | |
groundContactPoint = (transform.position - Vector3.down * -0.5f); | |
jumpPressed = false; | |
} | |
//Per-Frame Updates | |
void Update() { | |
//Record whether the jump key was hit this frame | |
//NOTE: Must be done in Update, not FixedUpdate | |
jumpPressed = jumpPressed ? jumpPressed : Input.GetButtonDown("Jump"); | |
//Rotate the player | |
transform.Rotate(0, (Input.GetAxis("Mouse X")) * 2f, 0); | |
//Rotate the camera rig and prevent it from penetrating the environment | |
RaycastHit hit; | |
cam.transform.parent.localRotation *= Quaternion.Euler(-Input.GetAxis("Mouse Y") * 2f, 0, 0); | |
cam.transform.localPosition = (Physics.SphereCast(cam.transform.parent.position, cam.nearClipPlane * 0.5f, -cam.transform.parent.forward, out hit, 3f) ? (Vector3.back * hit.distance) : Vector3.back * 3f); | |
} | |
//Ground Collision Handling | |
void OnCollisionEnter(Collision collision) { | |
colliding.Add(collision.collider); | |
} | |
void OnCollisionStay(Collision collision) { | |
if (collision.impulse.magnitude > float.Epsilon) { | |
if (!colliding.Contains(collision.collider)) { | |
colliding.Add(collision.collider); | |
} | |
//Record ground telemetry | |
for (int i = 0; i < collision.contacts.Length; i++) { | |
if (Vector3.Dot(Vector3.up, collision.contacts[i].normal) > Vector3.Dot(Vector3.up, groundNormal)) { | |
groundNormal = collision.contacts[i].normal; | |
groundCollider = collision.collider; | |
groundContactPoint = collision.contacts[i].point; | |
groundRigidbody = collision.rigidbody; | |
if (groundRigidbody != null && groundVelocity == Vector3.zero) { | |
groundVelocity = groundRigidbody.GetPointVelocity(groundContactPoint); | |
} | |
} | |
} | |
} | |
} | |
void OnCollisionExit(Collision collision) { | |
colliding.Remove(collision.collider); | |
if (colliding.Count == 0) { | |
groundVelocity = Vector3.zero; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment