internal StateController(StateControllerBuilder <T, TContext> builder) { DefaultState = builder.DefaultState; CurrentState = DefaultState; _states = builder._states; States = new ReadOnlyCollection <T>(builder.States.ToArray()); }
/// <inheritdoc/> public override StateController BuildController() { Initialize(); var builder = new StateControllerBuilder(); var stateMap = BuildStates(builder, _states); var typeOrder = new Type[] { typeof(StateAsset), typeof(StateGroupAsset), }; var transitions = _states.OrderBy(s => Array.IndexOf(typeOrder, s.GetType())) .SelectMany(s => s.Transitions); BuildTransitions(transitions, stateMap); return(builder.Build()); }
static Dictionary <StateAsset, State> BuildStates(StateControllerBuilder builder, List <BaseStateAsset> stateAssets) { var stateMap = new Dictionary <StateAsset, State>(); uint id = 0; foreach (var stateAsset in stateAssets.OfType <StateAsset>().OrderBy(s => s.name)) { if (stateAsset == null || stateMap.ContainsKey(stateAsset)) { continue; } State state = stateAsset.BuildState(id); builder.AddState(state); stateMap[stateAsset] = state; id++; } return(stateMap); }
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()); }
internal StateController(StateControllerBuilder builder) { DefaultState = builder.DefaultState; States = new ReadOnlyCollection <State>(builder.States.ToArray()); }