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