220 lines
6.6 KiB
C#
220 lines
6.6 KiB
C#
using UnityEngine;
|
|
|
|
//Example implementation of the SuperStateMachine and SuperCharacterController
|
|
[RequireComponent(typeof(SuperCharacterController))]
|
|
[RequireComponent(typeof(PlayerInputController))]
|
|
public class PlayerMachine : SuperStateMachine
|
|
{
|
|
public Transform AnimatedMesh;
|
|
|
|
public float WalkSpeed = 4.0f;
|
|
public float WalkAcceleration = 30.0f;
|
|
public float JumpAcceleration = 5.0f;
|
|
public float JumpHeight = 3.0f;
|
|
public float Gravity = 25.0f;
|
|
|
|
// Add more states by comma separating them
|
|
enum PlayerStates { Idle, Walk, Jump, Fall }
|
|
|
|
private SuperCharacterController controller;
|
|
|
|
// current velocity
|
|
private Vector3 moveDirection;
|
|
// current direction our character's art is facing
|
|
public Vector3 lookDirection { get; private set; }
|
|
|
|
private PlayerInputController input;
|
|
|
|
void Start()
|
|
{
|
|
input = gameObject.GetComponent<PlayerInputController>();
|
|
|
|
// Grab the controller object from our object
|
|
controller = gameObject.GetComponent<SuperCharacterController>();
|
|
|
|
// Our character's current facing direction, planar to the ground
|
|
lookDirection = transform.forward;
|
|
|
|
// Set our currentState to idle on startup
|
|
currentState = PlayerStates.Idle;
|
|
}
|
|
|
|
protected override void EarlyGlobalSuperUpdate()
|
|
{
|
|
// Rotate out facing direction horizontally based on mouse input
|
|
// (Taking into account that this method may be called multiple times per frame)
|
|
lookDirection = Quaternion.AngleAxis(input.Current.MouseInput.x * (controller.deltaTime / Time.deltaTime), controller.up) * lookDirection;
|
|
// Put any code in here you want to run BEFORE the state's update function.
|
|
// This is run regardless of what state you're in
|
|
}
|
|
|
|
protected override void LateGlobalSuperUpdate()
|
|
{
|
|
// Put any code in here you want to run AFTER the state's update function.
|
|
// This is run regardless of what state you're in
|
|
|
|
// Move the player by our velocity every frame
|
|
transform.position += moveDirection * controller.deltaTime;
|
|
|
|
// Rotate our mesh to face where we are "looking"
|
|
AnimatedMesh.rotation = Quaternion.LookRotation(lookDirection, controller.up);
|
|
}
|
|
|
|
private bool AcquiringGround()
|
|
{
|
|
return controller.currentGround.IsGrounded(false, 0.01f);
|
|
}
|
|
|
|
private bool MaintainingGround()
|
|
{
|
|
return controller.currentGround.IsGrounded(true, 0.5f);
|
|
}
|
|
|
|
public void RotateGravity(Vector3 up)
|
|
{
|
|
lookDirection = Quaternion.FromToRotation(transform.up, up) * lookDirection;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Constructs a vector representing our movement local to our lookDirection, which is
|
|
/// controlled by the camera
|
|
/// </summary>
|
|
private Vector3 LocalMovement()
|
|
{
|
|
Vector3 right = Vector3.Cross(controller.up, lookDirection);
|
|
Vector3 local = Vector3.zero;
|
|
|
|
if(input.Current.MoveInput.x != 0)
|
|
{
|
|
local += right * input.Current.MoveInput.x;
|
|
}
|
|
|
|
if(input.Current.MoveInput.z != 0)
|
|
{
|
|
local += lookDirection * input.Current.MoveInput.z;
|
|
}
|
|
|
|
return local.normalized;
|
|
}
|
|
|
|
// Calculate the initial velocity of a jump based off gravity and desired maximum height attained
|
|
private float CalculateJumpSpeed(float jumpHeight, float gravity)
|
|
{
|
|
return Mathf.Sqrt(2 * jumpHeight * gravity);
|
|
}
|
|
|
|
/*void Update () {
|
|
* Update is normally run once on every frame update. We won't be using it
|
|
* in this case, since the SuperCharacterController component sends a callback Update
|
|
* called SuperUpdate. SuperUpdate is recieved by the SuperStateMachine, and then fires
|
|
* further callbacks depending on the state
|
|
}*/
|
|
|
|
// Below are the three state functions. Each one is called based on the name of the state,
|
|
// so when currentState = Idle, we call Idle_EnterState. If currentState = Jump, we call
|
|
// Jump_SuperUpdate()
|
|
void Idle_EnterState()
|
|
{
|
|
controller.EnableSlopeLimit();
|
|
controller.EnableClamping();
|
|
}
|
|
|
|
// Run every frame we are in the idle state
|
|
void Idle_SuperUpdate()
|
|
{
|
|
if(input.Current.JumpInput)
|
|
{
|
|
currentState = PlayerStates.Jump;
|
|
return;
|
|
}
|
|
|
|
if(!MaintainingGround())
|
|
{
|
|
currentState = PlayerStates.Fall;
|
|
return;
|
|
}
|
|
|
|
if(input.Current.MoveInput != Vector3.zero)
|
|
{
|
|
currentState = PlayerStates.Walk;
|
|
return;
|
|
}
|
|
|
|
// Apply friction to slow us to a halt
|
|
moveDirection = Vector3.MoveTowards(moveDirection, Vector3.zero, 10.0f * controller.deltaTime);
|
|
}
|
|
|
|
// Run once when we exit the idle state
|
|
void Idle_ExitState()
|
|
{
|
|
}
|
|
|
|
void Walk_SuperUpdate()
|
|
{
|
|
if(input.Current.JumpInput)
|
|
{
|
|
currentState = PlayerStates.Jump;
|
|
return;
|
|
}
|
|
|
|
if(!MaintainingGround())
|
|
{
|
|
currentState = PlayerStates.Fall;
|
|
return;
|
|
}
|
|
|
|
if(input.Current.MoveInput != Vector3.zero)
|
|
{
|
|
moveDirection = Vector3.MoveTowards(moveDirection, LocalMovement() * WalkSpeed, WalkAcceleration * controller.deltaTime);
|
|
}
|
|
else
|
|
{
|
|
currentState = PlayerStates.Idle;
|
|
return;
|
|
}
|
|
}
|
|
|
|
void Jump_EnterState()
|
|
{
|
|
controller.DisableClamping();
|
|
controller.DisableSlopeLimit();
|
|
|
|
moveDirection += controller.up * CalculateJumpSpeed(JumpHeight, Gravity);
|
|
}
|
|
|
|
void Jump_SuperUpdate()
|
|
{
|
|
Vector3 planarMoveDirection = Math3d.ProjectVectorOnPlane(controller.up, moveDirection);
|
|
Vector3 verticalMoveDirection = moveDirection - planarMoveDirection;
|
|
|
|
if(Vector3.Angle(verticalMoveDirection, controller.up) > 90 && AcquiringGround())
|
|
{
|
|
moveDirection = planarMoveDirection;
|
|
currentState = PlayerStates.Idle;
|
|
return;
|
|
}
|
|
|
|
planarMoveDirection = Vector3.MoveTowards(planarMoveDirection, LocalMovement() * WalkSpeed, JumpAcceleration * controller.deltaTime);
|
|
verticalMoveDirection -= controller.up * Gravity * controller.deltaTime;
|
|
|
|
moveDirection = planarMoveDirection + verticalMoveDirection;
|
|
}
|
|
|
|
void Fall_EnterState()
|
|
{
|
|
controller.DisableClamping();
|
|
controller.DisableSlopeLimit();
|
|
}
|
|
|
|
void Fall_SuperUpdate()
|
|
{
|
|
if(AcquiringGround())
|
|
{
|
|
moveDirection = Math3d.ProjectVectorOnPlane(controller.up, moveDirection);
|
|
currentState = PlayerStates.Idle;
|
|
return;
|
|
}
|
|
|
|
moveDirection -= controller.up * Gravity * controller.deltaTime;
|
|
}
|
|
} |