
轻重攻击逻辑
- 轻重攻击只能在地面释放
- 轻攻击有三段,第二段可以衔接重攻击
- 重攻击可以单独释放

实现
状态机的切换
攻击的实现和跳跃,冲刺的实现类似。都是使用输入事件监听的方法。在PlayerGroundState中添加新的事件。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| public class PlayerGroundState : PlayerState { public PlayerGroundState(Player player, PlayerStateMachine stateMachine, string animBoolName, string animTriggerName) : base(player, stateMachine, animBoolName, animTriggerName) { }
public override void Enter() { base.Enter(); playerInput.GamePlay.Jump.started += Jump; playerInput.GamePlay.Dash.started += Dash; playerInput.GamePlay.BackDash.started += BackDash; playerInput.GamePlay.LightAttack.started += LightAttack; playerInput.GamePlay.HeavyAttack.started += HeavyAttack; }
private void HeavyAttack(InputAction.CallbackContext context) { if(physicsCheck.isGrounded) stateMachine.ChangeState(player.heavyAttackState); }
private void LightAttack(InputAction.CallbackContext context) { if (physicsCheck.isGrounded) stateMachine.ChangeState(player.lightAttackState); }
private void BackDash(InputAction.CallbackContext context) { if (physicsCheck.isGrounded) stateMachine.ChangeState(player.backDashState); }
private void Dash(InputAction.CallbackContext context) { if (physicsCheck.isGrounded) stateMachine.ChangeState(player.dashState); }
private void Jump(InputAction.CallbackContext context) { if(physicsCheck.isGrounded) stateMachine.ChangeState(player.jumpState); }
public override void Exit() { base.Exit(); playerInput.GamePlay.Jump.started -= Jump; playerInput.GamePlay.Dash.started -= Dash; playerInput.GamePlay.BackDash.started -= BackDash; playerInput.GamePlay.LightAttack.started -= LightAttack; playerInput.GamePlay.HeavyAttack.started -= HeavyAttack; }
public override void LogicUpdate() { base.LogicUpdate(); if (!physicsCheck.isGrounded) stateMachine.ChangeState(player.fallState); }
public override void PhysicsUpdate() { base.PhysicsUpdate(); } }
|
当按下轻重攻击时,分别进入到对应状态。
1 2 3 4 5 6 7 8 9
| private void HeavyAttack(InputAction.CallbackContext context) { if(physicsCheck.isGrounded) stateMachine.ChangeState(player.heavyAttackState); }
private void LightAttack(InputAction.CallbackContext context) { if (physicsCheck.isGrounded) stateMachine.ChangeState(player.lightAttackState); }
|
动画状态机设置
动画状态机的对应参数是Trigger和comboCounter

如何实现多段攻击
通过在LightAttack状态中同样添加按键触发事件来实现。当从Ground状态进入到LightAttack状态时,每按一次轻攻击键都会触发Trigger。但是这样就存在一个问题,因为anystate连接到了第一段攻击,当我们进行第二段攻击时,再次按下攻击键,又会返回到第一段攻击,所以我们需要额外添加一个ComboCounter参数,当进入到攻击状态时,把combo数置0,之后每触发一次攻击就加一,至于状态的退出,还是用动画绑定事件的方法。重攻击状态的实现比较简单,这里就不放了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| public class PlayerLightAttackState : PlayerState { public PlayerLightAttackState(Player player, PlayerStateMachine stateMachine, string animBoolName, string animTriggerName) : base(player, stateMachine, animBoolName, animTriggerName) { }
public override void Enter() { base.Enter(); player.comboCounter = 0; player.animator.SetInteger("ComboCounter", player.comboCounter); playerInput.GamePlay.LightAttack.started += LightAttack; playerInput.GamePlay.HeavyAttack.started += HeavyAttack; }
private void HeavyAttack(InputAction.CallbackContext context) {
stateMachine.ChangeState(player.heavyAttackState); }
private void LightAttack(InputAction.CallbackContext context) { player.comboCounter++; player.animator.SetInteger("ComboCounter", player.comboCounter); animator.SetTrigger("LightAttackTrigger"); }
public override void Exit() { base.Exit();
playerInput.GamePlay.LightAttack.started -= LightAttack; playerInput.GamePlay.HeavyAttack.started -= HeavyAttack; }
public override void LogicUpdate() { base.LogicUpdate(); if (animFinTrigger) stateMachine.ChangeState(player.idleState); }
public override void PhysicsUpdate() { player.SetZeroVelocity(); }
}
|
输入窗口
上面的实现虽然能完成连段的释放,但是存在一个问题,那就是只要输入足够快,每一段攻击都可以瞬间切换到下一段,也就是可以在任意时候取消上一次的攻击,为了限制可以取消的时机,我们为player增加一个Bool变量isAttacking,只有isAttacking为false时,才响应输入事件,同样通过动画绑定事件的方法来控制isAttacking变量。
1 2 3 4 5 6 7 8 9 10
| public void AnimationAttack() { player.isAttacking = true; } public void AnimationAttackOver() { player.isAttacking = false;
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| private void HeavyAttack(InputAction.CallbackContext context) { if (!player.isAttacking) stateMachine.ChangeState(player.heavyAttackState); }
private void LightAttack(InputAction.CallbackContext context) { if (!player.isAttacking) { player.comboCounter++; player.animator.SetInteger("ComboCounter", player.comboCounter); animator.SetTrigger("LightAttackTrigger"); } }
|
AnimationAttackOver到AnimationFin之间就是可以衔接连段的窗口
