【Unity脚本】使用脚本修改游戏对象静态属性

【知识链】Unity -> -> 脚本系统 -> 访问游戏对象 -> 静态属性

【摘要】本文介绍了Unity中游戏对象的静态和动态类型,并说明了如何修改静态属性。
在这里插入图片描述

第一章 Unity中的静与动

在Unity中,静态(Static)对象和动态(Dynamic)对象有着不同的属性和用途,它们的主要区别在于它们是否能够在运行时移动或变化,以及Unity对它们应用的优化策略。

静态对象是指那些在游戏中不会动的东西,比如地面、建筑物,它们永远固定在那里。Unity可以对这些静态对象进行优化,以提高游戏性能,因为这些东西不会变动。

动态对象则是会动的东西,比如玩家角色、敌人或者会滚动的球。这些对象在游戏运行时会改变位置、大小或方向,Unity需要实时计算它们的变化,所以不能对它们进行像静态对象那样的优化。

简单来说,静态对象是固定不动的,性能更好;动态对象是会动的,但需要更多计算

需要特别说明的是,在构建应用时Unity会对静态对象进行优化。Unity提供了相应的方法来改变对象的静态属性,但这种改变只是在编辑状态时有效,而对于运行时即使设置了静态属性也不会进行相应的优化。当然运行时静态属性的改变也有其他一些用途,将在本文中一一说明。

第二章 静态和动态对象

1. 静态对象(Static Objects)

定义:
静态对象是指在运行时不会移动、缩放或旋转的对象。它们的变换(Transform)属性在游戏运行期间保持不变。

主要特点:

  • 性能优化:

    • 静态批处理(Static Batching):Unity可以对静态对象进行静态批处理,这样可以大大减少绘制调用(Draw Calls),提高渲染性能。静态批处理通过将多个静态对象合并为一个网格(Mesh)来减少渲染开销。
    • 光照贴图(Lightmapping):静态对象可以在编辑器中进行光照贴图烘焙,这意味着光照信息在构建时就被预先计算并存储在贴图中,减少了运行时的光照计算开销。
    • 剔除优化(Occlusion Culling):静态对象可以参与剔除优化,Unity可以预先计算哪些对象在视野之外,从而减少不必要的渲染。
  • 物理计算:

    • 静态对象通常不会参与物理模拟(如刚体、重力等),因为它们的状态不会发生变化。Unity可以对这些对象应用简化的物理计算,从而提高性能。
      场景构建:
    • 静态对象通常用作场景的不可移动部分,例如地形、建筑物、固定障碍物等。它们为游戏世界提供了稳定的背景。

设置方式:

  • 在Unity编辑器中,选择对象后,可以在Inspector面板中勾选 “Static” 复选框,或选择具体的静态类型(如光照静态、导航静态等)。

2. 动态对象(Dynamic Objects)

定义:
动态对象是指在运行时会发生移动、缩放、旋转或其他变化的对象。它们的变换属性在游戏运行期间是可变的。

主要特点:

  • 没有静态优化:

  • 动态对象不会参与静态批处理或光照贴图烘焙,因为它们的状态是动态变化的,无法预先计算和优化。渲染这些对象时需要单独进行处理,可能会增加绘制调用。

  • 物理计算:

    • 动态对象通常是物理模拟的一部分,它们可能受到重力、碰撞、力等影响。例如,玩家角色、敌人、可移动的道具等都属于动态对象。
  • 实时光照:

    • 动态对象通常使用实时光照,这意味着光照计算在运行时进行,适应对象的实时位置和状态变化。
  • 交互性:

    • 动态对象通常是游戏中可交互的部分,它们响应玩家输入或环境变化,如推拉门、移动平台、掉落的物体等。

常见用途:

  • 动态对象用于所有需要在运行时发生变化的场景中,例如玩家角色、NPC、可移动的道具、环境变化的物体等。

3. 对比总结

