Skip to content

场景视野系统(Scene Vision) ​

场景视野系统控制单位之间的可见性、战争迷雾和本地视野遮罩表现。它按 GameDataScene 生效,同一个游戏模式里的不同场景可以使用不同视野模式,并可与场景的 SpaceModel 独立组合。

核心分层 ​

层级API作用
场景配置GameDataScene.Vision选择该场景的视野模式、精确视野观察者策略,以及是否自动使用主控单位绘制本地视野遮罩
单位默认配置GameDataUnit.Vision可选配置。单位创建后如果存在该配置,会懒创建 UnitVision 并应用观察者开关和视野形状
单位能力对象unit.Vision / unit.VisionIfCreated运行时读写观察者开关、形状和视野范围。Vision 会懒创建;VisionIfCreated 不会创建
玩家本地表现Player.LocalVisionFocus客户端本地视野遮罩的渲染焦点。只影响本地表现,不决定服务端权威可见性

场景视野模式 ​

SceneVisionConfig.Mode 支持三种模式:

模式说明
SceneVisionMode.Normal默认正常视野。按单位视野范围、阵营关系和地图视野规则计算可见性
SceneVisionMode.Open视野全开。所有单位默认互相可见,不按视野距离和阻挡限制
SceneVisionMode.Precise精确视野。按观察者单位的 Sight 距离、视野阻挡和可选扇形角度判定可见性

精确视野适合潜行、探索、战争迷雾、扇形视野、墙体遮挡等玩法。没有配置扇形形状时,精确视野仍然是圆形距离 + 阻挡判定。

观察者策略 ​

SceneVisionConfig.ObserverPolicy 只在 SceneVisionMode.Precise 下生效:

策略参与精确视野计算的单位
VisionObserverPolicy.AllOwnedUnits玩家拥有的普通视野单位都参与计算。配置最简单,但单位很多时计算量更高
VisionObserverPolicy.Explicit只有 unit.Vision.ObserverEnabled == true 的单位参与计算。适合只让英雄、侦察兵、摄像头等少量单位提供视野
VisionObserverPolicy.MainControlledUnit只有玩家的 MainUnit 参与计算。适合单主控角色、探索类玩法

如果使用 Explicit,不要忘记在单位默认配置或运行时代码里启用观察者:

csharp
Vision = new UnitVisionConfig
{
    ObserverEnabled = true,
}

视野距离 ​

视野距离仍然来自单位默认属性 GSC.GameDataUnitProperty.Sight。UnitVisionConfig 不配置距离,避免出现两套视野半径。

csharp
Properties = new UnitPropertyInitialData
{
    { GSC.GameDataUnitProperty.Sight, 900 },
}

运行时 unit.Vision.Range 读写的也是同一个 Sight 属性;服务端写入会改变单位实际视野距离,客户端为只读。Buff、属性公式或其他系统修改 Sight 后,精确视野距离也会使用最终属性值。

UnitVisionConfig.InnerRadius 不是视野距离。它只用于扇形视野:目标落在内半径内时不受角度过滤,外层仍受 Sight 距离限制。

圆形与扇形 ​

单位视野形状通过 UnitVisionConfig.Shape 或运行时 unit.Vision.SetCircle() / unit.Vision.SetCone(...) 配置。

csharp
Vision = new UnitVisionConfig
{
    ObserverEnabled = true,
    Shape = UnitVisionShape.Cone,
    CentralAngle = 90f,
    InnerRadius = 120f,
    DirectionSource = UnitVisionDirectionSource.Facing,
}
字段说明
Shape = UnitVisionShape.Circle圆形视野。半径来自 Sight
Shape = UnitVisionShape.Cone扇形视野。半径仍来自 Sight,额外应用角度过滤
CentralAngle扇形中心角,单位为度。小于 360 时产生扇形过滤
InnerRadius扇形内半径。目标在内半径内时不受角度过滤
DirectionSource = Facing使用单位当前朝向作为扇形方向
DirectionSource = Fixed使用 FixedDirection 作为固定世界角度

扇形只在精确视野模式下参与服务端可见性判定。普通视野模式不会因为配置了 UnitVisionConfig 自动变成扇形。

客户端本地视野遮罩 ​

服务端可见性是权威来源;客户端本地视野遮罩只是表现层,用于把玩家当前视野画成圆形或扇形迷雾。

