从顶层应用【探索卡片的付费弹窗】浅谈数据

最近在一家上市公司的游戏部实习。组里用的T-Engine,此后准备开一个专栏记录一下,自己从框架的角度,看待游戏项目中(自己涉及到的模块)部分的编写。
大概会从具体例子from top to bottom的流程浅浅地聊一下框架。
为什么选择from top to bottom?
我思考了好几个书写的流程,因为商业框架的继承关系非常复杂,大量的交叉引用,如果直接从底层开始讲,那牵扯的内容估计够大几十页,那显然是不合理的,也不符合用户观感。
出于保护,我把项目中的美术资源全部打码了。

数据部分

看前须知:
Unity基础篇:Serializable总结与深入研究
彻底搞明白Unity-async-task特性

从顶层应用【探索卡片的付费弹窗】浅谈数据

image.png
ExploreWidgetUI预制件
image.png
它的核心是一个Scroll View,支持横向滑动,涉及一些热更的数据。


namespace GameLogic.UI
{
    [Window(UILayer.UI)]
    public class ExploreWidgetUI : UIWidget
    {
        #region 脚本工具生成的代码
        private GameObject m_goCloseBtn;
        private GameObject m_goContent;
        public override void ScriptGenerator()
        {
            m_goCloseBtn = FindChild("m_goCloseBtn").gameObject;
            m_goContent = FindChild("Panel/ScrollView/ViewPort/m_goContent").gameObject;
        }
        #endregion

        public override void OnCreate()
        {
            base.OnCreate();
            m_goCloseBtn.GetComponent<Button>().onClick.AddListener(() =>
            {
                //关闭弹窗
                DestroyUIWidget(this);
            });

            //动态加载资源卡片
            LoadImageContentExploreLevel();
        }

        #region 事件
        /// <summary>
        /// 动态加载探索卡片
        /// </summary>
        private void LoadImageContentExploreLevel()
        {

            List<BookGallerySystem.RecommendBookData> recommendPictureLists = BookGallerySystem.Instance.LoadRecommendPicture();

            foreach (BookGallerySystem.RecommendBookData item in recommendPictureLists)
            {
                //实例化对象
                Item_RecommendPicture item_RecommendPicture = CreateWidgetByPath<Item_RecommendPicture>
                    (m_goContent.transform, "Item_RecommendPicture");
                //更新
                item_RecommendPicture.Update(item);
            }
           

        }
        #endregion
    }
}



ExploreWidgetUI 是一个Widget组件,定位于一种小窗口组件。继承UIWidget比较合适。
下面是探索卡片RecommendBookData的获取

   #region Explore

        /// <summary>
        /// 推荐书籍数据
        /// </summary>
        public class RecommendBookData
        {
            public string PictureName;
            public bool IsLocked;
        }

        /// <summary>
        /// 返回配置表中需更改字段
        /// </summary>
        /// <returns></returns>
        public List<RecommendBookData> LoadRecommendPicture()
        {
            var recommendBookList = new List<RecommendBookData>();
            foreach (var bookId in ControlData.data[0].recommendedBooks)
            {
                var bookData = FindBookData(bookId);
                if (bookData == null) continue;

                recommendBookList.Add(new RecommendBookData
                {
                    PictureName = bookData.recommendPicture,
                    IsLocked = bookData.unlockBookType == 1 // 1: locked, 0: unlocked
                });
            }

            return recommendBookList;
        }

        #endregion

第19行遍历的ControlData.data[0]是配置表中每个卡片的结构,比如我里需要加载卡片的img,需要根据唯一主键ID 访问对应的recommendPicture,拿到sprite2D and UI 图片然后替换原位置image对象的Sourge Image即可
image.png
这些美术资源是存放在服务器里的,通过AB加载到本地,与策划提供的配置表一一绑定,
本地定义了存储的数据结构


namespace GameData.Game
{
    [Serializable]
    public class ControlData : GameBaseData<ControlSubData>
    {
    }

    [Serializable]
    public class ControlSubData: GameSubBaseData
    {
        // 总控id	控制角色移动速度	推荐书籍规则
        //     id	characterSpeed	recommendedBooks
        // int32	int32	[]int32
        public override int DataId => id;
        public int id; //总控id
        public int characterSpeed; //控制角色移动速度
        public int[] recommendedBooks; //推荐书籍规则
        public int[] mainBooks; //主界面书籍
        public float[] coefficientTime; //系数时间
        public float[] coefficientScore; //系数分数
    }

    public class Control : ConfigBase
    {
        public override DataType GetDataType()
        {
            return DataType.Control;
        }

        protected override UniTask<GameBaseData> UnserializeData()
        {
            return Unserialize<ControlData, ControlSubData>(nameof(Control));
        }
    }
}

怎样处理接受到的服务器数据呢?
反序列化。因为接收到的服务器中的二进制流。
上述方法中的UnserializeData方法中的返回值是一个GameBaseData(来源于框架定义的基类)泛型的UniTask.
下面给出Unserialize<,>()的方法

 protected static async UniTask<GameBaseData> Unserialize<TData, TSubData>(string typeName) where TData : GameBaseData<TSubData>, new()
            where TSubData : GameSubBaseData
        {
            var jsonData = AssetsLoadManager.LoadAssets<TextAsset>(char.ToLower(typeName[0]) + typeName[1..]);
            return new TData
            {
                data = JSONSerializer.Unserialize<TSubData[]>(jsonData.text)
            };
        }

这里是异步的形式,以纯文本的形式AB加载了TextAsset类型的数据,拿到了json串
然后解析json,反序列化封装成对象,构建上面用到的ControlData类,这是总控表,在顶层需要用到的时候,实例化类,使用就可以了。
下面是json序列化和反序列化的方法

namespace PandaScript.Helpers
{
    public class JSONSerializer
    {
        public static string Serialize<T>(T data) where T : class
        {
            string serializedData = null;
            try
            {
                serializedData = JsonConvert.SerializeObject(data, Formatting.Indented, new JsonSerializerSettings
                {
                    TypeNameHandling = TypeNameHandling.Auto,
                    MissingMemberHandling = MissingMemberHandling.Ignore
                });
            }
            catch (Exception e)
            {
                Debug.LogError(string.Format("An error happened while serializing the object : {0}\n{1}", e.Message,
                    e.StackTrace));
            }

            return serializedData;
        }

        public static T Unserialize<T>(string serializedData) where T : class
        {
            var unserializedData = default(T);

            try
            {
                unserializedData = JsonConvert.DeserializeObject<T>(serializedData, new JsonSerializerSettings
                {
                    TypeNameHandling = TypeNameHandling.Auto,
                    MissingMemberHandling = MissingMemberHandling.Ignore
                });
            }
            catch (Exception e)
            {
                Debug.LogError(string.Format("An error happened while serializing the object : {0}\n{1}", e.Message,
                    e.StackTrace));
            }

            return unserializedData;
        }
    }
}

JsonConvert.DeserializeObject()方法对T类型的序列化数据解析,返回T类型的非序列化数据。
这样,我们等于是通过读取服务器中的Byte流,反序列化还原成了类似下面(策划提供)的json文件,再与本地的数据结构关联,最终就到了我需要用到ControlData.data列表,拿到了相应美术资源的地址。
image.png
策划人员只需要通过.excel表格提出资源的配置,关联程序部的工作。详见另一篇从配置表角度浅谈游戏公司的资源管理

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值