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(); // Grab the controller object from our object controller = gameObject.GetComponent(); // 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; } /// /// Constructs a vector representing our movement local to our lookDirection, which is /// controlled by the camera /// 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; } }