尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

Unity3D FPS期末作业全攻略:从零搭建到答辩提分

Unity3D FPS期末作业全攻略:从零搭建到答辩提分 简介游戏开发中第一人称射击FPS是一种经典的游戏类型其核心技术链路包含角色控制、射击判定、敌人AI等模块在Unity3D中有着成熟的实现方案。掌握CharacterController与鼠标视角控制、射线检测即时命中、有限状态机驱动的敌人AI以及UI与数据持久化等关键点能够高效构建一个逻辑完整的可玩作品。无论是课程设计还是独立游戏原型这些技术都极具复用价值。本文基于真实的Unity3D FPS期末项目实践从功能清单到答辩演示系统复盘各模块的实现要点与踩坑经验为时间紧、基础一般的开发者提供可落地的参考。 下周就交期末作业了Unity里还躺着一个空场景老师要求做3D游戏并附带源码和设计报告。如果你的第一反应是平台跳跃或者打砖块我建议你把目光转向第一人称射击FPS。不是因为它“帅”而是因为FPS在Unity里的实现链路非常成熟角色控制、射击判定、敌人AI、UI、音效每个模块都有固定套路按顺序搭好是短期内最容易做出“完成度高”观感的类型之一。而且每个模块都能写进设计报告变成实实在在的得分点。这篇文章不是教程搬运是我自己从零做Unity3D第一人称射击期末作业的完整复盘。包含功能清单怎么定、角色和射击手感怎么调、敌人AI怎么做、报告怎么写、答辩怎么讲以及最容易让人翻车的打包和存档问题。适合时间紧、基础一般、想把作业做得“有技术含量”的人参考。1. 期末FPS作业的定位先搞清楚老师想看什么1.1 为什么FPS是性价比最高的期末选题课程设计的评分逻辑和商业游戏评审完全是两回事。老师看一份Unity期末作业核心关注三点第一程序能不能跑起来、交互是否流畅第二有没有完整游戏循环而不是一堆摆好但不能玩的东西第三有没有体现课程里讲过的关键知识比如碰撞检测、物理系统、UI交互、数据持久化。FPS在这三点上天然占优。玩家移动、镜头旋转、开枪、敌人扣血、敌人死亡、计分、重新开始这一整套因果反馈链非常直观演示的时候老师一眼就能看懂“你的游戏做完了”。我自己当年见过不少同学花了很多时间做RPG类型的作业结果NPC对话系统没写完背包系统半成品最后只能演示一段“角色在地图上跑来跑去”场面相当尴尬。相比之下FPS哪怕只做一关只要“开枪能打死敌人、分数能累计、死了能重开”就妥妥是一个逻辑完整的作品。还有一点容易被忽略FPS不需要大量美术资源。用Unity自带的Cube、Capsule、Terrain就能搭出可玩的场景。枪械模型、敌人模型都可以从Asset Store免费资源或低模素材里找真正的时间投入在代码逻辑上而不是在建模和调材质上。对于期末这种以代码评分主体为主的场景这笔账非常划算。1.2 从验收标准倒推最小功能清单很多人的期末作业做不完不是能力不够而是目标定得太宽。今天加一个换弹动画明天加一个武器切换后天又想搞个地图传送点到最后主线玩法反而没做完。正确的做法是先定一条“功能基线”也就是所谓的最小可玩版本Minimum Viable ProductMVP把它做完做稳再做加分项。我给自己定的MVP清单长这样模块功能要求是否必须角色控制移动、跳跃、鼠标视角旋转必须射击判定鼠标左键开火、射线命中敌人、敌人扣血必须敌人AI至少能巡逻和追击玩家被击杀后有反馈必须游戏流程开始界面、游戏倒计时或波次、结束界面必须HUD生命值、得分、准星必须音效枪声、命中音、背景音加分项但建议做数据持久化最高分保存加分项代码少建议做武器系统多把枪、换弹、后坐力加分项视时间而定这个清单的妙处在于每一项都对应设计报告里的一个章节。做完清单里的所有“必须”项你的游戏已经能完整跑通一局了如果还有时间再往“加分项”里加。我身边按这个思路做的同学普遍比那些从第一天就开始找枪械模型的同学最后完成度高很多。记住美术资源可以往后放但玩法闭环一定要最先完成。2. 角色控制与场景搭建第一人称的第一步2.1 CharacterController还是Rigidbody先做对选择第一人称角色的移动控制Unity里主流方案有两个CharacterController和Rigidbody。这两个组件都常用于角色控制但使用场景差别很大需要做一次清晰的对比。维度CharacterControllerRigidbody物理碰撞方式类似胶囊碰撞体手动推进不自带真实物理响应完全由物理引擎驱动碰撞响应真实受到外力影响几乎不受需要自己代码处理击退等效果受重力、碰撞、外力影响更真实坡度爬升自带Step Offset和Slope Limit上坡下坡体验好需要额外配置材质和力来控制斜坡站立会沿着坡面下滑需要额外处理稳定在斜面上站立典型使用场景人形角色、NPC、FPS主角可推动箱子、载具、受物理效果影响的对象我的建议是主角用CharacterController。原因很实际FPS主角不需要被爆炸炸飞不需要被子弹击退只要稳定移动和跳跃就行。CharacterController的API简单直接Move()方法传入速度向量每帧调用内置碰撞和斜坡处理写起来远比Rigidbody省心。Rigidbody做角色最麻烦的就是碰撞后镜头乱晃、速度不稳定你得写一堆代码去“锁”住物理效果纯属给自己加工作量。另外如果你打算让敌人也用简单的移动方式同样可以用CharacterController或NavMeshAgent后面会细说。物体拾取、子弹击退这些需要物理反馈的再用Rigidbody各尽其职。2.2 鼠标视角与移动控制第一人称的手感基础第一人称的手感核心在两块鼠标视角旋转和WASD移动。这两块的代码量不大但踩坑点不少。先看鼠标视角。通常的做法是把角色拆成两个节点一个负责水平旋转绕着Y轴转一个负责垂直旋转绕着X轴转。水平旋转挂在Player对象上垂直旋转挂在子物体Camera上。如果反着来镜头会出现“万向锁”问题也就是抬头超过90度后旋转方向反掉体验非常糟糕。垂直旋转需要加限制。现实中人抬头低头是有限度的所以把Camera的欧拉角X轴限制在-90到90度之间。代码如下using UnityEngine; public class MouseLook : MonoBehaviour { public Transform playerBody; public float mouseSensitivity 2f; private float xRotation 0f; private void Start() { Cursor.lockState CursorLockMode.Locked; Cursor.visible false; } private void Update() { float mouseX Input.GetAxis(Mouse X) * mouseSensitivity; float mouseY Input.GetAxis(Mouse Y) * mouseSensitivity; xRotation - mouseY; xRotation Mathf.Clamp(xRotation, -90f, 90f); // 垂直旋转挂在Camera上 transform.localRotation Quaternion.Euler(xRotation, 0f, 0f); // 水平旋转挂在Player父物体上 playerBody.Rotate(Vector3.up * mouseX); } }光有视角还不够移动控制要跟上。CharacterController有一套固定的“获取输入-转换方向-应用位移”流程。输入用Input.GetAxis获取WASD对应的Horizontal和Vertical轴然后用transform.right和transform.forward把输入方向从局域坐标系转换到世界坐标系最后调用CharacterController.Move()。跳跃和重力需要自己维护一个垂直线速度变量。每帧减去重力加速度乘deltaTime落地时清零。跳跃时给这个速度一个向上的初值。这个逻辑虽然简单但写错了会出现“跳起来像坐电梯”或者“永远掉不下来”的问题核心就是别忘了在controller.isGrounded为true时把垂直速度重置为一个小负值而不是0这样角色才能稳定贴地。using UnityEngine; public class PlayerController : MonoBehaviour { public float moveSpeed 6f; public float jumpHeight 1.5f; public float gravity -9.81f; private CharacterController controller; private float verticalVelocity; private void Awake() { controller GetComponentCharacterController(); } private void Update() { float horizontal Input.GetAxis(Horizontal); float vertical Input.GetAxis(Vertical); Vector3 move transform.right * horizontal transform.forward * vertical; controller.Move(move * moveSpeed * Time.deltaTime); bool isGrounded controller.isGrounded; if (isGrounded verticalVelocity 0f) { verticalVelocity -2f; // 一个小负值保证贴地 } if (Input.GetButtonDown(Jump) isGrounded) { verticalVelocity Mathf.Sqrt(jumpHeight * -2f * gravity); } verticalVelocity gravity * Time.deltaTime; controller.Move(new Vector3(0f, verticalVelocity, 0f) * Time.deltaTime); } }2.3 场景布置与免费美术资源别在美术上花太多时间做期末作业最容易掉进去的坑就是在美术资源上花大量时间精修。我的切身体会是如果你把找枪械模型、调贴图的时间用在调试射击手感和敌人AI上最后的总分大概率要高得多。因为代码逻辑是“硬技术”而美术风格属于主观判断老师不会因为你的枪好看就多给你十分但会因为敌人会巡逻会追击而觉得你的作业更有设计感。场景搭建可以参考这几个原则用Unity自带的地形工具Terrain拉一块地面刷一些草和树视觉上就及格了。用Cube、Cylinder摆几个掩体FPS的地图氛围立刻出来还顺带测试了碰撞。从Asset Store里搜一些免费的低模资源比如环境素材、枪械模型、敌人角色注意看授权许可尽量选允许免费使用的。如果想导入外部模型比如SolidWorks建模后导入注意单位转换。Unity默认单位是米SolidWorks里通常习惯用毫米导入后会出现模型巨大或缩成一团的问题需要在导入设置里把Scale Factor调整到0.01这是很常见的坑。3. 射击系统从射线检测到伤害结算3.1 射线检测与弹道模拟期末作业选哪个射击判定的实现方式FPS游戏里就两大流派即时命中Hitscan和弹道模拟Projectile。即时命中的思路是你开枪的瞬间从枪口或相机中心发射一条射线沿射线方向检测第一个碰撞到的物体立刻结算伤害。CS:GO、守望先锋、Valorant都是这种模式。它的好处是手感干脆逻辑简单不需要管子弹的飞行过程。弹道模拟则是生成一颗有速度、有重力的子弹对象像战地系列的部分武器那样需要考虑飞行时间、下坠、弹道散布。它更真实但复杂度提升一个量级。期末作业我强烈建议选射线检测。理由非常直接期末答辩不会有人要求你展示“子弹飞行轨迹”但要确保“开枪后目标立刻扣血”。射线检测天然适合处理高速目标不存在子弹碰撞穿透问题。实现代码量只有几行逻辑清晰答辩时讲起来也容易。核心实现代码如下using UnityEngine; public class Gun : MonoBehaviour { public Camera playerCamera; public float damage 25f; public float range 100f; public ParticleSystem muzzleFlash; public AudioClip shootSound; private void Update() { if (Input.GetButtonDown(Fire1)) { Shoot(); } } private void Shoot() { // 播放枪口火光和枪声 if (muzzleFlash ! null) muzzleFlash.Play(); AudioSource.PlayClipAtPoint(shootSound, transform.position); RaycastHit hit; if (Physics.Raycast(playerCamera.transform.position, playerCamera.transform.forward, out hit, range)) { // 命中目标调用伤害接口 IDamageable damageable hit.collider.GetComponentIDamageable(); if (damageable ! null) { damageable.TakeDamage(damage); } // 在命中点生成弹痕效果 // 这里可以实例化一个小Quad贴在碰撞表面 } } }有个细节值得注意射线起始点不要用枪口而要用相机中心。因为玩家的视野是跟着相机走的如果射线从枪口发出子弹落点会和准星不一致近距离还好远距离偏差会大到离谱。这也是很多新手第一版射击“打不准”的原因。当然如果用相机中心发射射线枪口火光还是在枪口模型上视觉效果不影响。3.2 开火表现枪口火光、弹痕、准星扩散射击手感这东西30%靠判定逻辑70%靠表现反馈。如果开了枪只有敌人扣血玩家是感受不到的必须有一整套“开枪反馈链”来告诉玩家“你刚才那一枪生效了”。我调射击手感时一般按这个顺序加反馈枪口火光Muzzle Flash一个ParticleSystem放在枪口位置开枪时Play()。很小的细节但视觉冲击力很强。枪声AudioSource.PlayClipAtPoint配合一把短促有力的枪声音效。命中提示敌人被击中时闪白或闪红可以用协程把材质颜色短暂改掉。弹痕贴花在RaycastHit.point处生成一个小平面贴图模拟子弹打墙上留下的痕迹。准星扩散连射时准星变大停火后慢慢收缩。虽然只是UI操作但会明显提升“射击感”。弹痕的生成我建议直接写一个简单的对象池而不是每打一枪就Instantiate一个Quad。因为连续射击时生成大量临时物体会造成Draw Call飙升和GC压力手机上尤其明显。用一个List维护空闲弹痕对象命中时取出复用超过上限就回收最旧的那个代码不超过三十行但这是设计报告里很加分的“性能优化点”。在敌人身上我更建议用Canvas血条或简单的动画变色来反馈伤害而不是通过屏幕震动。因为屏幕震动幅度控制不好会让玩家头晕反而拉低手感。3.3 生命值、伤害计算与击杀反馈伤害计算是射击系统的核心。为了让代码结构清晰我一定会先定义一个伤害接口而不是在子弹里直接判断“如果打到敌人就扣血”。原因很简单如果以后加了炸药桶、木箱、Boss这些都可以实现同一个接口子弹不需要改任何代码这就是面向接口编程的意义。接口定义非常简单public interface IDamageable { void TakeDamage(float amount); }敌人的具体实现可以在TakeDamage里处理扣血、死亡、播放死亡动画、加分。这样设计后敌人的血条、玩家的枪、甚至未来的手雷都通过接口解耦。伤害数值这块我建议给不同武器设定明显差异。比如手枪25点伤害步枪15点但射速快狙击枪90点。这样游戏就有了武器选择和策略感也方便在设计报告里写“武器数值平衡性分析”又是一小块能撑起篇幅的内容。如果做头部伤害判定可以给敌人加一个子碰撞体用碰撞体名称区分头部和身体头部伤害乘2。这个功能不复杂但演示效果非常拔群。击杀反馈我一般做三件事敌人身体变透明消失、播放死亡音效、UI上弹出“10”得分飘字。敌人消失不能直接用Destroy因为会显得很突兀。我习惯用协程做一个0.5秒到1秒的渐隐或者快速下坠动画看起来更自然。击杀反馈做得好不好直接决定答辩演示时观众“哦”一声还是“嗯”一声的区别。4. 敌人AI与关卡循环让游戏有“玩头”4.1 敌人状态机巡逻、追击、攻击敌人AI是一门大学问但期末作业不需要深度学习、行为树那些花哨东西最经典的有限状态机FSM就足够。一个敌人至少有四个状态巡逻Patrol、追击Chase、攻击Attack、死亡Dead。每个状态的行为简单明确状态触发条件行为巡逻出生后默认在出生点附近随机游走寻找玩家追击玩家进入索敌范围朝玩家方向移动持续接近攻击距离小于攻击范围停止移动播放攻击动作造成伤害死亡生命值归零停止所有行为播放死亡效果销毁我实现FSM用的是最简单的枚举Switch写法。对于作业来说这比抽象状态机模式更好懂也更容易在报告里画状态图。如果你想让报告看起来“有设计感”可以再画一张“敌人状态转换图”这是标准的加分操作。切换到追击状态的判定条件不能只看距离。如果隔着墙敌人也能“看到”你会显得很假。我在检查距离的同时会从敌人往玩家方向打一条射线如果射线被障碍物挡住就认为没有视线不触发追击。这个“视线判定”在实现上只需要多写5行代码但游戏真实感直线上升。4.2 NavMesh寻路与避障别让敌人撞墙追击状态的核心问题是“怎么走到玩家面前”。最简单粗暴的做法是让敌人直接朝向玩家移动。但现实地形不会这么配合——如果有掩体、障碍物敌人会一头撞在墙上原地抽搐。这时就需要NavMesh寻路。NavMesh是Unity内置的寻路系统使用步骤分三步打开Window - AI - Navigation面板。选中场景里需要参与寻路的静态物体地面、墙壁、箱子在Inspector里勾选Navigation Static。在Navigation面板里点击Bake生成导航网格。然后给敌人挂上NavMeshAgent组件运动相关的参数都不用手动控制直接调Agent的Speed、Angular Speed、Stopping Distance然后在追击状态里调用agent.SetDestination(player.position)剩下的交给引擎。这里有一个非常容易翻车的细节Bake完成后如果你后来改了场景模型比如加了一堵墙忘了重新Bake敌人就会尝试穿墙走过去。所以每次改完场景一定要记得去Navigation面板重新Bake。另外NavMeshAgent只负责“移动路径”不负责“动画表现”。如果你用默认的Capsule模型敌人移动时看起来是滑行的这很出戏。我建议给敌人挂一个Animator做一个简单的“走路/攻击/死亡”动画切换或者退一步让敌人在追击时用正弦波模拟身体起伏也会比完全滑行好一点。4.3 刷怪、得分与关卡结束条件完成单个敌人之后还要把它们组合成“关卡循环”。我设计的是波次刷怪制玩家进入关卡后敌人分波生成每波敌人全部被击杀后下一波生成所有波次结束后显示胜利界面。这种结构的好处是可控性强、演示效果好代码也简单。刷怪器EnemySpawner的核心逻辑是在场景中设置三到五个生成点刷怪时随机选一个。每波生成固定数量的敌人数量可以逐波递增。监听“玩家得分”变化来判断当前波是否清空。全部波次结束后触发胜利UI。得分机制我放在敌人死亡时处理。敌人实现了IDamageable接口在TakeDamage里判断生命值归零时调用全局的得分管理器GameManager的AddScore()方法。这样一来新增敌人类型、新增武器都不会破坏得分流程。关卡结束条件一定不能只做胜利条件。失败条件同样重要玩家生命值归零后进入失败界面显示本局得分和最高分并允许“重新开始”。把胜败条件都做完游戏的“完整度”才装得起来这在报告里可以专门写一节“游戏流程设计”。5. UI、音效与存档容易被忽略的提分项5.1 HUD与菜单流程一个完整的游戏循环FPS游戏的UI看着不起眼但它决定了“游戏是否像一个完整的商品”。一个最小的FPS UI系统至少要包含三层主菜单游戏标题、开始按钮、操作说明、退出按钮。游戏内HUD生命值、得分、准星、当前波次。结束界面胜利/失败文字、本局得分、最高分、重新开始按钮。Unity里用UGUI做这些非常快。Canvas设成Screen Space - Overlay所有UI自动在最上层省去设置相机的事件相机。注意主菜单和结束界面必须连到EventSystem不然按钮点了没反应。这三个界面的切换我建议用一个GameManager类来管理。GameManager持有一个枚举类型的GameStateMainMenu、Playing、Paused、Victory、Defeat。每个状态切换时控制对应场景的显示和隐藏、Time.timeScale的启停、鼠标指针的锁定状态。这样整个游戏流程的代码都集中在GameManager里报告写起来也方便。暂停功能别忘了。按Esc或P键时把Time.timeScale设为0弹出暂停菜单。恢复时设回1。这里有个坑timeScale为0时协程里的WaitForSeconds也会被暂停如果你希望在暂停时执行某些特效逻辑要用WaitForSecondsRealtime。还有暂停时记得把鼠标指针解锁否则玩家看到暂停菜单但鼠标还在屏幕中间移动不了按钮会非常抓狂。5.2 音效与氛围营造把“廉价感”压下去很多学生作品感觉“很便宜”一半原因是没有任何声音。同样的射击动作有枪声和没枪声给人的专业感天差地别。Unity里播放音效的最小实现就是一行AudioSource.PlayClipAtPoint(clip, position)成本极低但效果立竿见影。我的音效优先级排序是枪声 命中音 敌人脚步声 背景音乐 UI点击音。前四个属于“不做就缺失”最后一个属于“做了很精致”。背景音乐建议用AudioSource挂到主相机上循环播放音量调低一点。如果引擎里没有现成音乐可以用简单循环音轨或者从免费音效站找一些无版权的环境音。记住背景音乐的目的是营造氛围不是抢戏音量控制在-18dB到-12dB比较合适。如果想再往上走一步给音效加上AudioMixer把主音量、音乐音量、音效音量分开并在设置界面里让玩家调节。这个设计和“音频系统”章节完美对应报告里的“系统设计说明”又多一个能写的内容点。5.3 数据持久化最高分与设置的保存Unity里保存数据的方案很多从简单的PlayerPrefs到Json文件再到SQLite。期末作业用到的最优解是PlayerPrefs。它的API非常简单操作类似于键值对存储// 保存最高分 PlayerPrefs.SetInt(HighScore, score); PlayerPrefs.Save(); // 读取最高分 int highScore PlayerPrefs.GetInt(HighScore, 0);但注意一个容易忽略的问题PlayerPrefs在编辑器、Windows和Android上存储位置不同。如果你在编辑器里测试时保存了数据打包到安卓手机后是读不到的因为它们是不同的存储位置。我见过有同学在电脑上跑得好好的打包到手机后存档“丢失”其实是存储路径不同导致的误解。如果游戏有复杂的存档需求比如关卡进度、武器解锁用PlayerPrefs存字符串或Json也可以但不建议在期末作业里做太重。最高分、音量设置、鼠标灵敏度设置这三个用PlayerPrefs搞定数据的完整性和简单性兼顾。再提一个跟存档相关的经典坑如果把存档文件写到Application.persistentDataPath下的自定义文件在Android上需要处理运行时权限。而PlayerPrefs是对开发者完全透明的不涉及权限问题。所以期末作业能PlayerPrefs就PlayerPrefs别自己折腾文件读写。5.4 画面后处理低成本高观感这算一个“隐藏提分点”。Unity的URP渲染管线自带Volume后处理系统给主相机加一个Volume组件添加Bloom泛光和Vignette暗角画面质感立刻提升一个档次几乎零成本。Bloom会让枪口火光看起来更亮Vignette会聚焦玩家的注意力配合场景灯光能营造出一种“正式游戏”的感觉。不过要注意URP管线的设置需要在项目创建时就选好。如果是刚创建的项目建议创建时直接选Universal 3D模板。如果你已经在用默认的Built-in管线也不用慌控制台下的Post Processing Stack也可以实现类似效果只是配置方式略有不同。6. 设计报告写作与期末答辩准备6.1 设计报告的写作框架与得分点期末作业的源码和设计报告是评分的两大核心。设计报告写得好等于用文档给老师“二次讲解”了一遍你的项目会显著降低改作业的人的理解成本。我见过代码功能很全但报告写得流水账的同学分数反而不如功能略少但报告条理清晰的同学。一个标准的Unity游戏期末设计报告目录建议这样组织章节内容建议对应项目部分摘要纯文字概述你做的是什么游戏、用到了哪些关键技术整篇浓缩关键技术路线技术选型说明为什么用URP、为什么用射线检测、角色控制器选型等技术决策系统需求分析功能需求和非功能需求对应MVP功能清单功能清单总体设计游戏流程状态图、核心类图、模块划分架构设计模块详细设计每个模块角色控制、射击、AI、UI、存档的代码实现讲解核心代码测试与分析运行结果截图、测试用例、性能分析运行效果总结与展望遇到的问题、解决过程、未来能怎么扩展项目复盘写摘要时有个技巧不要只说“我做了一个FPS游戏”要突出关键技术词。比如“本作品基于Unity 2022 LTS和URP渲染管线实现了基于有限状态机的敌人AI、基于射线检测的即时命中射击系统、基于PlayerPrefs的本地存档机制”这句话一出来技术含量立刻上来了。每个模块的详细设计建议采用“截图代码片段说明”的三段式写法。截图放运行效果代码片段放核心实现说明部分解释“为什么这么做”的逻辑依据。这样一段代码讲下来报告的字数和质量都有保障。绝对不要贴整段完整代码老师没时间看读起来也像在读源码而不是读文档。6.2 答辩演示顺序与常问问题答辩演示的顺序我建议严格按照“主菜单 - 操作说明 - 游戏进行 - 胜利/失败 - 代码展示”的流程来。一来让老师看清楚游戏玩法二来在演示中穿插讲设计思路三来可以在最后展示代码时回答老师的提问。演示过程最容易翻车的点有两个一是游戏内突然报错二是敌人AI抽风。针对报错我有个很实用的建议演示时如果遇到Bug不要慌先看是不是环境问题比如没连手柄快速重启重新进入游戏比在现场找Bug要稳妥得多。针对敌人AI如果你用了NavMesh演示前一定要确认场景Bake过否则敌人会当众穿墙。老师最可能问的问题我提前帮你列好为什么用CharacterController而不用Rigidbody射线检测的原理是什么如果子弹速度很快会不会出现穿墙敌人AI怎么实现巡逻和追击的状态之间是怎么切换的如果一屏有几十个敌人游戏会卡吗怎么优化你的数据是怎么保存的换了机器能不能继续读这几个问题的标准回答思路是第一个讲“角色需要稳定移动不需要物理反应”第二个讲“射线是每帧瞬时检测不走物理运动所以不存在穿墙”第三个讲“用有限状态机距离和视线判定触发切换”第四个讲“对象池、限制每帧射线检测数量、降低导航网格更新频率”第五个讲“PlayerPrefs保存到本地读取时加了缺省值保护”。答辩时不要只会照着代码念要强调“我做了什么、为什么这样做、遇到了什么问题、怎么解决的”。哪怕你的解决方案不是最优的只要你能讲清楚思考过程老师都会认可。7. 我踩过的坑和给学弟学妹的建议7.1 学生党最常翻车的四个坑第一个坑是“只做不测”。有的人代码写完就交从来没做过完整流程测试。结果老师演示时一枪打死敌人后分数没变或者死了一次后游戏卡死直接给了个低分。我建议你在提交前至少完整跑三遍游戏覆盖胜利、失败、中途暂停、退出重开这些路径。第二个坑是“场景列表没配”。Unity打包时Build Settings里有一个Scenes列表你必须把用到的场景拖进去否则打包出来的游戏是个黑屏。我见过不止一个同学演示前一天打包发现“什么都没有”就是这个原因。第三个坑是“在编辑器里能跑发布后跑不了”。常见原因包括脚本用了编辑器API、资源用了StreamingAssets但没放对位置、Lighting没有BakeBaked光照在打包后找不到光照贴图。发布前一定要做一次Build在Windows或Android上实际启动验证。第四个坑是“版本不兼容”。用了Unity 2021创建的工程拿到Unity 2023打开经常报一堆错误。期末项目从创建到提交尽量锁定同一个Unity版本不要中途升级。7.2 我是怎么分配这四周时间的如果你按四周规划这项作业我建议这样分配时间和任务第一周搭建场景、实现角色移动、实现鼠标旋转、把枪械模型摆到相机下方。每天推进一个脚本周末前一个能走路、能跳、能看到枪的角色在场景里跑动这就是第一个里程碑。第二周实现射线射击和伤害结算。先让子弹能打中一个测试Cube并让Cube变色再把伤害接口和敌人预制体做好。周末前能打死一个静止的敌人、能看到血条变化这是第二个里程碑。第三周做敌人AI和关卡循环。先让敌人巡逻再让敌人追击玩家最后加攻击和死亡逻辑。然后把刷怪器、胜利/失败条件、UI界面串起来。这周结束你的游戏已经是一个可以完整玩一局的成品了。第四周查漏补缺写设计报告做打包测试。这周不建议再大动功能只做完善音效、后处理、最高分、操作说明、Bug修复。每天抽时间写报告别最后两天突击。7.3 打包发布演示当天才发现的致命问题打包相关的坑我在前面提到过场景列表这里再补充几个。如果你的目标平台是Android需要提前装好Android Build Support模块和对应版本的JDK、SDKUnity Hub和Android Studio这些环境配置很琐碎建议提前一周处理完。脚本后端建议选IL2CPP它对C#语法支持更严格能暴露很多在Mono下被忽略的问题比如代码里的值类型陷阱虽然首次打包耗时更长但产物性能更好。打包之后用真机做一个简单的性能测试。如果你的游戏在低端安卓机上掉帧严重优先检查Unity场景中的实时灯光数量、粒子特效数量、后处理效果是否过重。把实时阴影关掉或者改为Baked是立竿见影的优化手段。这些性能优化也可以写进报告“测试与分析”章节注明帧率改善数据学术味更浓。根据我的个人经验最后一天才去处理打包和真机问题是整项作业里心态最容易崩溃的时候。把“打包验证”提前到第四周的周三之前完成你会发现自己还有充裕时间处理各种意外状况。最后再分享一个小技巧当你把项目提交给老师之前自己扮演一次“老师”从头到尾玩一遍游戏边玩边记录哪里不顺畅、哪里没提示、哪里看起来像半成品。改掉这些问题后你的Unity3D第一人称射击期末作业无论从源码完成度还是设计报告质量来说都不会辜负你投入的时间。本文还有配套的精品资源点击获取
返回列表