【问题标题】:Serialize a class that is derived from a non serializable class序列化从不可序列化类派生的类
【发布时间】:2016-06-02 15:26:41
【问题描述】:

我在 Unity 中遇到序列化问题(使用 C#)。

我有以下类(箭头表示继承):

Vehicle(摘要)Car(摘要)Sedan

Vehicle(摘要)MotorBike

车辆类继承自MonoBehavior

我有一些游戏对象(预制件),我附加了分类。我只使用非抽象类(即MotorBikeSedan)。

我的问题是这样的:

我想序列化存储在这些类中的数据,以便能够保存/加载。 (我为此使用BinaryFormatter。)问题是,MonoBehavior 不可序列化。

我想要的只是序列化车辆类中的数据,并(在加载数据时)将其传递给我的 Vehicle Factory 类,以使用反序列化的数据重新实例化预制件。所以,我对 MonoBehavior 部分中存储的内容并不真正感兴趣。

到目前为止我所做的尝试:

使用单独的数据类,但这会导致各种problems,我需要为我的每个车辆类创建一个子数据类。而且我需要将 Vehicle 类设为 Generic,以指示它需要使用哪个 Data 类,这将要求我在使用 Vehicle 类型的每个地方都使用 Generic Type。

另外,我尝试为 MonoBehaviour 创建一个 SerializationSurrogate,但这没有成功,因为还有许多其他类型需要代理。而且由于我对 MonoBehaviour 不感兴趣,而只对 Vehicle 类及其子类感兴趣,因此这似乎太复杂而无法尝试。

所以,我的问题是:有人知道如何处理这个问题吗?

【问题讨论】:

  • 使用XmlSerializer,它不需要为类赋予serializable属性。
  • 序列化在 Unity 中基本上不起作用。我会忘记它。没有你真正需要它的真实游戏场景。忘记它并继续前进。
  • 程序员已经完美解释了情况。
  • 您似乎属于“经验丰富的程序员,正在尝试 Unity”。从某种意义上说,你所做的是完全错误的。 Unity 中没有“汽车”这样的东西,而且永远不会有。 Unity 难以置信地不是 OO。 Unity 更像是使用 Photoshop 而不是编程。也许读这个...stackoverflow.com/a/37243035/294884
  • 确实如此。在我的工作室里,非常优秀的 c++ 程序员开始在我的团队中作为 Unity3D 开发人员工作——我只能说,即使他的代码在某种程度上很好(你会看到他良好的编程技能),但完全不是“Unity3D”的编码方式。到处使用接口、部分类定义等,使 unity3d 项目代码非常晦涩。

标签: c# oop serialization unity3d


【解决方案1】:

我总是发现很难从继承的类中保存数据。您的数据类不应继承或派生自任何东西。另一个类中的一个类完全没问题。这里的目标是为每辆车设置两个类。一种从MonoBehaviour(Object) 派生,另一种不是(data)。

您使用 Object 类对车辆执行操作,例如移动、碰撞决策等。您使用 data 类来存储有关每辆汽车/车辆的信息。

下面的例子用 Sedan 来说明我在说什么:

SedanObject.cs 附加到轿车预制件。

class SedanObject : MonoBehaviour
{
    float fuel;
    public void setFuel(float fuel)
    {
        this.fuel = fuel;
    }

    public float getFuel(float fuel)
    {
        return this.fuel;
    }

    void Start()
    {

    }

    void Update()
    {

    }
}

轿车的数据类:

[Serializable]
public class MotorBike
{

}

[Serializable]
public class Sedan
{
    public float fuel;
}

[Serializable]
public class Cars
{
    public List<Sedan> sedan;

    public Cars()
    {
        sedan = new List<Sedan>();
    }
}

[Serializable]
public class Vehicles
{
    public Cars cars;
    public MotorBike motorBike;

    public Vehicles()
    {
        cars = new Cars();
        motorBike = new MotorBike();
    }
}

在游戏结束时,保存车辆设置。 Vehicles 中的每个类/脚本都将被保存。

//Save on Exit
Vehicles vehicles = new Vehicles();
string vehicleJson = JsonUtility.ToJson(vehicles);
PlayerPrefs.SetString("vehicles", vehicleJson);
PlayerPrefs.Save();

游戏开始时,从磁盘加载车辆信息,然后根据列表中的轿车数量实例化 Sedan Prefab。

//Load on Startup
string loadVehicleJson = PlayerPrefs.GetString("vehicles");
Vehicles loadVehicles;
loadVehicles = JsonUtility.FromJson<Vehicles>(loadVehicleJson);

//Process and instantiate sedan based on the loaded data amount/count
for (int i = 0; i < vehicles.cars.sedan.Count; i++)
{
    GameObject tempObjt = Instantiate(sedanPrefab);
    SedanObject sd = tempObjt.GetComponent<SedanObject>();

    //Send loaded settings to each vehicle script 
    sd.setFuel(vehicles.cars.sedan[i].fuel);
}

如果您以后想添加更多轿车:

//Create 3 Sedans
vehicles.cars.sedan.Add(new Sedan());
vehicles.cars.sedan.Add(new Sedan());
vehicles.cars.sedan.Add(new Sedan());

这只是一个基本的解决方案,可以扩展。您可以在 for 循环期间将每个轿车数据脚本的实例传递给 SedanObject,就像我将加载的燃料传递给每个实例一样。通过传递每个实例,可以在运行时从SedanObject 脚本的每个实例修改来自数据脚本的信息。这也可以通过xml 完成。

【讨论】:

  • 感谢您的回复。我基本上已经尝试过这种方法。问题是,我真的需要 Data 类从某些东西继承。我做了一个例子here。当我想存储Sedan 时,我也需要来自基类的all 数据。此外,您这样做的方式会导致重复代码,对吗?我的意思是,您在 SedanObject 和 SedanData 类中都有一个燃料属性。这对于一个属性来说无关紧要,但是当你拥有很多属性时会很烦人。
  • 您好,用户,是的,您必须复制一些代码。所以呢?是的,您的数据类也可以继承。 (有点并行。)
猜你喜欢
  • 2012-05-25
  • 2011-01-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-05-25
相关资源
最近更新 更多