You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Unity中INetworkSerializable序列化GameObject报错:需为非可空值类型

Unity Netcode序列化GameObject的问题解决

问题代码

自定义序列化结构体

public struct MyStruct : INetworkSerializable{
    public static GameObject OBJ1 = GameObject.Find("Obj1");
    public static GameObject OBJ2 = GameObject.Find("Obj2");
    public static GameObject OBJ3 = GameObject.Find("Obj3");

    public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
    {
        serializer.SerializeValue(ref OBJ1);
        serializer.SerializeValue(ref OBJ2);
        serializer.SerializeValue(ref OBJ3);
    }
}

Start函数中的调用代码

string DoNotDelete = PlayerPrefs.GetString("ActiveObj");
MyStruct Struct = new MyStruct();
{
    if (Struct.OBJ1.name != DoNotDelete)
    {
        DestroyServerRpc(Struct.OBJ1);
    }
}

报错信息

The type 'GameObject' must be a non-nullable value type, along with all fields at any level of nesting, in order to use it as parameter 'T' in the generic type or method BufferSerializer<T>.SerializeValue<T>(ref T, FastBufferWriter.ForPrimitives)


核心原理讲解

首先明确两个关键概念:

  1. 值类型 vs 引用类型

    • 值类型(比如int、bool、自定义struct)直接存储数据本身,默认不可为空;
    • 引用类型(比如GameObject、string、class)存储的是指向内存对象的地址,本身可以为空。
      你代码里的GameObject是引用类型,完全不符合SerializeValue要求的「非可空值类型」条件,这就是报错的根本原因。
  2. Netcode序列化的限制
    Netcode的SerializeValue只能处理基础值类型和自定义可序列化值类型结构体,不能直接序列化引用类型对象——因为客户端和服务器的内存地址完全独立,传递对象地址没有实际意义。

另外你代码还有两个额外问题:

  • OBJ1/OBJ2/OBJ3是static静态字段,不属于结构体实例,序列化静态字段完全无效;而且你在Start里访问Struct.OBJ1本质是访问全局静态变量,和创建的Struct实例无关;
  • GameObject.Find在结构体初始化时调用风险极高,可能场景未加载完成导致返回null。

修复方案

Netcode中同步GameObject引用,正确做法是用NetworkObjectReference或同步NetworkObjectId:

方法1:使用NetworkObjectReference(推荐)

public struct MyStruct : INetworkSerializable
{
    // 用Netcode专门的类型存储对象引用
    public NetworkObjectReference obj1Ref;
    public NetworkObjectReference obj2Ref;
    public NetworkObjectReference obj3Ref;

    // 单独做初始化,避免结构体初始化时的查找风险
    public void Initialize()
    {
        obj1Ref = GameObject.Find("Obj1").GetComponent<NetworkObject>();
        obj2Ref = GameObject.Find("Obj2").GetComponent<NetworkObject>();
        obj3Ref = GameObject.Find("Obj3").GetComponent<NetworkObject>();
    }

    public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
    {
        // 序列化NetworkObjectReference,符合Netcode要求
        serializer.SerializeValue(ref obj1Ref);
        serializer.SerializeValue(ref obj2Ref);
        serializer.SerializeValue(ref obj3Ref);
    }

    // 封装获取GameObject的方法
    public GameObject GetObj1()
    {
        if (obj1Ref.TryGet(out NetworkObject netObj))
        {
            return netObj.gameObject;
        }
        return null;
    }

    // 同理实现GetObj2、GetObj3方法
}

修改Start函数调用

string DoNotDelete = PlayerPrefs.GetString("ActiveObj");
MyStruct myStruct = new MyStruct();
myStruct.Initialize(); // 先初始化对象引用

GameObject obj1 = myStruct.GetObj1();
if (obj1 != null && obj1.name != DoNotDelete)
{
    DestroyServerRpc(obj1);
}

方法2:手动同步NetworkObjectId

如果不想用NetworkObjectReference,可以同步对象的NetworkObjectId(ulong值类型,符合序列化要求):

public struct MyStruct : INetworkSerializable
{
    public ulong obj1Id;
    public ulong obj2Id;
    public ulong obj3Id;

    public void Initialize()
    {
        obj1Id = GameObject.Find("Obj1").GetComponent<NetworkObject>().NetworkObjectId;
        obj2Id = GameObject.Find("Obj2").GetComponent<NetworkObject>().NetworkObjectId;
        obj3Id = GameObject.Find("Obj3").GetComponent<NetworkObject>().NetworkObjectId;
    }

    public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
    {
        serializer.SerializeValue(ref obj1Id);
        serializer.SerializeValue(ref obj2Id);
        serializer.SerializeValue(ref obj3Id);
    }

    public GameObject GetObj1()
    {
        if (NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(obj1Id, out NetworkObject netObj))
        {
            return netObj.gameObject;
        }
        return null;
    }
}

内容的提问来源于stack exchange,提问作者Billibambessou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 04:50:34