大家好,我是展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。
图书作者:《ESP32-C3 物联网工程开发实战》
图书作者:《SwiftUI 入门,进阶与实战》
超级个体:COC上海社区主理人
特约讲师:大学讲师,谷歌亚马逊分享嘉宾
科技博主:华为HDE/HDG
我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。
展菲:您的前沿技术领航员
👋 大家好,我是展菲!
📱 全网搜索“展菲”,即可纵览我在各大平台的知识足迹。
每周定时推送干货满满的技术长文,从新兴框架的剖析到运维实战的复盘,助您技术进阶之路畅通无阻。
文章目录
- 引言
- 一、动画真正解决的是什么?
- 二、动画不应该属于业务逻辑
- 三、动画系统在架构中的位置
- 四、动画状态机(Animation State Machine)
- 五、定义动画状态
- 六、动画状态机 Demo
- 七、为什么状态驱动动画更重要?
- 八、动画事件系统
- 九、技能动画系统
- 十、特效系统拆分
- 十一、UI 动画也应该系统化
- 十二、AISystem 与动画系统协同
- 十三、动画性能优化
- 十四、未来架构:Animation Graph
- 十五、一个关键认知升级
- 总结
引言
很多开发者第一次做鸿蒙游戏动画时,思路通常是这样的:
角色移动 ↓ 播放动画 角色攻击 ↓ 播放动画 角色死亡 ↓ 播放动画于是代码慢慢变成:
if(state=="idle"){playIdle()}if(state=="run"){playRun()}if(state=="attack"){playAttack()}游戏初期没什么问题。但随着项目变大:
待机 跑步 攻击 受伤 死亡 技能1 技能2 技能3 Buff动画 特效动画 UI动画你会发现:
动画越来越多 状态越来越乱 切换越来越复杂最终出现经典问题:
动画和业务逻辑耦合在一起。
例如:
attack(){playAttack()enemy.hp-=100}看起来很自然。但实际上:
动画 业务 状态已经混在一起了。大型游戏最终都会发现:
动画不是特效,而是一个独立系统。
一、动画真正解决的是什么?
很多人认为:
动画 = 好看实际上:
动画 = 状态变化可视化例如,角色攻击:
Store变化 ↓ enemy.hp减少玩家看不到。所以需要:
攻击动作 伤害飘字 受击效果告诉玩家:
世界发生了变化本质上:
动画是状态变化的翻译器。
二、动画不应该属于业务逻辑
错误写法:
attackEnemy(){playAttack()enemy.hp-=100}问题:
BattleSystem 依赖动画耦合严重。
正确结构:
BattleSystem ↓ Store变化 ↓ AnimationSystem ↓ 播放动画例如:
battle.attack(store)修改:
store.enemyHp-=100然后:
AnimationSystem监听变化。
三、动画系统在架构中的位置
前面我们一直讲:
Input ↓ System ↓ Store ↓ HUD ↓ UI动画应该插在哪里?答案:
Input ↓ System ↓ Store ↓ AnimationSystem ↓ HUD/UI因为:
动画来自状态变化而不是:
按钮点击四、动画状态机(Animation State Machine)
大型游戏不会这样写:
playIdle()playRun()playAttack()而是:
AnimationStateMachine管理状态,例如:
Idle Run Attack Hit Dead关系:
Idle ↓ Run ↓ Attack ↓ Idle形成:
状态机五、定义动画状态
enumAnimationState{Idle,Run,Attack,Hit,Dead}角色保存:
classCharacterStore{animation=AnimationState.Idle}动画状态成为:
Store的一部分六、动画状态机 Demo
实现:
classAnimationSystem{update(store:CharacterStore){if(store.hp<=0){store.animation=AnimationState.Deadreturn}}}作用:
状态决定动画而不是:
动画决定状态七、为什么状态驱动动画更重要?
错误思路:
攻击 ↓ 播放动画 ↓ 修改状态容易不同步。
正确:
攻击 ↓ 修改状态 ↓ 动画自动切换例如:
store.isAttacking=true动画系统读取:
isAttacking自动播放:
Attack Animation八、动画事件系统
很多动画会触发:
攻击命中 技能爆炸 伤害计算例如:
挥刀 ↓ 第8帧 ↓ 真正造成伤害不能:
点击就扣血否则:
动画和表现错位推荐:
Animation Event机制。
定义:
classAnimationEvent{frame:numbercallback:Function}例如:
frame=8触发:
battle.hitEnemy()九、技能动画系统
很多技能:
抬手 施法 释放 结束并不是一个动作,例如:
FireBall流程:
Cast ↓ Launch ↓ Impact动画系统负责:
阶段切换而:
BattleSystem负责:
伤害计算十、特效系统拆分
很多项目喜欢:
playEffect()到处调用,最后:
特效失控推荐独立:
EffectSystem结构:
AnimationSystem ↓ EffectSystem例如:
攻击动画触发:
刀光特效动画和特效分离。
十一、UI 动画也应该系统化
例如:
获得金币 升级 任务完成很多开发者直接写:
.animate()在页面里。
项目大了之后:
无法统一管理推荐:
UIAnimationSystem负责:
Toast 弹窗 奖励动画形成:
GameAnimationSystem UIAnimationSystem双系统。
十二、AISystem 与动画系统协同
前面讲过:
AISystem驱动 NPC,例如:
NPC决定攻击执行:
store.state=Attack然后:
AnimationSystem自动切换:
Attack Animation结构:
AISystem ↓ Store ↓ AnimationSystem非常清晰。
十三、动画性能优化
很多项目掉帧并不是:
AI导致,而是:
动画太多例如:
100个敌人 100个动画同时更新。
优化方案:
LOD动画即:
远距离 简化动画 近距离 完整动画例如:
if(distance>500){skipAnimation()}大型游戏非常常见。
十四、未来架构:Animation Graph
再往后发展,行为树管理:
AI决策状态机管理:
动画状态最终演化:
Animation Graph结构:
Idle ↓ Run ↓ Attack ↓ Skill ↓ Dead节点可视化连接,这也是现代游戏引擎普遍采用的方案。
十五、一个关键认知升级
初学者认为:
动画 = 播放图片进阶开发者认为:
动画 = 状态切换而大型项目最终理解:
动画系统的本质,是把 Store 中的状态变化翻译成玩家能够感知的视觉反馈。
所以真正驱动动画的不是:
按钮也不是:
页面而是:
Store总结
鸿蒙游戏动画系统推荐架构:
Input ↓ System ↓ Store ↓ AnimationSystem ↓ EffectSystem ↓ HUD/UI核心模块:
AnimationStateMachine AnimationEvent EffectSystem UIAnimationSystem核心原则:
状态驱动动画 动画不驱动状态如果用一句话总结:
优秀的动画系统从来不是“播放动作”,而是让 Store 中的状态变化,以最自然的方式呈现在玩家眼前。