特性静态对象动态对象
移动/旋转/缩放在运行时不变在运行时会变化
性能优化静态批处理、光照贴图、剔除优化等无静态优化,渲染和物理计算开销较高
物理计算通常不参与物理模拟或使用简化的计算参与物理模拟,响应力、重力和碰撞等
光照光照贴图烘焙(静态)实时光照(动态)
场景用途固定不变的场景元素,如建筑、地形可移动的游戏元素,如角色、道具

4. 实际应用

  • 选择静态对象:如果你确定某个对象在游戏运行时绝不会移动、旋转或缩放,建议将其标记为静态对象,以便Unity应用各种性能优化。
  • 选择动态对象:对于需要在运行时发生变化或与玩家互动的对象,应该保持它们为动态对象。

第三章 如何修改对象的静态属性

在Unity中,可以通过以下几种方法来改变对象的static属性:

1. 在编辑器中手动设置

操作方法:

  1. 在Unity编辑器中,选中需要设置为静态的对象。
  2. 在Inspector面板的顶部,有一个名为"Static"的复选框。
  3. 勾选此复选框后,弹出下拉菜单,你可以选择应用哪些静态标志(例如BatchingStatic、NavigationStatic等)。如果选择了Everything,对象将会被标记为所有类型的静态对象。
    用途:适用于手动设置场景中的对象为静态。

2. 在脚本中动态设置(运行时修改)

操作方法:

  • 通过C#脚本,在运行时修改对象的静态属性。虽然在运行时可以修改,但实际上在运行时修改对象的静态属性并不会触发Unity的静态优化,静态标志的实际作用在编辑器中设置并在构建时生效。

示例代码

GameObject myObject = GameObject.Find("MyObject");
// 设置对象为静态
myObject.isStatic = true;
// 取消对象的静态设置
myObject.isStatic = false;

用途:适用于在特殊情况下根据游戏逻辑临时改变对象的静态状态,但不推荐用于期望的性能优化场景,因为运行时设置isStatic并不会应用静态优化。

3. 使用 GameObjectUtility.SetStaticEditorFlags(在编辑器脚本中)

操作方法:

  • GameObjectUtility.SetStaticEditorFlags方法通常用于编辑器扩展或批量设置多个对象的静态标志。这在你需要创建自定义工具或编辑器脚本时非常有用。

示例代码:

using UnityEditor;
using UnityEngine;

public class SetStaticFlagsExample : MonoBehaviour
{
    [MenuItem("Tools/Set Static Flags")]
    static void SetStaticFlags()
    {
        GameObject myObject = GameObject.Find("MyObject");

        // 设置对象的静态标志
        GameObjectUtility.SetStaticEditorFlags(myObject, StaticEditorFlags.BatchingStatic | StaticEditorFlags.NavigationStatic);

        // 取消所有静态标志
        GameObjectUtility.SetStaticEditorFlags(myObject, 0);
    }
}

用途:适用于在编辑器中批量或程序化地设置对象的静态属性,通常在构建场景或优化时使用。
还有一种比较简便的方法
参考:https://discussions.unity.com/t/how-to-set-use-staticeditorflags-cant-seem-to-set-them-from-script/476886/13

public static void SetStaticEditorFlag(GameObject obj, StaticEditorFlags flag,  bool shouldEnable)
        {
            var currentFlags = GameObjectUtility.GetStaticEditorFlags(obj);
            if (shouldEnable)
            {
                currentFlags |= flag;
            }
            else
            {
                currentFlags &= ~flag;
            }
           
            GameObjectUtility.SetStaticEditorFlags(obj, currentFlags);
        }

使用方法:
SetStaticEditorFlag(gameObject, StaticEditorFlags.LightmapStatic, true)

总结

  • 在编辑器中手动设置:最常用的方式,适合单独设置或通过Inspector面板批量设置对象为静态。
  • 在脚本中动态设置:可以在运行时修改对象的isStatic属性,但无法利用静态优化。
  • 使用 GameObjectUtility.SetStaticEditorFlags:适合在编辑器脚本中批量设置对象的静态属性,特别适用于需要开发自定义工具或进行批量操作时。