框架提供一套现成可用的本地视野遮罩渲染,适合“只围绕一个单位显示玩家当前视野”的玩法,例如主控角色探索、潜行或单英雄模式。这个内置渲染同一客户端同一时间只支持一个 Player.LocalVisionFocus,通常就是本地玩家主控单位。

这只是内置客户端表现的限制,不是服务端精确视野或扇形视野的限制。服务端可以通过 AllOwnedUnits 或 Explicit 让多个单位同时提供权威视野,也可以让任意数量单位使用扇形观察形状。客户端如果需要把多个观察者的视野形状同时画出来,可以不启用内置单单位遮罩,改用 Canvas 或 GameGraph 绘制 API 自行绘制圆形、扇形或其他视野提示;这些自绘内容仍然只是表现,不替代服务端可见性判定。

在场景配置中开启 UseMainUnitAsLocalVisionFocus 后,客户端会在精确视野模式下自动把本地玩家的 MainUnit 作为本地视野遮罩焦点,并在没有全局自定义渲染管线时自动使用支持视野遮罩的渲染管线:

csharp
Vision = new SceneVisionConfig
{
    Mode = SceneVisionMode.Precise,
    ObserverPolicy = VisionObserverPolicy.MainControlledUnit,
    UseMainUnitAsLocalVisionFocus = true,
}

如果用户主动设置了 Player.LocalVisionFocus,客户端会固定使用这个值,不再自动回退到主控单位;主动设置为 null 表示关闭自动回退和本地遮罩焦点。调用 ClearLocalVisionFocusOverride() 可以清除手动设置,让场景配置重新决定是否回退到本地玩家主控单位。

csharp
#if CLIENT
Player.LocalPlayer.LocalVisionFocus = scoutUnit;

// 需要恢复场景配置驱动时:
Player.LocalPlayer.ClearLocalVisionFocusOverride();
#endif

如果游戏模式已经配置了全局自定义渲染管线,框架不会覆盖它;此时需要确保自定义渲染管线支持本地视野遮罩,否则服务端可见性可能正确,但画面上看起来像没有迷雾。

推荐配置流程 ​

  1. 在 GameDataScene.Vision 上选择 Normal、Open 或 Precise。需要墙体遮挡或扇形时使用 Precise。
  2. 在 GameDataUnit.Properties 中配置 GSC.GameDataUnitProperty.Sight,不要把距离写进 UnitVisionConfig。
  3. 只有需要作为精确视野观察者或需要非默认形状的单位才配置 GameDataUnit.Vision。
  4. 使用 Explicit 策略时,为观察者单位设置 ObserverEnabled = true。
  5. 如果需要客户端显示圆形/扇形迷雾遮罩,开启 UseMainUnitAsLocalVisionFocus,或在客户端设置 Player.LocalVisionFocus。
  6. 单主控角色玩法要确保服务端设置了 player.MainUnit,否则自动本地视野焦点没有可回退的单位。

UnitNodeBinding 绑定节点 ​

SCE 场景中的 replicated GameGraph Node 如果通过 UnitNodeBinding 绑定到 Unit,会随该 Unit 的服务端视野可见性同步。Unit 离开某个客户端视野时,该客户端会收到绑定 Node 的 OnNodeUnreplicated,之后不再收到该 Node 的 transform/delta;Unit 重新进入视野时,会重新收到 OnNodeReplicated 和当前完整 transform。

这条规则覆盖 UnitDriven、NodeDriven 和 Manual 绑定,用于 root、hitbox、hurtbox、fire point、raycast target 或自定义绑定节点。未绑定 Unit 的 replicated Node 不会按自身坐标自动套用单位视野,仍按所属 SCE Scene 同步;如果需要“没有绑定 Unit 的 node 也按所在位置做视野同步”,需要等待独立的 node 级视野同步能力。

性能与 AI 分层建议 ​

精确视野比普通视野模式更贵,因为它不仅看距离,还要考虑视野阻挡,并且扇形观察者还要做角度过滤。实际消耗取决于玩家数、观察者数、单位密度、视野半径、地图阻挡复杂度和当前同步压力;没有一个适合所有项目的固定上限。

