美文网首页unity
GameObject.Instantate前后对字段赋值在生命周

GameObject.Instantate前后对字段赋值在生命周

作者: 雨落随风 | 来源:发表于2018-11-02 13:37 被阅读4次

有些问题不去试试,不清不楚不方便搞事情,就像笔者今天做的这个备忘一样。

写在前面

  • 这个笔记就是记录一个测试结果。
  • 测试的目的是确认一个字段 在 Resource.Load 后获得,并在Instantate前后 赋值,观察它在生命周期中的表现:

实验流程

1 .测试用c#类:

using UnityEngine;

public class TestInstantatLifeCycle : MonoBehaviour {
    GameObject go;
    void Update () {
        if (Input.GetMouseButtonDown(2))
        {
            TestLifecycle();
        }
        if (Input.GetKeyDown(KeyCode.R))
        {
            if (null != go)
            {
                Debug.Log("重新加载Prefab");
                TestLifecycle(true);
            }
        }
    }
    #region TestCode
    private void TestLifecycle(bool ifReload = false)
    {
        if (null == go || ifReload)
        {
            go = Resources.Load<GameObject>("一个预制体");
        }

        Debug.Log("加载资源!");
        TestChangeFieldValueAfterResourceLoad before = go.GetComponent<TestChangeFieldValueAfterResourceLoad>();
        Debug.Log((null == before) + ":" + (null == go));
        Debug.Log("1.赋值前 " + before.AA+":"+before.BB);
        before.AA = "After Resources.Load";
        before.BB = new TestRefrenceField();
        Debug.Log("2.赋值后 " + go.GetInstanceID() + " : " + before.AA + " : " + before.GetInstanceID()+":"+before.BB.BB); //编辑模式Resource加载后实例化前赋值字段会导致Resource目录下的预制物字段的值被修改。 运行模式下只修改内存值,app重开恢复默认。
        Debug.Log("实例化前");
        GameObject go_after = GameObject.Instantiate(go);
        Debug.Log("实例化了");
        TestChangeFieldValueAfterResourceLoad after = go_after.GetComponent<TestChangeFieldValueAfterResourceLoad>();      //引用的参数,如果没有标记可序列化,Resource.Load之后修改了数据在instantate时依旧加载默认值,不能序列化的类默认值null。
        Debug.Log("3.实例化后 " + go_after.GetInstanceID() + " : " + after.AA + " : " + after.GetInstanceID()+" : "+after.BB.BB); 
        after.AA = "xxx实例化后 ";
        after.BB = new TestRefrenceField() {BB="实例化后赋值" };
        Debug.Log("4.实例化后赋值 " + go_after.GetInstanceID() + " : " + after.AA + " : " + after.GetInstanceID()+" : "+after.BB.BB);  //实例化后赋值,Awake 里面用的还是初始值,Start里面会受到影响。 也就是Awake里面加载UI组件,start订阅事件,这样保证就算是事件被触发了,事件里面用到的数据也是最新的
    }
    #endregion
}

  1. 游戏对象上将挂载的组件,含 2 个字段,一个值类型,一个引用类型。
using UnityEngine;
public class TestChangeFieldValueAfterResourceLoad : MonoBehaviour
{
    public string AA = "初始值";
    public TestRefrenceField BB;
    private void Awake()
    {
        Debug.Log("Awake" + AA);
        BB = new TestRefrenceField()
        {
            BB="Inside and Awake"
        };
        Debug.Log(BB.BB);
    }
    void Start()
    {
        Debug.Log("Start" + AA);
        Debug.Log(BB.BB);
    }
}
public class TestRefrenceField
{
    public string BB = "AOE";
}
  1. 触发测试的方法,输出如下:


    Debug输出

