• [cb]ScriptableObject 序列化


    ScriptableObject

           ScriptableObject是一个类,它允许你存储大量用于共享的数据独立脚本实例,不要迷惑这个类同样可以叫做 SerializableObject,可以理解成是一个Unity串行化工具。这是一个编辑器类并且你可以在Inspector面板中编辑数据。例如:如果你有一个存储了一百万数据的 int[],这个数组占用4MB内存,放在Prefab上,那么当你每次实例化Prefab,你都会得到这个数组的一个副本。如果你实例化10个这个Prefab,那就会占用40MB内存。

    可序列化的类型

    Unity的serializes(序列化)支持所有原生的类型,也支持strings,arrays,lists还有Unity的Vector3等都支持,而且还支持自定义的类,但需要有一个串行的属性。

    使用情景

    预期使用情况,使用ScriptableObject是减少内存使用量,避免Values的副本。但是你也可以用它来定义可插拨的数据集。这方面的一个例子是:想像RPG游戏中的NPC商店,你可以创建自定义ShopContens ScriptableObject,每个资产定义了一组可用于购买物品。在这样一个场景,游戏中有三个区域,每个区域都可以提供不同层级的项目。你的店铺脚本将引用ShopContents对象,定义哪些项目可供选择。

    Tips

    当在检查ScriptableObject引用时,你可以在Inspector双击这个参考字段。

    你可以创建一个自定义的Editor来查看不同的类似在Inspector,以帮助你管理它所表示的数据。

    游戏关卡数据序列化

    策划需求

    一个游戏中的配置表数据,这些数据一般都是由策划在Excel等工具上配置,要运用到游戏中时,一般需要做一个转换,比如类似转换。这时可以使用ScriptableObject,将数据预先处理成程序需要访问的数据结构,存储在ScriptableObject中,然后打包成一个外部文件,这样在游戏运行的时候就不用做解析和组装了,这个功能对大批量的公用数据尤其有用!!

    思路分析

    策划在Art工程拼接好关卡信息之后,客户端根据关卡的中元素的位置,大小等信息生成出关卡,这中间有一个存储关卡信息的过程。我们的做法是把关卡的信息存储在ScriptableObject上,然后在Editor里,把当前关卡信息存储在Product目录下做为一个文件。Client直接读取这个MapObject文件

    MapSetting.cs

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    
    //地图信息打包成外部文件,供Client读取
    public class CMapSetting : ScriptableObject
    {
        public List<string> TexturesDependencies;//依赖的贴图
        public string MapObjectPath;//MapRoot
    
        public List<CLevelBattleSetting> Battles;//战役信息
    }

    导出关卡数据代码

        public void ExportCurrentScene()
        {
            SceneName = EditorApplication.currentScene.Substring(EditorApplication.currentScene.LastIndexOf('/') + 1);
            SceneName = SceneName.Substring(0, SceneName.LastIndexOf('.'));
            string exportPath = string.Format("Scene/{0}{1}", SceneName, GameDef.ASSET_BUNDLE_FILE_EXT);
    
            string mapObjectPath = string.Format("Scene/{0}_MapObject{1}", SceneName, GameDef.ASSET_BUNDLE_FILE_EXT);
    
            CSimBattle[] battles = GameObject.FindObjectsOfType<CSimBattle>();//获取所有的Battle
    
            List<CSimBattle> battleList = new List<CSimBattle>(battles);
            battleList.Sort((CSimBattle x, CSimBattle y) =>
            {
                return x.transform.position.y.CompareTo(y.transform.position.y);
            });//根据Battle的Y进行排序
    
            CSimActor[] actors = GameObject.FindObjectsOfType<CSimActor>();//获取所有的Actor
            List<CSimActor> actorList = new List<CSimActor>(actors);
            int count = 0;//测试一个Battle中多少只怪
            List<CLevelBattleSetting> LevelBattleSettings = new List<CLevelBattleSetting>();//有多少关卡
    
            for (int b = 0; b < battleList.Count; b++)//遍历Battle
            {
                CSimBattle simBattle = battleList[b];
                CLevelBattleSetting levelBatSetting = new CLevelBattleSetting();//创建一个新的BattleSetting实例
                levelBatSetting.MapActorSettings = new List<CMapActorSetting>();//Battle中的Actor设置信息
                levelBatSetting.Num = simBattle.KillNum;
                levelBatSetting.Time = simBattle.BattleTime;
                levelBatSetting.StoryOnStart = simBattle.StoryOnStart;
                levelBatSetting.StoryOnEnd = simBattle.StoryOnEnd;
                levelBatSetting.CurPosition = simBattle.transform.position;
                //CBase.Log("CSimBattle.CurPosition:{0}", levelBatSetting.CurPosition);
    
                float battlePosY = simBattle.transform.position.y;//Battle的Y值
                for (int a = (actorList.Count - 1); a >= 0; a--)//遍历怪
                {
                    float actorPosY = actorList[a].transform.position.y;//Actor的Y值
                    if (actorPosY <= battlePosY)//判断这个Actor是否在这个Battle内
                    {
                        CMapActorSetting actorSetting = new CMapActorSetting();
                        CSimActor simActor = actorList[a];
                        actorSetting.NpcId = simActor.NPC编号;
                        actorSetting.NpcLevel = simActor.NPC等级;
                        actorSetting.NpcPosition = simActor.transform.position;
                        actorSetting.IsEnemy = simActor.是否敌人;
    
                        levelBatSetting.MapActorSettings.Add(actorSetting);//把怪添加到关卡中
                        actorList.Remove(simActor);//移除已经添加的Actor
                        count += 1;
                    }
                }
    
                LevelBattleSettings.Add(levelBatSetting);//把battle添加进关卡地图中
                CBase.Log("Battle :{0}  有怪物 {1} 只" ,b, count);//打印一个Battle中有多少怪
                count = 0;
            }
            //CBase.Log("当前关卡共有 {1} 个Battle", LevelBattleSettings.Count);
    
            GameObject mapRoot = GameObject.Find("MapRoot");
            if (mapRoot != null)
            {
                List<string> textureList = new List<string>();//存放打包好图片的路径
                Renderer[] renderers = mapRoot.GetComponentsInChildren<Renderer>();
                foreach (Renderer child in renderers)
                {
                    Texture _texture = child.sharedMaterial.mainTexture;
                    string _path = AssetDatabase.GetAssetPath(_texture);
                    _path = XBuildTools.GetUniquepath(_path);
                    if (!textureList.Contains(_path))
                    {
                        textureList.Add(_path);
                        XBuildTools.PushAssetBundle(_texture, string.Format("Textures/{0}{1}", _path, GameDef.ASSET_BUNDLE_FILE_EXT));
                        CBase.Log("Texture导出成功! =>{0}", _path);
                    }
                }
    
                XBuildTools.PushAssetBundle(mapRoot, mapObjectPath);//打包 mapRoot
                Debug.Log("地图导出成功!" + SceneName);
                XBuildTools.PopAssetBundle();
                //XBuildTools.PopAllAssetBundle();
    
                CMapSetting mapSetting = ScriptableObject.CreateInstance<CMapSetting>();
                mapSetting.TexturesDependencies = textureList;
                mapSetting.MapObjectPath = mapObjectPath;
                mapSetting.Battles = LevelBattleSettings;
                XBuildTools.BuildScriptableObject(mapSetting, exportPath);//序列化 MapSetting的位置啊,路径信息。
            }
        }

    打包出的关卡文件

    image

    文档资料

    Unity Manual:http://docs.unity3d.com/Manual/class-ScriptableObject.html

    Scripting API:http://docs.unity3d.com/ScriptReference/ScriptableObject.html

  • 相关阅读:
    sql查询
    PHP常用的设计模式
    PHP内存管理和垃圾回收机制
    记一次面试
    获取py文件函数名及动态调用
    正确解决 mysql 导出文件 分隔符 问题
    解决ValueError: cannot convert float NaN to integer
    Python ---接口返回值中文编码问题
    pandas python 读取大文件
    【neo4J】后台关闭后,前端还能打开视图
  • 原文地址:https://www.cnblogs.com/zhaoqingqing/p/3775069.html
Copyright © 2020-2023  润新知