第四章 StaticEditorFlags

StaticEditorFlags 是 Unity 中用来标记一个对象在编辑器中静态属性的枚举类型。通过设置这些标志,你可以决定 Unity 如何在构建时优化这些对象。以下是 StaticEditorFlags 的各个类型及其含义:

1. BatchingStatic

  • 描述:用于静态批处理优化。将对象标记为 BatchingStatic 后,Unity 会在构建时将多个静态对象合并为一个网格,以减少绘制调用(Draw Calls)。
  • 用途:适用于大量的、小而重复的几何体,如建筑物的墙体、柱子等。

2. NavigationStatic

  • 描述:用于导航网格优化。将对象标记为 NavigationStatic 后,Unity 会在导航网格烘焙时将其视为不可移动的障碍物或路径的一部分。
  • 用途:适用于需要在AI路径规划中被视为不可穿越的静态对象,如建筑物、固定的障碍物。

3. OccludeeStatic

  • 描述:用于遮挡剔除优化。标记为 OccludeeStatic 的对象可以被遮挡剔除系统考虑,用于决定哪些对象可以被视野外的其他对象遮挡,从而不进行渲染。
  • 用途:适用于较大的、可能会遮挡其他对象的静态物体,如建筑物或大型场景物体。

4. OccluderStatic

  • 描述:用于遮挡物优化。标记为 OccluderStatic 的对象可以作为遮挡物使用,用于遮挡视野中的其他对象。
  • 用途:适用于可以充当遮挡物的静态对象,如建筑物的墙体、山体等。

5. ReflectionProbeStatic

  • 描述:用于反射探针优化。标记为 ReflectionProbeStatic 的对象会在烘焙反射探针时被认为是静态的,因此反射效果更加精确。
  • 用途:适用于需要高质量反射效果的静态对象,如水面、玻璃、光滑的金属表面等。

6. OffMeshLinkGeneration

  • 描述:用于生成离线网格链接。标记为 OffMeshLinkGeneration 的对象会被用来生成离线网格链接,这些链接可以用作AI路径规划的跳跃、攀爬等动态动作。
  • 用途:适用于场景中需要AI做特殊移动的静态对象,如悬崖边缘、楼梯等。

7. LightmapStatic

  • 描述:用于光照贴图优化。将对象标记为 LightmapStatic 后,Unity 会在光照贴图烘焙时将其纳入考虑,使其接收并投射阴影、反射光等。
  • 用途:适用于需要烘焙光照贴图的静态对象,如地形、建筑物、室内装饰等。

8. ContributeGI

  • 描述:用于全局光照贡献。标记为 ContributeGI 的对象会被全局光照系统纳入计算,从而影响整个场景的全局光照。
  • 用途:适用于希望在全局光照中起作用的静态对象,如地形、建筑物、大型场景物体等。

9. Everything

  • 描述:将对象标记为所有类型的静态对象,即它将同时启用所有上述优化选项。
  • 用途:适用于希望对某个对象应用所有可能的静态优化的情况。

小结

  • StaticEditorFlags 提供了针对不同优化需求的标志,可以根据对象在场景中的角色和用途选择合适的标志进行设置。通过合理使用这些标志,可以显著提高游戏的性能,特别是在涉及大量静态几何体的场景中。

第五章 运行时修改静态属性

你可以在运行时修改GameObject.isStatic属性。不过需要理解的是,虽然这个属性在运行时是可修改的,但它的用途和效果与编辑器中的静态优化不同。

1. 运行时修改 GameObject.isStatic

在运行时,你可以通过脚本来动态改变一个游戏对象的静态状态,例如:

void Start()
{
    // 将该GameObject设置为静态
    gameObject.isStatic = true;
    
    // 也可以在运行时将其设置为非静态
    gameObject.isStatic = false;
}

