Skip to content

Instantly share code, notes, and snippets.

@MadLittleMods
Last active March 15, 2022 09:24
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save MadLittleMods/10935622 to your computer and use it in GitHub Desktop.
Save MadLittleMods/10935622 to your computer and use it in GitHub Desktop.
Unity Character Driver/Controller for Movement, Jumping, and Gravity
using UnityEngine;
using System.Collections;
[RequireComponent (typeof(CharacterController))]
public class CharacterDriver : MonoBehaviour {
public class CharacterState
{
public Vector3 position = new Vector3();
public Vector3 velocity = new Vector3();
public CharacterState()
{
}
public CharacterState(CharacterState s)
{
this.position = s.position;
this.velocity = s.velocity;
}
public CharacterState(Vector3 position,Vector3 velocity)
{
this.position = position;
this.velocity = velocity;
}
public static CharacterState Lerp(CharacterState from, CharacterState to, float t)
{
return new CharacterState(Vector3.Lerp(from.position, to.position, t), Vector3.Lerp(from.velocity, to.velocity, t));
}
public static implicit operator string(CharacterState s)
{
return s.ToString();
}
public string ToString()
{
return "p: " + this.position + " v: " + this.velocity;
}
}
public float maxSurgeSpeed = 5f; // Forward, backward
public float maxSwaySpeed = 5f; // Side to side
public float jumpHeight = 4f;
CharacterController characterController;
// We use these to smooth between values in certain framerate situations in the `Update()` loop
CharacterState currentState = new CharacterState();
CharacterState previousState = new CharacterState();
// Use this for initialization
void Start () {
this.characterController = GetComponent<CharacterController>();
this.ResetCharacterDriver();
}
// Use this to reset any built up forces
[ContextMenu("Reset Character State")]
void ResetCharacterDriver()
{
// Set the transition state
this.currentState = new CharacterState(transform.position, Vector3.zero);
this.previousState = this.currentState;
}
float t = 0f;
float dt = 0.01f;
float currentTime = 0f;
float accumulator = 0f;
bool isFirstPhysicsFrame = true;
// Update is called once per frame
void Update ()
{
// Fixed deltaTime rendering at any speed with smoothing
// Technique: http://gafferongames.com/game-physics/fix-your-timestep/
float frameTime = Time.time - currentTime;
this.currentTime = Time.time;
this.accumulator += frameTime;
while (this.accumulator >= this.dt)
{
this.previousState = this.currentState;
this.currentState = this.MoveUpdate(this.currentState, this.dt);
//integrate(state, this.t, this.dt);
Vector3 movementDelta = currentState.position - transform.position;
this.characterController.Move(movementDelta);
this.currentState = new CharacterState(transform.position, this.currentState.velocity);
accumulator -= this.dt;
this.t += this.dt;
}
// Reset it
this.isFirstPhysicsFrame = true;
}
CharacterState MoveUpdate(CharacterState state, float deltaTime)
{
CharacterState currentState = new CharacterState(state);
// Add the gravity
if(this.characterController.isGrounded)
{
// Remove the gravity in the direction we hit (ground)
currentState.velocity -= Vector3.Project(currentState.velocity, Physics.gravity.normalized);
}
currentState.velocity += Physics.gravity * deltaTime;
// Jumping
if(this.characterController.isGrounded && Input.GetButtonDown("Jump") && this.isFirstPhysicsFrame)
{
// Play jump sound effect here
// Jump the player
currentState.velocity += -1f * Physics.gravity.normalized * this.CalculateJumpVerticalSpeed(this.jumpHeight);
}
// Movement Surge and Sway
// Elliptical player/character movement. See diagram for more info:
// http://i.imgur.com/am2OYj1.png
float angle = Mathf.Atan2(Input.GetAxis("Vertical"), Input.GetAxis("Horizontal"));
float surgeSpeed = Mathf.Abs(Input.GetAxis("Vertical")) * this.maxSurgeSpeed * Mathf.Sin(angle); // Forward and Backward
float swaySpeed = Mathf.Abs(Input.GetAxis("Horizontal")) * this.maxSwaySpeed * Mathf.Cos(angle); // Left and Right
// Get the camera directions without the Y component
Vector3 cameraForwardNoY = Vector3.Scale(Camera.main.transform.forward, new Vector3(1, 0, 1)).normalized;
Vector3 cameraRightNoY = Vector3.Scale(Camera.main.transform.right, new Vector3(1, 0, 1)).normalized;
Vector3 movementDelta = (cameraForwardNoY*surgeSpeed + cameraRightNoY*swaySpeed) * deltaTime;
movementDelta += currentState.velocity * deltaTime;
currentState.position += movementDelta;
// Set this so we don't get confused later on
this.isFirstPhysicsFrame = false;
return currentState;
}
float CalculateJumpVerticalSpeed(float targetJumpHeight)
{
// From the jump height and gravity we deduce the upwards speed
// for the character to reach at the apex.
// See for formula: http://math.stackexchange.com/a/222585/60008
return Mathf.Sqrt(2f * targetJumpHeight * Physics.gravity.magnitude);
}
}
@gakkossphynx
Copy link

cool,thanks for sharing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment