尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

Unity Netcode 预测切换(Prediction Switching)实战:EntityComponentSystemSamples 中按需启停客户端预测的完整解析

发布时间:2026/9/16 17:50:51

资讯中心
01
ARTICLE

Unity Netcode 预测切换(Prediction Switching)实战:EntityComponentSystemSamples 中按需启停客户端预测的完整解析

Unity Netcode 预测切换(Prediction Switching)实战:EntityComponentSystemSamples 中按需启停客户端预测的完整解析
Unity Netcode 预测切换Prediction Switching实战EntityComponentSystemSamples 中按需启停客户端预测的完整解析【免费下载链接】EntityComponentSystemSamples项目地址: https://gitcode.com/GitHub_Trending/en/EntityComponentSystemSamples本篇基于 EntityComponentSystemSamples 仓库中 PredictionSwitching 示例文档 展开讲解 Unity Netcode for Entities 的预测切换机制如何在游戏运行时playmode动态切换 Ghost 的预测/插值模式让客户端只对近处实体做客户端预测、远处实体退回插值从而节省 CPU 开销。读完本文你将理解该示例的沙盒结构、核心 System 的双 Job 半径判定逻辑、配置组件的烘焙链路以及可直接调用的场景默认参数。一、什么是 Prediction SwitchingNetcode for Entities 中每个同步的实体Ghost都有一种GhostMode客户端可以选择预测Predicted——用客户端预测本地模拟以追求响应性也可以选择插值Interpolated——只回放服务器历史状态以换取更低的客户端 CPU 开销。Prediction Switching 允许你在运行时切换某个 Ghost 的 GhostMode即让客户端在两种模式之间按需动态加入opt-in或退出预测从而在响应性与性能之间取得平衡同时保留服务器权威。原文档给出的核心结论Takeaways值得完整保留一般而言与 Netcode 中所有机制相同移动越快、越不可预测的实体补偿compensation起来就越困难Prediction Switching 让你选择性地对某些 Ghost 开启预测在**客户端性能通过插值与游戏响应性通过客户端预测**之间取得合理的折中同时维持服务器权威。二、示例结构一个简化的足球沙盒该示例用一个简化的football沙盒演示上述思想。示例位于 NetcodeSamples/Assets/Samples/PredictionSwitching 目录包含两个关键 Prefab资产角色Sphere.prefab物理球。它在数量多时是一个预测成本相对较高的对象正是本次优化的目标——即足球。Player.prefab玩家Character Controller它会与这些球发生碰撞交互并定义Prediction Switching Radius的圆心见 PredictionSwitchingSystem.cs。颜色图例Color Key青色Cyan——处于插值模式的 Ghost绿色Green——处于预测模式的 Ghost玩家自身的颜色变化不在图例范围内被排除。注意原文档特别指出这套颜色图例同时被Bounding Box Drawer工具使用可通过Multiplayer PlayMode Tools Window Bounding Box Drawer Disabled按钮切换该工具。运行后的可观察现象进入 playmode 后你可以观察到位于玩家半径内的球会切换到 Predicted绿色半径外的则回到 Interpolated青色反之亦然在模式切换的瞬间Transition可以观察到插值平滑过渡正在生效——尤其是当球与球之间互相弹开时。三、配置项PredictionSwitchingSettings 及其场景默认值示例文档要求读者通过PredictionSwitchingSettingsAuthoring这个MonoBehaviour修改设置并观察其对玩法的影响。该 Authoring 组件PredictionSwitchingSettingsAuthoring.cs通过RegisterBinding把序列化字段映射到 ECS 组件PredictionSwitchingSettingsPredictionSwitchingSettings.cs并由内部Baker烘焙出该组件public struct PredictionSwitchingSettings : IComponentData { public Entity Player; public float PlayerSpeed; public float TransitionDurationSeconds; public float PredictionSwitchingRadius; /// summaryThe margin must be large enough that moving from predicted time to interpolated time does not move the ghost back into the prediction sphere./summary public float PredictionSwitchingMargin; public byte BallColorChangingEnabled; }各字段含义与仓库中 PredictionSwitchingEntityScene.unity 场景里的实际默认值字段含义场景默认值Player玩家实体引用Player Prefab 实例指向 Player PrefabPlayerSpeed玩家移动速度供输入应用 Job 使用12TransitionDurationSeconds预测/插值切换时的过渡时长秒过渡期间施加平滑插值1.2PredictionSwitchingRadius预测切换半径进入半径以玩家为圆心18PredictionSwitchingMargin退出半径的额外余量源码注释明确要求该余量必须足够大保证 Ghost 从预测时间切到插值时间时不会因时间回退而重新落回预测球内部否则会出现来回抖动的乒乓效应4BallColorChangingEnabled是否启用球体变色指示1 启用 / 0 禁用1四、核心实现PredictionSwitchingSystem 的双 Job 半径判定从源码结构看整个机制由一个仅在客户端模拟世界运行的 Burst 编译系统 PredictionSwitchingSystem.cs 驱动[BurstCompile] [WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)] public partial struct PredictionSwitchingSystem : ISystemOnCreate中声明了三个前置依赖PredictionSwitchingSettings配置组件、CommandTarget本连接对应的玩家实体、GhostPredictionSwitchingQueuesNetcode 提供的预测切换队列并建立GhostOwner的 ComponentLookup 以区分本方拥有的 Ghost玩家自己与他人的 Ghost。OnUpdate的流程第 2562 行从CommandTarget取出玩家实体并读取其LocalTransform位置作为圆心通过EndSimulationEntityCommandBufferSystem创建ParallelWriter 命令缓冲用于安全地在 Job 内修改组件并行调度两个IJobEntitySwitchToPredictedGhostViaRange进入半径判定第 4150 行SwitchToInterpolatedGhostViaRange退出半径判定第 5361 行。进入半径 Job把远处的球切为预测[BurstCompile] [WithNone(typeof(PredictedGhost), typeof(SwitchPredictionSmoothing))] partial struct SwitchToPredictedGhostViaRange : IJobEntity { // ... void Execute(Entity ent, [EntityIndexInQuery] int entityIndexInQuery, in LocalTransform transform, in GhostInstance ghostInstance) { if (ghostInstance.ghostType 0) return; // 跳过无效 Ghost if (math.distancesq(playerPos, transform.Position) enterRadiusSq) { predictedQueue.Enqueue(new ConvertPredictionEntry { TargetEntity ent, TransitionDurationSeconds transitionDurationSeconds, }); if (ballColorChangingEnabled 1 !ghostOwnerFromEntity.HasComponent(ent)) parallelEcb.AddComponent(entityIndexInQuery, ent, new URPMaterialPropertyBaseColor { Value new float4(0, 1, 0, 1) }); // 绿色 } } }要点查询用WithNone(typeof(PredictedGhost), typeof(SwitchPredictionSmoothing))过滤只对尚未预测且不在过渡中的 Ghost 生效使用平方距离distancesq enterRadiusSq避免开方开销enterRadiusSq Radius × Radius第 46 行判定命中后向GhostPredictionSwitchingQueues.ConvertToPredictedQueue入队一条ConvertPredictionEntry携带TargetEntity与TransitionDurationSeconds——由 Netcode 内部的转换系统在过渡时长内完成模式切换与平滑若启用了变色且该 Ghost 不是本方所有ghostOwnerFromEntity.HasComponent(ent)为假就通过并行 ECB 添加 URP 基础色组件把球染成绿色(0,1,0,1)。退出半径 Job把近处的球切回插值[BurstCompile] [WithNone(typeof(SwitchPredictionSmoothing))] [WithAll(typeof(PredictedGhost))] partial struct SwitchToInterpolatedGhostViaRange : IJobEntity { // ... void Execute(Entity ent, [EntityIndexInQuery] int entityIndexInQuery, in LocalTransform transform, in GhostInstance ghostInstance) { if (ghostInstance.ghostType 0) return; if (math.distancesq(playerPos, transform.Position) exitRadiusSq) { interpolatedQueue.Enqueue(new ConvertPredictionEntry { TargetEntity ent, TransitionDurationSeconds transitionDurationSeconds, }); if (!ghostOwnerFromEntity.HasComponent(ent)) parallelEcb.RemoveComponentURPMaterialPropertyBaseColor(entityIndexInQuery, ent); // 恢复默认色青色插值态 } } }关键设计在于退出半径比进入半径大第 5258 行var radiusPlusMargin (predictionSwitchingSettings.PredictionSwitchingRadius predictionSwitchingSettings.PredictionSwitchingMargin); // exitRadiusSq radiusPlusMargin * radiusPlusMargin这正是配置项PredictionSwitchingMargin的作用进入用半径 R默认 18退出用 RM默认 22。这个滞回hysteresis双阈值结构避免实体在半径边界附近来回穿越时反复切换模式而WithAll(typeof(PredictedGhost))保证只对当前处于预测状态的 Ghost 做退出判定。五、配套系统连接、输入与相机跟随示例还包含若干支撑系统完整呈现了一个 Netcode 客户端/服务器分治的骨架均带文件路径可查证连接与玩家实例化PredictionSwitchingConnect.cs客户端侧PredictionSwitchingConnectClientSystem在InitializationSystemGroup中为所有带NetworkId且尚未标记的本地实体加上NetworkStreamInGame组件表示已进入游戏服务器侧PredictionSwitchingConnectServerSystem为每个连接实体Instantiate配置中的Player原型打上对应NetworkId的GhostOwner第 44 行按NetworkId奇偶在场地边缘排成一行生成第 4656 行并把玩家实体加入该连接的LinkedEntityGroup使其在断线时被自动销毁第 5960 行。输入命令PredictionSwitchingInput.csPredictionSwitchingInput是一个ICommandData通过[GhostComponent(OwnerSendType SendToOwnerType.SendToNonOwner)]只把输入命令发给非本方的客户端服务器与旁观者而本方玩家直接用本地输入。系统PredictionSwitchingSampleInputSystem在GhostInputSystemGroup中读取 WASD/方向键/触摸键写入DynamicBufferPredictionSwitchingInput第 3053 行。薄客户端Thin Client演示PredictionSwitchingThinInputSystem第 5893 行在ThinClientSimulation世界中按服务器 tick 周期自动生成左右往复的假输入用于在没有完整模拟的瘦客户端上验证输入流。服务端输入应用PredictionSwitchingApplyInputSystem第 97142 行运行在PhysicsSystemGroup、PhysicsInitializeGroup之前从指定 tick 取出输入命令并归一化方向、乘以PlayerSpeed写入PhysicsVelocity——这正是服务器权威模拟中输入命令驱动角色的标准写法。相机跟随PredictionSwitchingCameraFollowSystem第 146176 行在客户端跟随带GhostOwnerIsLocal的本地玩家保持固定偏移。输入缓冲的烘焙由 PredictionSwitchingInputAuthoring.cs 完成仅为 Player Prefab 实例添加DynamicBufferPredictionSwitchingInput。六、环境与运行前提本示例属于仓库的NetcodeSamplesUnity 项目Packages/manifest.json锁定版本为com.unity.netcode 1.12.0、com.unity.entities 1.4.4、com.unity.physics 1.4.4、com.unity.render-pipelines.universal 17.3.0编辑器版本见 ProjectVersion.txt6000.3.9f1Unity 6000 系列代码位于独立程序集 PredictionSwitching.asmdef开启allowUnsafeCode依赖 Netcode、Entities、Physics、Graphics 等程序集运行方式在 Unity 中打开该 Netcode 项目进入PredictionSwitching场景后直接 Play。编辑器会按 Netcode 的客户端/服务器引导流程在单进程内同时拉起 Server 与 Client 世界此时即可观察到球随玩家距离在青色插值与绿色预测之间切换。七、可复用的工程经验结合原文档 Takeaways 与源码实现这套示例沉淀了三条可迁移到实际项目的经验预测是有预算的移动快、交互多如物理球群的实体客户端预测的 CPU 成本显著更高对远离视线的实体退回插值是标准的性能优化手段。切换需要过渡与滞回TransitionDurationSeconds本例 1.2s保证切换期间插值平滑避免位置跳变PredictionSwitchingRadius PredictionSwitchingMargin的双阈值滞回结构避免边界抖动两者共同保证了切换无感知。一切在客户端判定、服务器保持权威从源码结构看半径判定与切换队列全部发生在ClientSimulation世界[WorldSystemFilter(WorldSystemFilterFlags.ClientSimulation)]服务器模拟不受影响切换本身通过 Netcode 的GhostPredictionSwitchingQueues官方队列完成而非手动改组件这正是该机制可被官方支持的扩展点。如果你想继续深入仓库中 NetcodeSamples/README.md 列出了 NetCube、HelloNetcode、Asteroids、PredictionSwitching、PlayerList 等全部 Netcode 示例其中 HelloNetcode 系列按 Basic/Intermediate/Advanced 分层适合配合本示例补全对服务器权威、RPC、输入命令等前置机制的理解。【免费下载链接】EntityComponentSystemSamples项目地址: https://gitcode.com/GitHub_Trending/en/EntityComponentSystemSamples创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。