Unity C# 层次状态机HSM实战:3层状态嵌套实现角色复杂行为逻辑

📅 2026/7/6 23:27:59 👁️ 阅读次数 📝 编程学习
Unity C# 层次状态机HSM实战:3层状态嵌套实现角色复杂行为逻辑

Unity C# 层次状态机HSM实战:3层状态嵌套实现角色复杂行为逻辑

在游戏开发中,角色行为逻辑的复杂性往往随着游戏机制的丰富而呈指数级增长。想象一下,你的游戏角色需要同时处理移动、攻击、技能释放、装备切换等多种行为,每种行为又有多个子状态——比如攻击状态下又分为地面攻击、空中攻击、蓄力攻击等。传统的有限状态机(FSM)在这种场景下很快就会变得难以维护,而层次状态机(HSM)则提供了一种优雅的解决方案。

1. 为什么游戏开发需要层次状态机

当角色行为逻辑变得复杂时,传统的FSM会面临几个关键问题:

  • 状态爆炸:随着功能增加,状态数量急剧增长,导致难以管理
  • 代码重复:相似状态(如地面攻击和空中攻击)需要重复编写大量相同逻辑
  • 过渡复杂:状态间的转换关系变得错综复杂,难以理解和维护

层次状态机通过引入状态继承和层级结构解决了这些问题。让我们看一个典型游戏角色的状态层级示例:

角色状态 (Root) ├── 地面状态 (Grounded) │ ├── 待机 (Idle) │ ├── 移动 (Move) │ └── 地面攻击 (GroundAttack) └── 空中状态 (Airborne) ├── 跳跃 (Jump) ├── 下落 (Fall) └── 空中攻击 (AirAttack)

在这个结构中,子状态可以继承父状态的通用行为,只需实现自己特有的逻辑。例如,所有空中状态都会检查是否落地,这个逻辑只需在Airborne父状态中实现一次。

2. HSM核心实现:3层嵌套状态机设计

下面我们实现一个支持3层嵌套的HSM核心类。这个实现采用基于栈的状态管理,确保状态进入/退出顺序正确。

using System.Collections.Generic; using UnityEngine; public abstract class HSMState { protected HSMStateMachine stateMachine; protected HSMState parentState; protected List<HSMState> subStates = new List<HSMState>(); protected HSMState currentSubState; public HSMState(HSMStateMachine stateMachine, HSMState parentState = null) { this.stateMachine = stateMachine; this.parentState = parentState; } public abstract void Enter(); public abstract void Update(); public abstract void Exit(); public virtual void ChangeSubState(HSMState newState) { if (currentSubState != null) { currentSubState.Exit(); } currentSubState = newState; if (currentSubState != null) { currentSubState.Enter(); } } public virtual void AddSubState(HSMState state) { subStates.Add(state); } } public class HSMStateMachine : MonoBehaviour { private Stack<HSMState> stateStack = new Stack<HSMState>(); public void PushState(HSMState newState) { if (stateStack.Count > 0) { stateStack.Peek().Exit(); } stateStack.Push(newState); newState.Enter(); } public void PopState() { if (stateStack.Count > 0) { stateStack.Pop().Exit(); if (stateStack.Count > 0) { stateStack.Peek().Enter(); } } } public void ChangeState(HSMState newState) { while (stateStack.Count > 0) { PopState(); } PushState(newState); } private void Update() { if (stateStack.Count > 0) { stateStack.Peek().Update(); } } }

这个基础框架支持状态的嵌套和层级管理。现在让我们实现一个具体的角色状态机示例。

3. 实战:角色3层状态行为实现

我们将实现一个包含以下层级结构的角色状态机:

角色状态 ├── 地面状态 │ ├── 待机 │ ├── 移动 │ └── 攻击 └── 空中状态 ├── 跳跃 ├── 下落 └── 空中攻击

首先定义基础角色状态:

public class CharacterBaseState : HSMState { protected CharacterController character; protected Animator animator; public CharacterBaseState(HSMStateMachine stateMachine, HSMState parentState, CharacterController character) : base(stateMachine, parentState) { this.character = character; this.animator = character.GetComponent<Animator>(); } public override void Enter() {} public override void Update() {} public override void Exit() {} protected bool IsGrounded() { return character.isGrounded; } }

接着实现地面状态和它的子状态:

