新闻详情

新闻详情

首页 / 资讯中心 / 详情

Unity怪物格斗游戏开发:动画事件与状态机实战

发布时间:2026/9/30 6:17:08来源:尧图网络
Unity怪物格斗游戏开发:动画事件与状态机实战
简介这是一份面向Unity初学者与在校学生的2D格斗小游戏完整工程可直接作为期末大作业或课程设计参考。项目实现人物上下左右跳跃移动、攻击怪物、血量条扣减、分数统计与游戏背景切换等核心玩法并支持背景音乐调节与多按钮UI交互适合刚接触Unity3D、想通过一个可运行案例理解角色控制、碰撞检测与UI逻辑的入门者。压缩包为zip格式整体约50.78MB文件数量与类型明细上游暂未提供但按同类工程推测应包含场景、脚本与素材等资源。目前已有2400人学习下载热度较高。拿到后可直接在Unity中打开运行对照文章说明梳理场景结构、脚本挂载与参数配置快速掌握从角色移动到战斗结算的完整实现思路并在此基础上替换美术素材或扩展关卡完成属于自己的格斗小游戏。1. 从零做一个能打的 Unity 怪物格斗游戏期末大作业为什么总在动画和碰撞上翻车很多人第一次用 Unity 做格斗游戏卡住的地方不是写不出攻击逻辑而是角色挥拳时怪物没反应、怪物扑过来时角色穿模、连招按快了动画直接卡死。这个标题说的就是把这些坑一次性填平用 Unity 搭一个玩家对怪物的近战格斗小游戏包含移动、攻击、受击、血量和简单的连招判定规模控制在期末大作业能交、初学者能跟完的范围。它适合刚学完 Unity 基础、知道MonoBehaviour和Rigidbody是什么、但没独立做过完整战斗循环的人。我见过太多作业死在「动画播了但伤害没结算」和「碰撞体互相推开导致打不中」这两件事上所以这篇不堆概念直接按能跑起来的顺序拆先定战斗判定方案再写状态机最后调参数和排错。做完你会得到一个能扩展成 Boss 战、能加技能指示器的底子而不是一个只能原地挥拳的演示。2. 战斗判定怎么选触发器、射线还是碰撞盒格斗游戏的核心不是动画多好看而是「这一拳到底打没打中」这件事要说得清。初学者最容易犯的错是把攻击判定直接挂在角色身上结果角色一动判定框跟着乱跑怪物莫名其妙掉血。所以第一步不是写代码是先想清楚判定发生在哪里、什么时候发生。2.1 三种判定方案的取舍常见做法有三种。第一种是触发器Trigger在武器或拳头位置放一个BoxCollider勾上Is Trigger攻击动画的某一帧把它打开碰到怪物就结算伤害。第二种是射线检测Raycast从角色胸口往前打一条短射线命中才算。第三种是持续碰撞盒OverlapBox在攻击瞬间用Physics.OverlapBox查一次范围内有没有怪物。对初学者做怪物格斗我一般推荐触发器方案原因是它和动画事件配合最自然调试时能在 Scene 视图里直接看到那个绿框出问题一眼就知道是框没开还是怪物没进框。射线方案适合远程或判定要求极精确的场合但近战里角色和怪物贴脸时射线起点容易穿到怪物背后反而漏判。OverlapBox性能好、可控性强但需要你自己算攻击帧的起止时间对没写过帧同步的人是额外负担。方案适合场景初学者友好度主要坑触发器 Trigger近战挥拳、武器判定高判定框跟随角色移动会误伤射线 Raycast远程、精确点判定中贴脸时起点穿透OverlapBox范围技、性能敏感中需手动控制检测时机选触发器之后关键是把判定框做成角色的子物体但攻击时它的位置由动画驱动而不是跟着角色根节点乱飘。这样挥拳到哪判定就到哪。2.2 用动画事件开关判定框判定框不能一直开着否则角色站着不动也会打到路过的怪物。正确做法是在攻击动画的关键帧上挂动画事件Animation Event进入攻击帧时打开收招时关闭。下面这段脚本挂在带判定框的物体上由动画事件调用。using UnityEngine; public class AttackHitbox : MonoBehaviour { // 判定框的 Collider攻击帧才启用 private Collider hitCollider; // 本次攻击是否已经命中过防止一次挥拳打多下 private bool hasHit false; void Awake() { hitCollider GetComponentCollider(); hitCollider.enabled false; // 默认关闭避免误判 } // 动画事件调用打开判定 public void OpenHitbox() { hasHit false; hitCollider.enabled true; } // 动画事件调用关闭判定 public void CloseHitbox() { hitCollider.enabled false; } // 判定框碰到怪物时触发 void OnTriggerEnter(Collider other) { if (hasHit) return; // 一次攻击只结算一次 if (!other.CompareTag(Monster)) return; // 只对怪物生效 hasHit true; // 通知怪物扣血伤害值由攻击方决定 other.GetComponentMonsterHealth()?.TakeDamage(10); } }逻辑上Awake里先把碰撞体关掉保证角色待机时判定框是死的。OpenHitbox和CloseHitbox由动画事件在攻击帧和收招帧分别调用这样判定窗口和动画严格对齐。hasHit这个标志很关键因为触发器在怪物停留在框内时可能触发多次没有它一次挥拳能打出三四段伤害血条瞬间清空这是初学者最常见的翻车点之一。参数上TakeDamage(10)里的 10 是基础伤害建议先写死方便调试等战斗循环跑通再抽成ScriptableObject或攻击方属性。判定框的BoxCollider大小要贴着拳头别贪大框越大越容易在角色转身时扫到背后的怪物。注意动画事件必须挂在动画剪辑的关键帧上不是挂在脚本里。如果发现OpenHitbox没被调用先检查动画窗口里那一帧有没有事件标记。3. 角色和怪物的状态机为什么你的连招会卡死判定跑通之后下一个问题是状态管理。初学者常写出一堆if (isAttacking !isHurt !isDead)的布尔变量加到五六个之后自己都理不清按快攻击键角色就卡在攻击动画里出不来。格斗游戏天然是状态驱动的用状态机State Machine来管是最省心的做法。3.1 用枚举搭一个最小状态机不需要上复杂的框架一个枚举加一个当前状态变量就够初学者用。玩家状态大致有待机、移动、攻击、受击、死亡。怪物状态类似但攻击由 AI 触发。using UnityEngine; public enum PlayerState { Idle, Move, Attack, Hurt, Dead } public class PlayerController : MonoBehaviour { public PlayerState currentState PlayerState.Idle; public float moveSpeed 5f; private Animator anim; private Rigidbody rb; void Start() { anim GetComponentAnimator(); rb GetComponentRigidbody(); } void Update() { // 死亡和受击状态不接受输入 if (currentState PlayerState.Dead || currentState PlayerState.Hurt) return; if (currentState PlayerState.Attack) return; // 攻击中锁定移动避免滑步 float h Input.GetAxisRaw(Horizontal); float v Input.GetAxisRaw(Vertical); if (Mathf.Abs(h) 0.1f || Mathf.Abs(v) 0.1f) { currentState PlayerState.Move; Vector3 dir new Vector3(h, 0, v).normalized; rb.MovePosition(transform.position dir * moveSpeed * Time.deltaTime); // 角色朝向跟随移动方向 transform.forward dir; } else { currentState PlayerState.Idle; } if (Input.GetKeyDown(KeyCode.J)) { EnterAttack(); } anim.SetInteger(State, (int)currentState); } void EnterAttack() { currentState PlayerState.Attack; anim.SetTrigger(Attack); } // 动画事件攻击动画结束时调用回到待机 public void OnAttackEnd() { if (currentState PlayerState.Attack) currentState PlayerState.Idle; } // 被怪物打到时调用 public void TakeDamage(int dmg) { if (currentState PlayerState.Dead) return; currentState PlayerState.Hurt; anim.SetTrigger(Hurt); // 这里接血量扣减逻辑 } // 受击动画结束 public void OnHurtEnd() { if (currentState PlayerState.Hurt) currentState PlayerState.Idle; } }这段代码的关键在于攻击状态下直接return不接受移动输入角色就不会一边挥拳一边滑走。OnAttackEnd和OnHurtEnd同样由动画事件调用保证状态切换和动画时长一致。anim.SetInteger(State, ...)把状态同步给 Animator动画状态机里用这个整数做过渡条件比一堆布尔参数清爽得多。参数上moveSpeed建议先设 5格斗游戏节奏偏快太慢会显得笨重。Input.GetKeyDown(KeyCode.J)是攻击键换成鼠标左键就改成Input.GetMouseButtonDown(0)。注意GetAxisRaw比GetAxis响应更干脆格斗游戏不需要平滑加速。3.2 怪物 AI 的追击与攻击间隔怪物不能只会站着挨打。一个能用的怪物 AI 只需要三件事追玩家、进入攻击距离就打、打完等冷却。用状态机同样能表达。using UnityEngine; public enum MonsterState { Idle, Chase, Attack, Hurt, Dead } public class MonsterAI : MonoBehaviour { public MonsterState currentState MonsterState.Idle; public Transform player; public float chaseSpeed 3f; public float attackRange 1.8f; public float attackCooldown 1.5f; private float lastAttackTime -999f; private Animator anim; void Start() { anim GetComponentAnimator(); } void Update() { if (currentState MonsterState.Dead || currentState MonsterState.Hurt) return; float dist Vector3.Distance(transform.position, player.position); if (dist attackRange) { currentState MonsterState.Attack; // 冷却到了才真正出手 if (Time.time - lastAttackTime attackCooldown) { lastAttackTime Time.time; anim.SetTrigger(Attack); } } else { currentState MonsterState.Chase; Vector3 dir (player.position - transform.position).normalized; dir.y 0; transform.position dir * chaseSpeed * Time.deltaTime; transform.forward dir; } anim.SetInteger(State, (int)currentState); } // 怪物攻击动画的判定帧调用检测是否打到玩家 public void DealDamageToPlayer() { float dist Vector3.Distance(transform.position, player.position); if (dist attackRange 0.3f) // 留一点容差 { player.GetComponentPlayerController()?.TakeDamage(8); } } }attackCooldown是防止怪物贴脸后每帧都触发攻击动画没有它怪物会疯狂抽搐。lastAttackTime初始设成 -999 保证第一次能立刻攻击。DealDamageToPlayer由怪物攻击动画的判定帧调用里面再查一次距离是因为动画播放期间玩家可能已经跑开不查距离会出现「怪物对着空气挥拳玩家在远处掉血」的玄学现象。注意怪物追击时直接改transform.position会穿过墙壁。如果场景有障碍物改用NavMeshAgent或Rigidbody.MovePosition配合碰撞体。4. 避坑与排查格斗游戏最常见的五个翻车现场前面把判定和状态机搭起来了但真正跑起来一定还会遇到各种奇怪现象。这一章按「现象 → 原因 → 解决」列五个我踩过的坑基本都是初学者绕不过去的。4.1 挥拳动画播了怪物不掉血现象是攻击动画正常播放判定框在 Scene 视图里也亮了但怪物血条不动。原因通常是标签没对上OnTriggerEnter里other.CompareTag(Monster)返回 false因为怪物的 Tag 还是默认的Untagged。解决方法是选中怪物物体在 Inspector 顶部把 Tag 设成Monster没有这个标签就先在 Tag 管理器里新建。另一个可能是判定框和怪物碰撞体至少有一个没勾Is Trigger两个普通碰撞体只会互相弹开不会触发OnTriggerEnter。4.2 一次挥拳怪物掉三四次血现象是打一下血条掉一大截日志里TakeDamage被调了好几次。原因是触发器在怪物停留在判定框内的每一帧都可能触发或者攻击动画里OpenHitbox被调了多次。解决方法是像 2.2 那样加hasHit标志命中一次就锁住OpenHitbox时重置。如果还不行检查动画事件是不是在多个关键帧上重复挂了。4.3 角色攻击时还能移动像在滑冰现象是按攻击键后角色一边挥拳一边平移。原因是Update里移动逻辑没有在攻击状态下提前返回。解决方法是像 3.1 那样在currentState PlayerState.Attack时直接return把移动输入挡在门外。如果用的是Rigidbody还要把攻击期间的velocity清零否则惯性会让角色继续滑。4.4 受击后角色卡住不动现象是被怪物打一下之后角色再也无法移动或攻击。原因是受击状态进入后OnHurtEnd没有被调用状态永远停在Hurt。检查受击动画的最后一帧有没有挂OnHurtEnd动画事件。另一个可能是受击动画本身没有勾Loop播完就停事件自然不触发。把受击动画设为不循环并在末尾帧挂事件即可。4.5 怪物和玩家互相推开打不中现象是怪物靠近玩家时两者被物理引擎弹开攻击距离永远差一点。原因是玩家和怪物都挂了非运动学Rigidbody碰撞体又不是触发器物理引擎会把它们分开。解决方法是给角色和怪物的Rigidbody勾上Is Kinematic或者把它们的碰撞体设为触发器只保留判定框做实际检测。格斗游戏里角色之间通常不需要真实物理碰撞靠距离判断就够了。5. 让作业加分技能指示器与打击感的三个调参技巧基础战斗跑通之后想让期末作业从「能玩」变成「有点样子」可以加两样东西技能指示器和打击感。这两块不需要复杂代码但效果提升明显也是热搜里unity skill attack indicators常被问到的点。技能指示器说白了就是在角色脚下或前方画一个范围圈告诉玩家这一招能打到哪。最简单的做法是用一个半透明贴图的Quad或Projector攻击时显示、收招时隐藏。下面这段挂在指示器物体上由攻击脚本控制显隐。using UnityEngine; public class SkillIndicator : MonoBehaviour { public GameObject indicator; // 拖入范围圈物体 public float showDuration 0.3f; // 显示时长 private float hideTime -1f; void Start() { indicator.SetActive(false); } // 攻击开始时调用 public void Show() { indicator.SetActive(true); hideTime Time.time showDuration; } void Update() { if (hideTime 0 Time.time hideTime) { indicator.SetActive(false); hideTime -1f; } } }showDuration控制指示器停留时间设 0.3 秒左右刚好覆盖一次挥拳太长会显得拖沓。指示器的贴图用带透明通道的 PNG材质 Shader 选Unlit/Transparent避免受光照影响变暗。打击感这块三个参数最值得调。第一是命中顿帧命中瞬间把Time.timeScale设成 0.05持续 0.05 秒再恢复这一下会让打击感立刻不一样但注意恢复时要用Time.unscaledDeltaTime计时否则时间缩放会把自己也冻住。第二是受击闪白怪物受击时把材质_Color临时改成白色再改回来用协程控制 0.1 秒即可。第三是击退命中时给怪物一个朝后的短距离位移距离设 0.3 到 0.5 之间太远会打断连招节奏。我自己做这类作业时习惯先把判定和状态机跑通再花半小时调这三个参数最后交上去的版本和只做完战斗循环的版本观感差距很大。技能指示器别做太花一个干净的圆圈比一堆粒子特效更显专业。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

ChatGPT讲解——Deep Unsupervised Learning using Nonequilibrium Thermodynamics 2026/9/30 7:19:30

ChatGPT讲解——Deep Unsupervised Learning using Nonequilibrium Thermodynamics

Abstract:论文整体想表达什么? 这篇论文要解决的是生成模型中的一个核心矛盾: 模型越灵活,越能描述复杂数据;但模型通常越难训练、采样和计算概率。 例如,简单的高斯分布容易计算和采样,但无法表达复杂图像;复杂的概率模型能够拟合丰富的数据结构,却往往很难计算其归…

阅读更多 →
pgtable ___pmd_free_tlb 2026/9/30 7:19:29

pgtable ___pmd_free_tlb

___pmd_free_tlb 是 x86 架构中用于在 TLB 批量刷新(mmu_gather)过程中,延迟释放一个 PMD 页表页的底层函数。它的核心特点是将页表页的释放推迟到 TLB 刷新之后,并处理 PAE 模式下的特殊需求。核心作用:延迟释放与 TL…

阅读更多 →
Codex 一键安装包,国内网络直连,安装完成即可使用 2026/9/30 7:19:29

Codex 一键安装包,国内网络直连,安装完成即可使用

前言 做开发的朋友应该深有体会,想要本地部署 AI 代码工具,最折磨人的不是工具本身,而是环境配置。各种包版本冲突、缺少依赖、环境变量配置错误,经常折腾很久也无法正常启动。 今天分享 Codex 一键安装包,提前打包好…

阅读更多 →
鉴于我堆积的都是屎山代码,我并不介意被拿去训练用 2026/9/30 7:19:29

鉴于我堆积的都是屎山代码,我并不介意被拿去训练用

只是以后如果用这样的数据去做大模型训练之后导致拖沓和降智,那就不能怪我的代码不好了

阅读更多 →
ToC运营的重心正在从流量采买转向用户资产与信任资产:10个结构性转变与2套落地SOP 2026/9/30 7:19:29

ToC运营的重心正在从流量采买转向用户资产与信任资产:10个结构性转变与2套落地SOP

【摘要】当AI摘要使搜索排名第一的点击率下降58%、美国零售媒体广告达710.9亿美元、泡泡玛特会员销售贡献达92.9%,ToC运营的底层假设已改变。围绕10个结构性转变,给出用户资产6步SOP、AI入口GEO 4阶段SOP、AI Agent三层架构、3类误区与4条失效边界&#…

阅读更多 →
FileX 文件秘书:本地电脑文件管理小工具,简单实用 2026/9/30 7:19:16

FileX 文件秘书:本地电脑文件管理小工具,简单实用

软件下载:FileX 文件秘书 电脑用久了,磁盘里文件越堆越多。想找一个文件名含特定字符的文档,系统自带搜索要等很久;想看看 C 盘哪些大文件占了空间,手动一层层文件夹点开非常麻烦;找到一批文件之后&#x…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