2. 运行时修改的影响

虽然你可以在运行时更改 isStatic 属性,但这不会触发编辑器中的静态优化(如静态批处理、全局光照预计算等),因为这些优化操作通常是在构建或预处理阶段完成的,并且在运行时不再重新计算。
运行时的效果:

  • 碰撞检测:Unity可以基于该属性来优化物理系统的处理。将对象设置为静态后,Unity可以假设该对象不会在运行时移动,从而减少碰撞检测的开销。
  • 渲染优化:在某些情况下,渲染系统可能会基于该属性做出不同的优化决策,比如剔除(Culling)或灯光照射计算。
    然而,这些优化在运行时动态修改 isStatic 属性后,不一定会立刻重新计算或应用。例如,静态批处理通常不会因为在运行时改变 isStatic 而重新触发。

3. 编辑器中的静态优化

在编辑器中使用 StaticEditorFlags 来设置对象为静态时,Unity会在场景加载或构建时应用一系列静态优化,例如:

  • 静态批处理:减少绘制调用。
  • 光照贴图:预计算光照并烘焙到贴图中。
  • 导航网格:计算路径时不考虑静态对象的变化。
    这些优化通常在运行时不会因为修改 isStatic 而重新计算。

4. 小结

运行时修改 isStatic:可以改变对象的静态状态,可能会影响物理引擎和渲染系统的某些优化,但不会触发静态批处理或光照贴图等复杂的静态优化重新计算。
编辑器中的静态优化:通过 StaticEditorFlags 设置,在构建或场景加载时应用广泛的静态优化,但这些设置通常在运行时不再动态改变。
如果你希望在编辑器中批量设置对象为静态,以便在构建时获得最大化的性能优化,建议使用 GameObjectUtility.SetStaticEditorFlags 或在Inspector中手动设置静态标志。

第六章 本文总结

在Unity中将对象设置为静态,主要目的是为了提高性能。我们可以通过GameObject.isStatic和GameObjectUtility.SetStaticEditorFlags方法在编辑器中设置对象的静态属性。当然在运行时通过GameObject.isStatic修改静态属性,虽然不会触发静态优化,但可以在碰撞检测等场景中减少一部分开销。

第七章 学以致用

练习题 1:理论题

问题: 在Unity中,如何使用脚本动态设置一个对象的StaticEditorFlags?简要描述你需要完成的步骤,并编写一个脚本,使得名为"Environment"的GameObject对象被标记为静态物体,并且只开启光照贴图(LightmapStatic)和遮挡物(OccluderStatic)的静态标志。

目标:

  • 测试你对如何在脚本中使用GameObjectUtility.SetStaticEditorFlags的理解。
  • 测试你对静态标志的设置及其用途的掌握程度。

练习题 2:实践题

问题: 创建一个Unity场景,场景中包含两个GameObject对象,分别是House和Tree。使用Unity编辑器手动设置它们的静态属性:

  • House应该被设置为BatchingStatic和LightmapStatic。
  • Tree应该被设置为OccludeeStatic和NavigationStatic。
    接着,编写一个编辑器脚本,通过脚本验证这些对象的静态属性是否被正确设置。如果设置正确,在控制台输出相应的消息。

目标:

  • 测试你对在Unity编辑器中手动设置静态属性的熟悉程度。
  • 测试你对如何在脚本中获取和验证对象静态属性的理解与实践能力。

第八章 参考资料

  1. https://docs.unity3d.com/Manual/StaticObjects.html
  2. https://docs.unity3d.com/ScriptReference/GameObject-isStatic.html
  3. https://docs.unity3d.com/ScriptReference/GameObjectUtility.GetStaticEditorFlags.html
  4. https://discussions.unity.com/t/how-to-set-use-staticeditorflags-cant-seem-to-set-them-from-script/476886/13
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

tealcwu

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值