经验总结

  1. 常识性的结论:

    • Resource.Load 是将 Prefab 二进制文件 通过实例化方式加载到内存,尽管他们是对象了 ,但不会渲染出也不会执行生命周期函数。仅当使用 GameObject.Instantate 实例化后生命周期函数才开始运转。
    • 值类型和可序列化的引用类型,将会预先写入 Prefab 二进制内。所以 Resource.Load 出来是存在默认值的。
    • 常规的引用类型的字段,没有数据写入 Prefab 中,所以加载到内存时 该字段指向 null 。
  2. 本实验的结论:

    • 尝试在 Resource.Load 后对 string 类型的字段赋值,发现:
      a. 此修改对 Instantate 实例化的游戏对象有效。
      b. 此修改对原 Prefab 文件数据产生修改 ,Editor 模式下直接就保存在预制体中了,Runtime 则仅在内存中且对本次启动全局有效 ,软件重启数据恢复。
    • 尝试在 Resource.Load 后对 引用类型 的字段赋值,发现:
      a. 此修改对 Load 在内存的数据有效
      b. 此修改对 Instantate 动作无效,即:实例化的时候 该字段依旧为 null 。
    • 在 GameObject.Instantate 后对任意类型字段赋值,此修改对 Awake 函数中的引用(应用)无效,即保持默认值。
    • 在 GameObject.Instantate 后对任意类型字段赋值,此修改对 Start 函数中的引用(应用)开始产生影响。
    • 综上:对 Instantate 得到的游戏对象字段进行修改,务必在 Start 函数再对传入的数据进行处理,否则多半出现明明赋值了还报 null的情况
  3. 一直半解最可怕了,毕竟生命周期和脚本执行顺序混乱就会异常不断。要不Unity 整个 Execution order 干嘛?

写到最后

发现 Execution Order 设置的便捷方式,用的人少知道快捷方式的就更少了吧,没必要单独成文,强插一波吧:


  • 添加脚本?拖~
  • 移除脚本?拖~
  • 调整执行顺序?还是拖。
  • 还有这样的属性也不知好不好用?


相关文章

  • GameObject.Instantate前后对字段赋值在生命周

    有些问题不去试试,不清不楚不方便搞事情,就像笔者今天做的这个备忘一样。 写在前面 这个笔记就是记录一个测试结果。 ...

  • Java 类的初始化

    在 Java 代码中,如果要初始化一个静态字段,可以在声明时直接赋值,也可以在静态代码块中对其赋值。如果直接赋值的...

  • mysql表管理

    管理表结构:1.插入 添加一条记录,给所有字段赋值 添加一条记录,指定字段赋值ps:字段值要与字段类型相匹配 字符...

  • @Value 和 @PropertySource 注解

    @Value 注解赋值 直接给成员变量赋值 Person 类 在 Person 类中,为 name 字段和 age...

  • 这个readonly干什么用呢

    readonly用于字段,意思是:字段只能在初始化时候赋值,在随后的使用中,字段的值不能再改变。举个列子

  • lua protobuf repeated字段赋值

    lua使用protobuf发送列表结构,对repeated字段进行赋值会报错,报错内容为“Assignment n...

  • BeanUtils.copyProperties 选择性赋值字段

    BeanUtils.copyProperties 在字段赋值上有强大的功能,如果有两个的类,如果需要将相同的字段赋...

  • 去掉数据库中字段值前后空格

    在使用excel导入数据的时候由于没有对插入字段使用trim(),前台表单新增的时候没有去掉空格(或者没有对前后空...

  • IJKPlayer添加自定义Option

    1 在FFPlay中添加字段注意的是在opensles这个字段之后添加, 原因是配置是通过偏移位来赋值 2 在ff...

  • Redis基本命令(二)--散列类型

    Redis基本命令(二)--散列类型 1.赋值与取值 2.判断字段是否存在 3.当字段不存在时赋值[与hset的区...

网友评论

    本文标题:GameObject.Instantate前后对字段赋值在生命周

    本文链接:https://www.haomeiwen.com/subject/xggqxqtx.html