mergemilitary/Assets/Art_Military/AAsucai/ExplosiveLLC/SuperCharacterController/Code/PlayerMachine.cs

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;
}
}