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