当前位置: 首页 > news >正文

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管理复杂的角色行为逻辑。通过状态继承和层级结构,我们避免了代码重复,使逻辑更加清晰,并且易于扩展新的状态和行为。

http://www.jsqmd.com/news/1137708/

相关文章:

  • kmpi未来展望:消息传递技术在HPC领域的发展趋势
  • Monaspace字体革命:从等宽束缚到智能排版的艺术突破
  • AI安全靶场实战指南:从零构建大模型攻防演练环境
  • Kindle Comic Converter专业指南:高效漫画电子化转换工具使用教程
  • MySQL RR/RC隔离级别下SELECT FOR UPDATE锁行为实测:4种索引场景对比
  • AI智能体开发实战:从App到技能服务的范式转移
  • Python自动化抢票工具开发:从HTTP请求到Selenium实战
  • 用PIC32微控制器驱动RGB灯带实现智能灯光控制
  • 久坐:现代职场人的沉默杀手与自救指南
  • 量子近似优化算法(QAOA)的工程化改进:Bang-bang控制策略解析与实践
  • 密钥治理实战:从明文密码到动态凭据的全链路安全体系
  • 3 类 AppData 子文件夹深度解析:Local、Roaming、LocalLow 的 5 种安全清理策略
  • AWS CloudWatch 实战:从指标采集到自动化修复的监控体系
  • GetQzonehistory:5分钟快速找回QQ空间全部历史说说的完整指南
  • 如何快速上手kml_adapter:5分钟完成FFTW到KML的无缝迁移
  • RCE攻击原理、实战与防御:从命令注入到Log4j2漏洞深度解析
  • 虚幻引擎 UMG 蓝图架构设计:基于C++的3层UI框架实现
  • Element-Plus-Admin:5分钟快速搭建现代化Vue3后台管理系统的完整指南
  • MySQL 8.0 索引设计实战:3 个复合索引案例解析与 5 大避坑指南
  • Win11系统RTX 3080 Ti CUDA性能排查:对比Win10解决GPU占用率异常高问题
  • PyTorch 混合精度训练:省显存不等于省时间
  • 抖音动态监控助手:5分钟实现自动推送的完整教程
  • ArcGIS Pro 3.2 面转线工具:5种邻接关系与 LEFT_FID/RIGHT_FID 字段深度解析
  • 如何高效使用QMK Toolbox:免费开源机械键盘固件刷写完全指南
  • GPT-5.6与ppt-master:智能体工作流如何重塑PPT制作与知识工作
  • Git Push/Pull 实操手册:从失败报错到安全协同
  • R语言构建神经网络:从tidymodels预处理到torch部署的全链路实践
  • GPT-4 与 Claude 3 长文本分析:识别技术文档中的‘速成陷阱’与5个应对策略
  • 基于Si4731与STM32F303RC的数字收音机开发指南
  • 不蒜子 2.3 统计原理与安全实践:解析PV/UV算法及3种数据伪造风险