粗略建议:

  • 优先用 VisionObserverPolicy.Explicit,只把真正需要提供精确视野的单位设为 ObserverEnabled = true。
  • 一般玩法中,把精确视野观察者控制在几十到一两百个通常更稳;达到几百个时就应该压测和观察服务端帧耗时。
  • 不建议让成百上千个小怪全部成为扇形精确视野观察者。大量敌人只需要“能发现玩家并攻击”时,通常不要让它们参与精确视野。
  • 视野半径越大、阻挡越复杂、玩家越多,越应该减少观察者数量或降低更新频率相关玩法需求。
  • 如果必须让很多单位拥有权威视野,先使用圆形精确视野或普通视野验证性能,再逐步增加扇形观察者数量。

玩家少、怪物多的常见优化 ​

如果游戏中玩家/英雄数量较少,敌方电脑怪物很多,而且只有少数玩家单位、侦察单位或摄像头需要扇形视野,可以把“玩家看见什么”和“电脑如何搜敌”拆开:

  1. 场景使用 SceneVisionMode.Precise + VisionObserverPolicy.Explicit。
  2. 只给玩家主控单位、侦察单位等少量单位配置 GameDataUnit.Vision,并设置 ObserverEnabled = true。
  3. 不给普通敌方怪物配置 GameDataUnit.Vision,让它们不参与精确视野计算。
  4. 给敌方怪物使用自定义 GameDataAIThinkTree.ScanFilters,去掉 UnitRelationship.Visible 要求,让怪物按自己的扫描范围发现周围敌人。
  5. 如果玩法需要“潜行”或“不可被普通怪物发现”,优先用自定义扩展 UnitState 表示 AI 层潜行,并在敌方 AI 的 ScanFilters、技能 AcquireSettings.TargetingFilters、以及必要的 GameDataEffectSearch.SearchFilters 中排除该状态。若复用 UnitState.InvisibleToEnemy,要确认去掉 Visible 后是否还符合项目对侦测、反隐和客户端可见性的设计。

示例:

csharp
ScanFilters = [
    new()
    {
        Required = [UnitRelationship.Enemy, UnitFilter.Unit],
        Excluded = [UnitState.Dead, UnitState.Invulnerable, CustomUnitState.Stealth]
    },
    new()
    {
        Required = [UnitRelationship.Enemy, UnitFilter.Structure],
        Excluded = [UnitState.Invulnerable]
    }
]

这种做法的含义是:玩家视野仍由少量精确观察者权威计算;电脑怪物的“发现目标”则由 AI 扫描半径和过滤器控制,不再要求目标处于怪物视野内。它只适用于敌方电脑怪物不需要遵守迷雾、墙体遮挡或扇形视野的场合。

如果敌方怪物也必须被墙挡住、必须只能攻击自己扇形视野里的目标,或者玩家可以利用绕后/遮挡躲避怪物,就不要去掉 UnitRelationship.Visible,而应让这些怪物也成为合适的精确视野观察者,并通过 Explicit 控制数量。

常见问题 ​

现象优先检查
服务端看起来像全图可见场景是否配置为 SceneVisionMode.Open;目标单位同步类型是否为 All、Ally 或其他绕过视野的同步范围
精确视野下看不到应该可见的单位是否同场景;观察者是否参与策略;Sight 是否大于 0;目标是否被墙体/视野阻挡;扇形角度是否朝向目标
配了扇形但仍是圆形场景是否为 SceneVisionMode.Precise;单位 Shape 是否为 Cone;CentralAngle 是否小于 360
服务端可见性正常,但客户端没有迷雾遮罩本地玩家是否有 MainUnit 或 LocalVisionFocus;是否开启 UseMainUnitAsLocalVisionFocus;全局自定义渲染管线是否支持本地视野遮罩
绑定到 Unit 的 hitbox / fire point 节点在客户端一直可见是否真通过 UnitNodeBinding 绑定到该 Unit;未绑定 Unit 的 replicated Node 仍按 SCE Scene 级同步
想让多个单位一起提供权威视野使用 AllOwnedUnits 或 Explicit。服务端观察者数量不受内置客户端遮罩限制
想在客户端同时画多个单位的视野形状内置本地视野遮罩只支持单个 LocalVisionFocus;多单位视野表现请用 Canvas 或 GameGraph 绘制 API 自绘
怪物很多,精确视野开销过高用 Explicit 只让少量单位提供视野;如果怪物不需要遵守迷雾/墙体/扇形,调整 AI ScanFilters 去掉 UnitRelationship.Visible,并用状态过滤处理潜行
只想做技能扇形范围使用技能/效果系统的搜索或目标过滤,不要把场景视野当作技能范围系统