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