ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

Unity警车追逐逃脱源码:车辆物理、追击AI与摄像机跟随实战

Unity警车追逐逃脱源码:车辆物理、追击AI与摄像机跟随实战 1. 为什么追逐逃脱类玩法值得直接拿Unity源码起步做独立游戏这几年我越来越倾向于一个判断警察追逐汽车逃脱这种玩法是少有的机制简单但上限极高的类型。玩家开一辆车身后跟着一串警车目标是在被围堵之前冲到逃脱点——就这么一句话却能衍生出漂移、道具、氮气、路障、直升机、多路线分支等一大堆变体。搜索引擎里天天有人搜Unity Source Code、Unity 游戏模板本质上大家想要的就是这类拿来就能跑、跑起来就能改的骨架工程。我手上这套Police Chase Unity Source Code说白了就是把追逐-逃脱这条核心循环拆成了可复用的模块车辆物理、追击AI、摄像机跟随、逃脱判定、UI与关卡流程。它解决的问题很具体——新手从零搭一个能跑的追逐场景光是调车辆手感、写警察寻路、处理摄像机穿墙就能耗掉两三周而模板把这些脏活累活提前做完你拿到手改的是玩法创意不是基础设施。这套源码适合谁三类人我特别推荐。第一类是刚学完C#基础、想找个完整项目练手的学生追逐游戏涉及物理、AI、UI、协程是极好的综合练习题材。第二类是想快速做原型验证玩法的独立开发者你可能只是想测一个撞击警车回血的点子没必要重新造轮子。第三类是做外包或者课程作业的朋友有套结构清晰的模板二次开发效率能翻倍。不过我得把丑话说前面模板不等于成品。源码给你的是能跑通的框架和基础手感美术资源、关卡设计、数值平衡还得自己填。我见过太多人下载了模板跑起来发现就这其实问题不在模板在于他把模板当成了可直接上架的游戏。理解了这一点后面的内容你才能吸收得进去。2. 源码工程的整体结构与模块划分2.1 目录组织别小看文件夹规范拿到任何一套Unity Source Code我的第一个动作永远是先看目录而不是急着按播放键。目录乱的项目后面改起来必遭罪。这套警车追逐模板的Assets目录大致是这样分的Assets/ ├── _Project/ // 项目自有内容下划线排序靠前 │ ├── Scripts/ │ │ ├── Vehicle/ // 玩家与AI车辆控制 │ │ ├── AI/ // 追击状态机与感知 │ │ ├── Camera/ // 摄像机跟随 │ │ ├── Core/ // 游戏管理器、事件总线 │ │ ├── UI/ // 界面逻辑 │ │ └── Utils/ // 工具类、扩展方法 │ ├── Prefabs/ // 预制体玩家车、警车、路障 │ ├── Scenes/ // 主场景、菜单场景 │ ├── Materials/ │ ├── Audio/ │ └── Settings/ // 输入系统、渲染管线配置 ├── ThirdParty/ // 第三方插件 └── Resources/ // 谨慎使用容易增大包体为什么强调这种分法因为Unity项目一旦超过两百个资源找东西就全靠记忆。_Project前面加下划线能让它排在最上面这是我跟着不少老项目养成的习惯。另外把Scripts按功能域切分而不是按类型所有Controller放一堆是为了让一个功能的所有代码物理上聚在一起。你改追击逻辑时只需要在AI和Vehicle两个文件夹里转不用满工程翻。提示导入任何源码模板前先用Unity Hub新建一个空工程再导入。直接打开别人打包的完整工程经常因为版本不匹配触发API升级弹窗运气不好直接编译报错。2.2 版本与渲染管线的选择这套模板我建议跑在Unity 2022 LTS上。搜索热词里unity 2022中文版下载、unity下载教程热度一直很高说明大量人卡在环境这一步。为什么锁定2022 LTS而不是更新的版本因为LTS长期支持版的API稳定第三方插件兼容性好教程资料多。追逐游戏用到的Terrain、物理、Cinemachine在这些版本上都很成熟没必要追新。渲染管线方面模板同时兼容Built-in和URP通用渲染管线。如果你做手机端或者中低配PCURP更划算它的后处理、移动端性能表现普遍更好。切换管线时注意材质球会变粉需要跑一次Render Pipeline Converter重新转换材质这一步很多人漏掉看到满场景的洋红色方块就以为工程坏了。2.3 预制体驱动模板能复用的关键整套工程最值得学的一点是它用预制体Prefab承载一切可变内容。玩家车、每种警车、路障、检查点全是预制体。这意味着什么呢——关卡设计师不需要懂代码往场景里拖几个预制体调整位置和路径点一个新关卡就出来了。我在实际项目里也坚持这个原则。脚本负责怎么动预制体负责长什么样、数值多少。把数值暴露成[SerializeField]在Inspector里调比写死在代码里强太多。这里有个小坑预制体上的引用如果是场景物体比如指向场景里的逃脱点在预制体模式下改了会失效。正确的做法是通过标签Tag或者单例管理器在运行时查找而不是硬引用。3. 车辆控制与物理手感的核心实现3.1 为什么不用Rigidbody的默认物理直接开新手最容易犯的错就是给车加个Rigidbody然后AddForce往前推结果车像肥皂一样滑转向像在冰面上。追逐游戏对操控手感要求极高物理引擎的默认参数根本不能满足。这套源码采用的是一个半物理方案表面用Rigidbody做碰撞和重力实际的加速、转向、侧向抓地力全部手动计算。核心思路是这样——把车速分解成纵向前进方向和横向侧滑方向。纵向加速度由油门/刹车控制横向速度则按一个抓地力系数衰减掉。抓地力越强漂移越少系数调低车就能甩尾。这个模型的好处是参数直观你调的是要多漂而不是在摩擦力、阻力、质量之间瞎试。// 简化的车辆核心力计算 private void ApplyVehicleForces() { // 把世界速度转换到车体局部坐标 Vector3 localVel transform.InverseTransformDirection(_rb.velocity); // 纵向油门驱动 localVel.z _throttleInput * _enginePower * Time.fixedDeltaTime; // 横向按抓地力衰减制造漂移手感 float lateralGrip _isDrifting ? _driftGrip : _normalGrip; localVel.x Mathf.Lerp(localVel.x, 0f, lateralGrip * Time.fixedDeltaTime); // 转回世界坐标并赋给刚体 _rb.velocity transform.TransformDirection(localVel); // 转向速度越低转得越慢避免原地打转 float speedFactor Mathf.Clamp01(localVel.z / _maxTurnSpeed); transform.Rotate(0f, _steerInput * _turnRate * speedFactor * Time.fixedDeltaTime, 0f); }这段代码看着简单但每一行都有讲究。把速度转到局部坐标是精髓因为前进和侧滑是相对车身的。speedFactor那行解决的是原地打转问题——真车低速时转向角度有限你不加这个限制玩家停车状态一按方向键车就疯狂旋转非常出戏。3.2 加速、刹车、手刹的参数怎么调调车是个手感活我分享几个实测有效的起始数值质量设为1500车长约4.5米的标准轿车参数建议初值作用调整方向EnginePower35 ~ 50油门加速度大了暴躁小了肉MaxSpeed30 ~ 45最高速度m/s追逐游戏别太慢NormalGrip6 ~ 10正常抓地力越大越稳越不漂DriftGrip1.5 ~ 3漂移时抓地力越小甩得越狠TurnRate100 ~ 140转向速率看车长和视野BrakePower60 ~ 90刹车力度要能果断停下我踩过的坑是一开始把MaxSpeed设成60想着快才刺激结果摄像机跟不上玩家根本反应不过来AI警车也追得乱七八糟。后来降到40上下反而更耐玩。速度不是越高越好得和视野、赛道宽度匹配。刹车和手刹是两回事。刹车是纵向减速手刹则是瞬间拉低抓地力让车进入漂移。追逐游戏里手刹是核心操作——过弯甩尾、紧急掉头都靠它。模板里手刹的实现就是把NormalGrip切成DriftGrip同时轻微加一点纵向阻力模拟轮胎锁死。3.3 输入系统的处理要点现在Unity官方推的是新输入系统Input System比老的Input.GetAxis灵活得多尤其适合要支持手柄、键盘、触屏多端的项目。但我得提醒一句新老输入系统混用会出乱子。如果你在Player Settings里只勾了Input System Package那么任何用Input.GetAxis的老脚本都会直接报错。导入模板后跑不动八成是这个原因。注意确认Project Settings Player Active Input Handling的设置。如果模板同时用了两套选Both。选错了要么报错要么手柄没反应。输入这块还有一个针对移动端的实战经验。搜索热词里unity 如何扩大按钮的点击范围出现频率很高说明很多人做触屏操作时按钮点不准。手机上的虚拟摇杆和按钮视觉尺寸可以小但实际点击热区一定要放大。做法很简单给按钮加一个透明的、更大的Image作为父物体接收点击或者用EventTrigger配合扩大Rect。手指比鼠标粗太多了这个细节不处理玩家的体验就是我明明按了却没反应。4. 追击AI让警察像人一样追你4.1 有限状态机是性价比最高的选择说到AI很多人第一反应是行为树、GOAP、机器学习。我泼盆冷水追逐游戏用有限状态机FSM就够了而且更好调。行为树适合复杂决策但警车追击的行为非常明确——追、堵、撞、卡住重找路。状态机几个状态一切换逻辑清清楚楚。这套源码里警车的状态大致是Patrol巡逻没发现玩家时沿路径点巡航Chase追击发现玩家朝玩家位置开Intercept拦截接近玩家时预判其前方位置试图截断Stuck脱困被卡住超过一定时间倒车重找路Lost丢失目标玩家跑出感知范围一段时间后回到巡逻为什么加Intercept而不只是Chase因为纯追尾永远追不上——你和玩家同速的话距离不变。聪明的AI会往你前面的位置开这叫预判拦截。实现就是取玩家速度乘以一个提前量时间比如0.8秒得到预判点然后朝那个点导航。// 拦截朝玩家前方预判点移动 Vector3 PredictTarget() { Vector3 playerVel _player.RbVelocity; // 提前量随距离动态变化远的时候预判更多 float leadTime Mathf.Lerp(0.4f, 1.2f, _distanceToPlayer / _maxSenseRange); return _player.position playerVel * leadTime; }这个leadTime动态变化是关键。距离远的时候多预判追得顺距离近了少预判避免冲过头。我最初写死了0.8秒结果近身时警车总是超车冲到你前面又得掉头特别蠢。改成动态后就自然多了。4.2 感知范围与作弊技巧警车怎么发现玩家模板用的是球形检测 视线检测双保险。先判断距离是否在感知半径内再用Physics.Linecast打一条射线如果中间有墙挡着就不算发现。这模拟了看不到就不知道的真实感。但我要说个大实话完全真实的感知让AI很笨。玩家拐个弯所有警察瞬间丢失目标追逐就没意思了。所以成熟的追逐游戏都会给AI加一点作弊——比如一个群体感知机制只要有任意一辆警车锁定了玩家就通过事件总线把玩家位置广播给附近的其他警车。这样形成一张网玩家甩掉一辆还有别人跟着紧张感就上来了。// 群体感知任意警车发现目标后广播位置 EventBus.SubscribePlayerSpottedEvent(OnPlayerSpotted); void OnPlayerSpotted(PlayerSpottedEvent e) { if (Vector3.Distance(transform.position, e.Position) _shareRadius) { _sharedTarget e.Position; // 临时共享目标点 _state State.Chase; } }_shareRadius别设太大否则整个地图的警察都朝你涌来玩家无处可逃。我一般设在感知范围的1.5到2倍让包围圈有个合理的形成过程。4.3 导航与卡墙问题的根治AI车辆我强烈建议走NavMesh而不是纯物理转向。为什么因为物理驱动转向的车在狭窄弯道经常蹭墙、打滑、原地打不着方向。NavMesh给你一条平滑路径你只需让车沿着路径点走再加点物理碰撞感即可。NavMesh用起来有几个必须注意的点。第一烘焙前把路障、建筑设为Navigation Static否则AI会把墙当成能通行的地方。第二NavMeshAgent和Rigidbody一起用时别让Agent和物理同时控制位置会打架。正确做法是Agent负责目标点速度由你的车辆脚本控制Agent的updatePosition视情况关掉。卡墙脱困也是必须写的。检测方式很简单记录每秒位移如果车速接近0但油门还踩着说明被卡持续超过1.5秒就进入Stuck状态执行倒车三秒然后重新导航。这个逻辑写在状态机的一个分支里能救回大量警车顶着墙磨叽的尴尬场面。5. 摄像机跟随与视觉呈现的细节5.1 跟随摄像机的三种模式与选型搜索热词里unity摄像机跟随长期高热说明这是新手普遍卡壳的点。追逐游戏的摄像机要求比一般游戏更苛刻——车高速移动、急转弯、漂移摄像机既不能晃到晕也不能迟钝到看不见。模板提供三种模式刚性跟随硬绑在车后、平滑跟随Lerp插值、带前瞻的弹簧跟随。实测下来第三种最好用。它的逻辑是镜头目标位置 车后方一段距离 车速度方向的前瞻偏移。前瞻偏移让高速时镜头更早看到前方路况玩家反应时间更充裕。void LateUpdate() { // 基础目标车后方高处 Vector3 targetPos _target.position - _target.forward * _distance Vector3.up * _height; // 前瞻按速度往前方推一点 targetPos _target.forward * (_speedLookAhead * _currentSpeed01); // 平滑用不同的时间分辨率 transform.position Vector3.SmoothDamp(transform.position, targetPos, ref _vel, _smoothTime); transform.LookAt(_target.position Vector3.up * _lookAtHeight); }必须放在LateUpdate里而不是Update。因为车辆的移动发生在Update或FixedUpdate摄像机要在它们之后更新才能跟上最新位置否则会有一帧延迟的抖动感。5.2 解决摄像机穿墙与抖动摄像机穿墙是3D游戏的通病。追逐游戏场景里到处是建筑和路障镜头钻进墙里开天窗非常出戏。解决办法是从车到摄像机目标位置打一条射线如果撞到了几何体就把摄像机拉到碰撞点前面一点。Vector3 dir transform.position - _target.position; float dist dir.magnitude; if (Physics.SphereCast(_target.position, 0.3f, dir.normalized, out RaycastHit hit, dist, _obstacleMask)) { // 撞到障碍就缩短距离留一点缓冲避免贴脸 transform.position _target.position dir.normalized * (hit.distance - 0.2f); }用SphereCast而不是Raycast是因为摄像机有体积单根射线会漏掉边角。加一个0.3米的小球半径穿透检测更可靠。这个0.3别设太大不然摄像机离墙还有半米就急刹车看着别扭。至于抖动十有八九是因为摄像机跟随和物理更新不在同一个时序或者SmoothDamp的参数太小。我一般把smoothTime设在0.08到0.15秒之间既能跟得上又有缓冲。如果你用Cinemachine直接挂个CinemachineCollider扩展就自动处理穿墙了比手写省心但性能略高一点。5.3 速度感是怎么营造出来的玩家的感觉快和实际快是两码事。同样40m/s视野窄、镜头低、有运动模糊就感觉风驰电掣视野宽、镜头高就感觉慢吞吞。追逐游戏要靠视觉语言强化速度视场角随速度变化提速时FOV从60增到75制造推背感镜头轻微下沉加速时镜头压低贴近地面速度线或粒子车尾拖出气流效果屏幕边缘暗角高速时四角变暗聚焦中心这几招叠加起来成本极低但效果立竿见影。我调试时经常明明只把FOV加了10度测试的朋友就说感觉快了一倍。6. 逃脱判定、关卡流程与UI搭建6.1 逃脱机制的设计逻辑这套模板的核心胜利条件是一个逃脱倒计时系统玩家进入逃脱区域后维持一段时间不被抓到就算赢。为什么用维持而不是到达即胜因为到达即胜太简单了玩家直接冲过去就完事丧失了最后的紧张感。维持N秒的设计逼着玩家在逃脱点附近和警车周旋戏剧性拉满。// 逃脱判定在区域内且未被抓累积计时 void UpdateEscapeZone(bool inZone, bool isCaught) { if (inZone !isCaught) { _escapeTimer Time.deltaTime; UIManager.ShowEscapeProgress(_escapeTimer / _requiredEscapeTime); if (_escapeTimer _requiredEscapeTime) GameManager.Instance.Win(); } else { // 出圈或被撞进度衰减 _escapeTimer Mathf.Max(0f, _escapeTimer - Time.deltaTime * _decayRate); UIManager.ShowEscapeProgress(_escapeTimer / _requiredEscapeTime); } }_decayRate这个衰减系数很关键。设成0玩家出圈再进来进度不丢太宽容设太大玩家被抓一下就前功尽弃太劝退。我一般设成2到3让进度掉得比涨得快一点制造守住阵地的压迫感。6.2 关卡管理器与事件总线整个游戏的流程控制在GameManager里开始、进行、暂停、胜利、失败。我强烈建议用单例 事件总线来解耦而不是让各个脚本互相GetComponent引用。为什么因为追逐游戏里状态切换频繁——抓到、逃脱、重开、暂停如果模块间直接引用改一处到处报空。事件总线的思路是谁有事情发生就发个事件出去谁关心就订阅。玩家被抓了就发一个PlayerCaughtEventUI去监听弹结算音频去监听放音效AI去监听重置状态。彼此不知道对方存在加功能不用动老代码。这是我从大项目里学到的、小而美的架构习惯。public static class EventBus { private static readonly DictionaryType, Delegate _events new(); public static void SubscribeT(ActionT handler) where T : struct { _events.TryGetValue(typeof(T), out var d); _events[typeof(T)] (ActionT)d handler; } public static void PublishT(T evt) where T : struct { if (_events.TryGetValue(typeof(T), out var d)) (d as ActionT)?.Invoke(evt); } }这个事件总线不到30行却能让整个项目的耦合度大幅下降。缺点是用多了会难以追踪到底谁触发了什么所以我的原则是跨模块的通信走事件模块内部的调用直接写。别为了架构而架构。6.3 UI的血泪教训UI这块我踩的坑能写一页。最大的一个频繁用SetActive切换UI面板导致性能抖动。搜索热词里unity ui显示隐藏是setactive还是改localscale还是移出相机这个问题问得非常好说明大家也遇到过。我的实测结论是偶尔切换的界面设置、结算用SetActive没问题每帧都可能变的血条、进度条绝对不要SetActive改CanvasGroup的alpha或者缩放高频更新的文本能缓存就缓存GetComponentText()别写在Update里还有一个坑是Canvas的批处理。UI元素一多如果每个都带不同的材质或打断合批drawcall飙升手机端直接掉帧。做法是把同一图集的元素放一起减少不同材质的穿插。这些都是打包后才暴露的问题PC上根本看不出来。7. 实操流程从导入到打包的完整走一遍7.1 环境准备与导入第一步用Unity Hub装Unity 2022 LTS勾选Android或iOS的构建支持看你发什么平台。搜索热词里mac pro intel 12.7.6 安装 unity 3d、unity安装都很热环境这关确实劝退不少人。Mac用户注意Intel芯片和M系列芯片下载的版本可能不同别下错。第二步新建空工程把模板的Assets和ProjectSettings两个文件夹覆盖进去。为什么要连ProjectSettings一起覆盖因为输入系统、物理层级、图形设置这些都在里面只拷Assets会导致输入失效、层级错乱。第三步打开工程让Unity编译。如果弹API升级提示先备份再升级升级后跑一遍场景看有没有报错。7.2 场景搭建的关键步骤导入后打开主场景检查这几样GameManager是否挂载、玩家车预制体在不在场景、逃脱区域触发器位置对不对、NavMesh有没有烘焙。少了任何一样都跑不起来。然后自己搭一个新关卡试试拖入几个路障预制体摆放成一字长蛇、口袋阵、迷宫调整警车的巡逻路径点。这一步是理解模板结构最好的方式。你能用预制体搭出关卡就说明你吃透了这套源码。7.3 参数调试与手感打磨调参不是一次性的是反复试的过程。我的方法论是每次只改一个参数改完立刻试玩。同时改三个参数你根本不知道是哪个起了作用。手感这种东西试玩十分钟比看十篇教程都管用。数值可以参考我前面的表格但务必按你的赛道尺寸、视野角度重新校准。别人的参数在你的场景里不一定好用这是常识。7.4 性能优化与打包打包前必做的优化清单优化项做法收益剔除无形物体远处路障开Culling减少渲染开销合并静态几何场景建筑Static Batching降drawcall限制AI数量屏幕外警车降频更新省CPU纹理压缩移动端用ASTC减包体关闭多余后处理按平台分级提帧率搜索热词里unity游戏优化、unity 优化 限定数据块大小这些高频出现说明优化是刚需。警车数量一多每辆都跑状态机和寻路CPU立马吃紧。我的做法是屏幕外的AI降频不在视野里的警车从每帧更新改成每0.1秒更新一次玩家根本察觉不到但性能能救回来一大截。如果涉及微信小游戏打包热词里unity微信小游戏打包、视频播放方案、广告这些都很活跃要注意小游戏对包体和内存的限制更严很多PC上没问题的资源到小游戏上就是灾难。得提前规划资源分级和按需加载。8. 常见问题速查与独家避坑经验我把这套源码在多个项目里摸爬滚打踩过的坑整理成一张速查表遇到问题直接对照现象可能原因排查与解决车像在冰上滑抓地力系数太低调高NormalGrip转向原地打转没做速度因子限制加speedFactor乘算警车卡墙磨叽无脱困逻辑加Stuck状态倒车摄像机穿墙无碰撞检测加SphereCast缩距输入没反应输入系统设置错检查Active Input Handling材质变粉渲染管线不匹配跑管线转换器打包后掉帧UI合批失效检查图集与材质AI目标丢失就呆住缺群体感知加事件广播位置最后分享几个文档里不会写的经验。第一别急着换美术资源。先把玩法跑通、手感调好再替换车模和贴图。我见过有人花了三天做精美车模结果玩法没调好全部推倒重来。第二善用Time.timeScale做慢动作。被抓的瞬间来一个0.3秒的慢镜戏剧性直接拉满两行代码的事。第三多录屏自测。你在操控时看不出问题回放录像就能发现原来这里镜头晃得厉害。我自己在这类追逐项目里最大的体会是玩法原型阶段能用现成模板绝不自己造。追逐逃脱这套循环该踩的坑前人早踩遍了Source Code给你的就是一条被验证过的捷径。真正值钱的从来不是那几百行车辆物理代码而是你怎么在这套骨架之上长出一个只属于你的玩法。改着改着你会发现模板最后可能只剩30%的代码还在用但那30%帮你省下的时间足够你把创意打磨到发光。
返回列表