public class GroundedState : CharacterBaseState { public GroundedState(HSMStateMachine stateMachine, HSMState parentState, CharacterController character) : base(stateMachine, parentState, character) {} public override void Enter() { base.Enter(); animator.SetBool("IsGrounded", true); ChangeSubState(new IdleState(stateMachine, this, character)); } public override void Update() { base.Update(); if (!IsGrounded()) { stateMachine.PushState(new AirborneState(stateMachine, null, character)); return; } currentSubState?.Update(); } } public class IdleState : CharacterBaseState { public IdleState(HSMStateMachine stateMachine, HSMState parentState, CharacterController character) : base(stateMachine, parentState, character) {} public override void Enter() { base.Enter(); animator.SetFloat("Speed", 0); } public override void Update() { base.Update(); if (Input.GetAxisRaw("Horizontal") != 0 || Input.GetAxisRaw("Vertical") != 0) { parentState.ChangeSubState(new MoveState(stateMachine, parentState, character)); } else if (Input.GetButtonDown("Fire1")) { parentState.ChangeSubState(new GroundAttackState(stateMachine, parentState, character)); } } } public class MoveState : CharacterBaseState { public MoveState(HSMStateMachine stateMachine, HSMState parentState, CharacterController character) : base(stateMachine, parentState, character) {} public override void Enter() { base.Enter(); animator.SetFloat("Speed", 1); } public override void Update() { base.Update(); Vector3 moveInput = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical")); character.Move(moveInput.normalized * character.moveSpeed * Time.deltaTime); if (moveInput.magnitude < 0.1f) { parentState.ChangeSubState(new IdleState(stateMachine, parentState, character)); } else if (Input.GetButtonDown("Fire1")) { parentState.ChangeSubState(new GroundAttackState(stateMachine, parentState, character)); } } } public class GroundAttackState : CharacterBaseState { private float attackTimer; public GroundAttackState(HSMStateMachine stateMachine, HSMState parentState, CharacterController character) : base(stateMachine, parentState, character) {} public override void Enter() { base.Enter(); animator.SetTrigger("Attack"); attackTimer = character.attackDuration; } public override void Update() { base.Update(); attackTimer -= Time.deltaTime; if (attackTimer <= 0) { parentState.ChangeSubState(new IdleState(stateMachine, parentState, character)); } } }

然后实现空中状态及其子状态:

public class AirborneState : CharacterBaseState { public AirborneState(HSMStateMachine stateMachine, HSMState parentState, CharacterController character) : base(stateMachine, parentState, character) {} public override void Enter() { base.Enter(); animator.SetBool("IsGrounded", false); ChangeSubState(new JumpState(stateMachine, this, character)); } public override void Update() { base.Update(); if (IsGrounded()) { stateMachine.PopState(); // 返回上一个状态(应该是GroundedState) return; } currentSubState?.Update(); } } public class JumpState : CharacterBaseState { private float jumpTimer; public JumpState(HSMStateMachine stateMachine, HSMState parentState, CharacterController character) : base(stateMachine, parentState, character) {} public override void Enter() { base.Enter(); animator.SetTrigger("Jump"); character.velocity.y = character.jumpForce; jumpTimer = character.jumpDuration; } public override void Update() { base.Update(); jumpTimer -= Time.deltaTime; if (jumpTimer <= 0 || character.velocity.y <= 0) { parentState.ChangeSubState(new FallState(stateMachine, parentState, character)); } else if (Input.GetButtonDown("Fire1")) { parentState.ChangeSubState(new AirAttackState(stateMachine, parentState, character)); } } } public class FallState : CharacterBaseState { public FallState(HSMStateMachine stateMachine, HSMState parentState, CharacterController character) : base(stateMachine, parentState, character) {} public override void Enter() { base.Enter(); animator.SetBool("IsFalling", true); } public override void Update() { base.Update(); if (Input.GetButtonDown("Fire1")) { parentState.ChangeSubState(new AirAttackState(stateMachine, parentState, character)); } } public override void Exit() { base.Exit(); animator.SetBool("IsFalling", false); } } public class AirAttackState : CharacterBaseState { private float attackTimer; public AirAttackState(HSMStateMachine stateMachine, HSMState parentState, CharacterController character) : base(stateMachine, parentState, character) {} public override void Enter() { base.Enter(); animator.SetTrigger("AirAttack"); attackTimer = character.airAttackDuration; } public override void Update() { base.Update(); attackTimer -= Time.deltaTime; if (attackTimer <= 0) { if (character.velocity.y > 0) { parentState.ChangeSubState(new JumpState(stateMachine, parentState, character)); } else { parentState.ChangeSubState(new FallState(stateMachine, parentState, character)); } } } }

4. 状态机集成与使用

最后,我们需要将状态机集成到角色控制器中:

public class CharacterController : MonoBehaviour { public float moveSpeed = 5f; public float jumpForce = 10f; public float jumpDuration = 0.5f; public float attackDuration = 0.8f; public float airAttackDuration = 0.6f; public Vector3 velocity; public bool isGrounded; private HSMStateMachine stateMachine; private Animator animator; private Rigidbody rb; private void Awake() { animator = GetComponent<Animator>(); rb = GetComponent<Rigidbody>(); stateMachine = gameObject.AddComponent<HSMStateMachine>(); } private void Start() { stateMachine.PushState(new GroundedState(stateMachine, null, this)); } private void Update() { isGrounded = Physics.Raycast(transform.position, Vector3.down, 0.1f); } private void FixedUpdate() { rb.velocity = velocity; } public void Move(Vector3 direction) { velocity.x = direction.x * moveSpeed; velocity.z = direction.z * moveSpeed; } }

这个实现展示了如何利用HSM管理复杂的角色行为逻辑。通过状态继承和层级结构,我们避免了代码重复,使逻辑更加清晰,并且易于扩展新的状态和行为。