void FixedUpdate() { // Get current head position float currentHeight = head.localPosition.y; if (IsKeyPressed(keys)) { // Crouch down float minHeight = defaultHeadYLocalPosition - crouchYLocalPosition; // Enforce crouched y local position animation of the head. if (minHeight < currentHeight) { head.localPosition = new Vector3(head.localPosition.x, head.localPosition.y - 0.1f, head.localPosition.z); } // Lower the capsule collider. if (capsuleCollider) { capsuleCollider.height = defaultCapsuleColliderHeight - (defaultHeadYLocalPosition - crouchYLocalPosition); capsuleCollider.center = Vector3.up * capsuleCollider.height * .5f; } // Set state. if (!isCrouched) { isCrouched = true; CrouchStart?.Invoke(); } } else { // Will the Real Slim Shady please stand up? float maxHeight = defaultHeadYLocalPosition; // Reset the head to its default y local position. if (currentHeight < maxHeight) { head.localPosition = new Vector3(head.localPosition.x, head.localPosition.y + 0.1f, head.localPosition.z); } // Reset the capsule collider's position. if (capsuleCollider) { capsuleCollider.height = defaultCapsuleColliderHeight; capsuleCollider.center = Vector3.up * capsuleCollider.height * .5f; } // Reset state. isCrouched = false; CrouchEnd?.Invoke(); } }
void LateUpdate() { if (Input.GetKey(key)) { // Enforce crouched y local position of the head. head.localPosition = new Vector3(head.localPosition.x, crouchYLocalPosition, head.localPosition.z); // Lower the capsule collider. if (capsuleCollider) { capsuleCollider.height = defaultCapsuleColliderHeight - (defaultHeadYLocalPosition - crouchYLocalPosition); capsuleCollider.center = Vector3.up * capsuleCollider.height * .5f; } // Set state. if (!IsCrouched) { IsCrouched = true; SetSpeedOverrideActive(true); CrouchStart?.Invoke(); } } else if (IsCrouched) { // Reset the head to its default y local position. head.localPosition = new Vector3(head.localPosition.x, defaultHeadYLocalPosition, head.localPosition.z); // Reset the capsule collider's position. if (capsuleCollider) { capsuleCollider.height = defaultCapsuleColliderHeight; capsuleCollider.center = Vector3.up * capsuleCollider.height * .5f; } // Reset state. IsCrouched = false; SetSpeedOverrideActive(false); CrouchEnd?.Invoke(); } }
void LateUpdate() { if (Input.GetKey(key)) { // Enforce a low head. if (headToLower) { // If we don't have the defaultHeadYLocalPosition, get it now. if (!defaultHeadYLocalPosition.HasValue) { defaultHeadYLocalPosition = headToLower.localPosition.y; } // Lower the head. headToLower.localPosition = new Vector3(headToLower.localPosition.x, crouchYHeadPosition, headToLower.localPosition.z); } // Enforce a low colliderToLower. if (colliderToLower) { // If we don't have the defaultColliderHeight, get it now. if (!defaultColliderHeight.HasValue) { defaultColliderHeight = colliderToLower.height; } // Get lowering amount. float loweringAmount; if (defaultHeadYLocalPosition.HasValue) { loweringAmount = defaultHeadYLocalPosition.Value - crouchYHeadPosition; } else { loweringAmount = defaultColliderHeight.Value * .5f; } // Lower the colliderToLower. colliderToLower.height = Mathf.Max(defaultColliderHeight.Value - loweringAmount, 0); colliderToLower.center = Vector3.up * colliderToLower.height * .5f; } // Set IsCrouched state. if (!IsCrouched) { IsCrouched = true; SetSpeedOverrideActive(true); CrouchStart?.Invoke(); } } else { if (IsCrouched) { // Rise the head back up. if (headToLower) { headToLower.localPosition = new Vector3(headToLower.localPosition.x, defaultHeadYLocalPosition.Value, headToLower.localPosition.z); } // Reset the colliderToLower's height. if (colliderToLower) { colliderToLower.height = defaultColliderHeight.Value; colliderToLower.center = Vector3.up * colliderToLower.height * .5f; } // Reset IsCrouched. IsCrouched = false; SetSpeedOverrideActive(false); CrouchEnd?.Invoke(); } } }
public StateController <CharacterState, CharacterContext> BuildCharacterControllerImpl(StateControllerBuilder <CharacterState, CharacterContext> builder) { Builder = builder; InjectState(this); // Declare Smash Attacks SmashUp.Charge.Data.SmashAttack = SmashAttack.Charge; SmashSide.Charge.Data.SmashAttack = SmashAttack.Charge; SmashDown.Charge.Data.SmashAttack = SmashAttack.Charge; SmashUp.Attack.Data.SmashAttack = SmashAttack.Attack; SmashSide.Attack.Data.SmashAttack = SmashAttack.Attack; SmashDown.Attack.Data.SmashAttack = SmashAttack.Attack; // Ground Attacks new [] { Idle, Walk, CrouchStart, Crouch, CrouchEnd } // Smash Attacks .AddTransitions <CharacterState, CharacterContext>(context => { var input = context.Input; if (!input.Attack.WasPressed) { return(null); } switch (input.Smash.Direction) { case Direction.Right: case Direction.Left: return(SmashSide.Charge); case Direction.Up: return(SmashUp.Charge); case Direction.Down: return(SmashDown.Charge); } return(null); }) // Tilt Attacks .AddTransitions <CharacterState, CharacterContext>(context => { var input = context.Input; if (!input.Attack.WasPressed) { return(null); } switch (input.Movement.Direction) { case Direction.Right: case Direction.Left: return(TiltSide); case Direction.Up: return(TiltUp); case Direction.Down: return(TiltDown); } return(Neutral); }); SmashUp.Charge.AddTransitionTo(SmashUp.Attack); SmashDown.Charge.AddTransitionTo(SmashDown.Attack); SmashSide.Charge.AddTransitionTo(SmashSide.Attack); TiltDown.AddTransitionTo(Crouch, Input(i => i.Movement.Direction == Direction.Down)); new[] { Neutral, TiltUp, TiltDown, TiltSide, SmashUp.Attack, SmashDown.Attack, SmashSide.Attack } .AddTransitionTo(Idle); new [] { Fall, Jump, JumpAerial } .AddTransitions(Land, ctx => ctx.IsGrounded) // Aerial Attacks .AddTransitions <CharacterState, CharacterContext>(context => { var input = context.Input; if (!input.Attack.WasPressed) { return(null); } switch (input.Movement.Direction) { case Direction.Right: return(context.Direction >= 0f ? AerialForward : AerialBackward); case Direction.Left: return(context.Direction >= 0f ? AerialBackward : AerialForward); case Direction.Up: return(AerialUp); case Direction.Down: return(AerialDown); } return(AerialNeutral); }); new[] { AerialForward, AerialBackward, AerialDown, AerialUp, AerialNeutral } .AddTransitions(AerialAttackLand, ctx => ctx.IsGrounded) .AddTransitionTo(Fall); AerialAttackLand.AddTransitionTo(Idle); // Aerial Movement new [] { Idle, Walk, Dash, Run, RunTurn, RunBrake, CrouchStart, Crouch, CrouchEnd, Shield.Main } .AddTransitions(JumpStart, ctx => ctx.Input.Jump.WasPressed && ctx.CanJump); new[] { JumpStart, JumpAerial }.AddTransitionTo(Jump); new[] { Jump, Fall }.AddTransitions(JumpAerial, ctx => ctx.Input.Jump.WasPressed && ctx.CanJump) .AddTransitions(EscapeAir, Input(i => i.Shield.WasPressed)); Jump.AddTransition(Idle, ctx => ctx.NormalizedStateTime >= 1.0f && ctx.IsGrounded) .AddTransition(Fall, ctx => ctx.NormalizedStateTime >= 1.0f && !ctx.IsGrounded); EscapeAir.AddTransitionTo(FallHelpless); new[] { Fall, FallHelpless, EscapeAir }.AddTransitions(Land, ctx => ctx.IsGrounded); Land.AddTransitionTo(Idle); Func <Func <PlayerInputContext, DirectionalInput>, Func <CharacterContext, bool> > movementContext = func => { return(ctx => !DirectionInput(Direction.Down)(ctx) && Input(i => Mathf.Abs(func(i).Value.x) > DirectionalInput.DeadZone)(ctx)); }; // Running States Idle.AddTransition(Dash, movementContext(i => i.Smash)); Dash.AddTransitionTo(Idle, DirectionInput(Direction.Neutral)); new[] { Dash, RunTurn }.AddTransitionTo(Run); Run.AddTransition(RunBrake, DirectionInput(Direction.Neutral)); Run.AddTransition(RunTurn, ctx => !Mathf.Approximately(Mathf.Sign(ctx.Input.Movement.Value.x), Mathf.Sign(ctx.Direction))); RunBrake.AddTransitionTo(Idle); // Ground Movement new[] { Idle, Walk, Run } .AddTransitions(CrouchStart, DirectionInput(Direction.Down)) .AddTransitions(Fall, ctx => !ctx.IsGrounded); Idle.AddTransition(Walk, movementContext(i => i.Movement)); Walk.AddTransition(Idle, DirectionInput(Direction.Neutral)); // Crouching States CrouchStart.AddTransitionTo(Crouch); CrouchEnd.AddTransitionTo(Idle); new[] { CrouchStart, Crouch, CrouchEnd }.AddTransitions(Fall, ctx => !ctx.IsGrounded); Crouch.AddTransition(CrouchEnd, Input(i => i.Movement.Direction != Direction.Down)); // Ledge States new[] { Idle, Fall, FallHelpless }.AddTransitions(LedgeGrab, ctx => ctx.State.IsGrabbingLedge); LedgeGrab.AddTransitionTo(LedgeIdle); LedgeIdle.AddTransition(LedgeRelease, ctx => !ctx.State.IsGrabbingLedge) .AddTransition(LedgeClimb, DirectionInput(Direction.Up)) .AddTransition(LedgeJump, ctx => ctx.Input.Jump.WasPressed && ctx.CanJump) .AddTransition(LedgeAttack, Attack()); LedgeJump.AddTransitionTo(Jump); new[] { LedgeRelease, LedgeClimb, LedgeEscape, LedgeAttack } .AddTransitions(Idle, ctx => ctx.NormalizedStateTime >= 1.0f && ctx.IsGrounded) .AddTransitions(Fall, ctx => ctx.NormalizedStateTime >= 1.0f && !ctx.IsGrounded); // Shielding Idle.AddTransition(Shield.On, Input(i => i.Shield.Current)); Shield.On.AddTransition(Shield.Perfect, ctx => ctx.State.IsHit) .AddTransitionTo(Shield.Main); Shield.Main.AddTransition(Shield.Broken, ctx => ctx.State.ShieldDamage <= 0) .AddTransition(Shield.Off, Input(i => !i.Shield.Current)); Shield.Off.AddTransitionTo(Idle); new[] { Shield.Broken, Shield.Stunned, Idle }.Chain(); // Rolls/Sidesteps Shield.Main .AddTransition(EscapeForward, ctx => { if (ctx.Direction > 0f) { return(DirectionalSmash(Direction.Right)(ctx)); } else { return(DirectionalSmash(Direction.Left)(ctx)); } }) .AddTransition(EscapeBackward, ctx => { if (ctx.Direction > 0f) { return(DirectionalSmash(Direction.Left)(ctx)); } else { return(DirectionalSmash(Direction.Right)(ctx)); } }) .AddTransition(Escape, DirectionInput(Direction.Down)); new[] { Escape, EscapeForward, EscapeBackward }.AddTransitionTo(Shield.Main); Builder.WithDefaultState(Idle); BuildCharacterController(); return(Builder.Build()); }