【GameFramework框架内置模块】3、数据表(Data Table)

推荐阅读

  • CSDN主页
  • GitHub开源地址
  • Unity3D插件分享
  • 简书地址

大家好,我是佛系工程师☆恬静的小魔龙☆,不定时更新Unity开发技巧,觉得有用记得一键三连哦。

一、前言

【GameFramework框架】系列教程目录:
https://blog.csdn.net/q764424567/article/details/135831551

二、正文

2-1、简介

DataTable数据表是一个表的数据集合,可以理解为DataRow的字典集合比如Dictionary<int,T> m_DataRow

DataTable数据表是数据集合的访问查询类,主要操作有数据的增删改查方法(虽然框架提供了删除的接口,但是一般是不需要进行修改或者删除的,读取就好了)。

框架推荐我们使用DataTable数据表来设置初始数据,比如玩家初始生命值、初始蓝量、初始防御力等,下面就来看一下如何使用吧。

2-2、使用说明

2-2-1、准备数据表及生成实体类

以StarForce项目为例,数据表存放在这个位置:
在这里插入图片描述
每一个数据表都对应一个C#,这个C#对应表里面的字段,这样才能使用里面的信息,比如Music数据表
在这里插入图片描述
对应的C#类在这个目录下:
在这里插入图片描述
DRMusic.cs

//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------
// 此文件由工具自动生成,请勿直接修改。
// 生成时间:2021-06-16 21:54:35.591
//------------------------------------------------------------

using GameFramework;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using UnityEngine;
using UnityGameFramework.Runtime;

namespace StarForce
{
    /// <summary>
    /// 音乐配置表。
    /// </summary>
    public class DRMusic : DataRowBase
    {
        private int m_Id = 0;

        /// <summary>
        /// 获取音乐编号。
        /// </summary>
        public override int Id
        {
            get
            {
                return m_Id;
            }
        }

        /// <summary>
        /// 获取资源名称。
        /// </summary>
        public string AssetName
        {
            get;
            private set;
        }

        public override bool ParseDataRow(string dataRowString, object userData)
        {
            string[] columnStrings = dataRowString.Split(DataTableExtension.DataSplitSeparators);
            for (int i = 0; i < columnStrings.Length; i++)
            {
                columnStrings[i] = columnStrings[i].Trim(DataTableExtension.DataTrimSeparators);
            }

            int index = 0;
            index++;
            m_Id = int.Parse(columnStrings[index++]);
            index++;
            AssetName = columnStrings[index++];

            GeneratePropertyArray();
            return true;
        }

        public override bool ParseDataRow(byte[] dataRowBytes, int startIndex, int length, object userData)
        {
            using (MemoryStream memoryStream = new MemoryStream(dataRowBytes, startIndex, length, false))
            {
                using (BinaryReader binaryReader = new BinaryReader(memoryStream, Encoding.UTF8))
                {
                    m_Id = binaryReader.Read7BitEncodedInt32();
                    AssetName = binaryReader.ReadString();
                }
            }

            GeneratePropertyArray();
            return true;
        }

        private void GeneratePropertyArray()
        {

        }
    }
}

大家注意,这个配置表的实体类DRXXX类是工具生成的,不需要手动修改的,如果需要重新生成,可以点击菜单的Star Force→ Generator DataTables
在这里插入图片描述
DataTable数据表读取数据是分成一行一行的,每一行就是一个DataRow,在代码中对应的其实就是一个数据对象,index++是指同一行数据列数增加,一一对应了数据类型。

OK,数据表准备好之后,我们就在框架中加载配置。

2-2-2、ProcedurePreloa预加载

新建脚本,命名为Test04.cs,编辑代码:

using StarForce;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using UnityEngine;
using UnityGameFramework.Runtime;

public class Test04 : MonoBehaviour
{
    DataTableComponent DataTable;
    string[] DataTableNames;

    void Start()
    {
        DataTable = UnityGameFramework.Runtime.GameEntry.GetComponent<DataTableComponent>();
        DataTableNames = new string[2] { "Scene", "Music" };
        // 预加载 data tables数据表
        foreach (string dataTableName in DataTableNames)
        {
            LoadDataTable(dataTableName);
        }
    }

    /// <summary>
    /// 加载表数据
    /// </summary>
    /// <param name="dataTableName"></param>
    private void LoadDataTable(string dataTableName)
    {
        string dataTableAssetName = AssetUtility.GetDataTableAsset(dataTableName, false);
        // 表名、表名资源路径、用户自定义数据
        DataTable.LoadDataTable(dataTableName, dataTableAssetName, this);
    }

    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.W))
        {
            QueryData();
        }
    }

    /// <summary>
    /// 查询表数据
    /// </summary>
    private void QueryData()
    {
        //获取指定表数据列表
        var drScene = DataTable.GetDataTable<DRScene>();

        //根据行号查找数据
        DRScene scene1 = drScene.GetDataRow(1);
        Debug.Log("获取第一行数据的ID值:"+scene1.Id);

        //根据指定条件,比如按id查找,按名字查找
        DRScene scene2 = drScene.GetDataRow(x => x.Id == 1);
        DRScene scene3 = drScene.GetDataRow(x => x.AssetName == "Menu");
        Debug.Log("获取id等于1的场景名:"+scene2.AssetName);
        Debug.Log("获取场景名等于Menu的id值:" + scene3.Id);

        //根据条件查找多条数据
        DRScene[] scene4 = drScene.GetDataRows(x => x.Id > 0);
        for (int i = 0; i < scene4.Length; i++)
        {
            Debug.Log("获取id大于0的背景音乐编号:" + scene4[i].BackgroundMusicId);
        }
    }
}

运行结果:
在这里插入图片描述

对应的Scene.txt数据表:
在这里插入图片描述
PS:这里补充说明一下,加载表数据用了StarForce项目的拓展函数,方便加载,所以需要引用StarForce命名空间,推荐大家下载StarForce项目来学习这个框架。

2-3、实现及代码分析

接下来,就分析一下这个数据表DataTable是如何加载及代码分析。

首先,用流程图说明一下:

Created with Raphaël 2.3.0 开始 创建数据节点表 编写数据表对应的cs文件 加载数据表 使用数据表

(1)第一步,创建数据节点表

数据表需要严格按照它这个格式来,行是字段,列是每条数据:
在这里插入图片描述
这样看,不太清晰,我们用Excel看一下:
在这里插入图片描述
说到这,有一点想要说明一下,因为这些数据表一般是策划来修改,然后导入到我们项目中的。

而策划一般使用Excel表,而程序需要csv、xml、Json、txt格式,所以就需要一个Excel导出这个文件的工具,这个工具我们后续也会进行拓展开发,框架没有带这些,但是框架提供了接口,也是很方便的。

(2)第二步,编写数据表对应的CS文件
这个是工具自动生成的,点击菜单的Star Force→Generate DataTables,来看一下代码如何实现的:
在这里插入图片描述
DataTableGenerator.cs脚本,获取到表里面的行的数据保存到字符序列中,然后保存到文件中:
在这里插入图片描述

(3)第三步,加载数据表

加载数据表,就是用的StarForce项目的拓展函数:

//------------------------------------------------------------
// Game Framework
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
// Homepage: https://gameframework.cn/
// Feedback: mailto:ellan@gameframework.cn
//------------------------------------------------------------

using GameFramework.DataTable;
using System;
using UnityEngine;
using UnityGameFramework.Runtime;

namespace StarForce
{
    public static class DataTableExtension
    {
        private const string DataRowClassPrefixName = "StarForce.DR";
        internal static readonly char[] DataSplitSeparators = new char[] { '\t' };
        internal static readonly char[] DataTrimSeparators = new char[] { '\"' };

        public static void LoadDataTable(this DataTableComponent dataTableComponent, string dataTableName, string dataTableAssetName, object userData)
        {
            if (string.IsNullOrEmpty(dataTableName))
            {
                Log.Warning("Data table name is invalid.");
                return;
            }

            string[] splitedNames = dataTableName.Split('_');
            if (splitedNames.Length > 2)
            {
                Log.Warning("Data table name is invalid.");
                return;
            }

            string dataRowClassName = DataRowClassPrefixName + splitedNames[0];
            Type dataRowType = Type.GetType(dataRowClassName);
            if (dataRowType == null)
            {
                Log.Warning("Can not get data row type with class name '{0}'.", dataRowClassName);
                return;
            }

            string name = splitedNames.Length > 1 ? splitedNames[1] : null;
            DataTableBase dataTable = dataTableComponent.CreateDataTable(dataRowType, name);
            dataTable.ReadData(dataTableAssetName, Constant.AssetPriority.DataTableAsset, userData);
        }

        public static Color32 ParseColor32(string value)
        {
            string[] splitedValue = value.Split(',');
            return new Color32(byte.Parse(splitedValue[0]), byte.Parse(splitedValue[1]), byte.Parse(splitedValue[2]), byte.Parse(splitedValue[3]));
        }

        public static Color ParseColor(string value)
        {
            string[] splitedValue = value.Split(',');
            return new Color(float.Parse(splitedValue[0]), float.Parse(splitedValue[1]), float.Parse(splitedValue[2]), float.Parse(splitedValue[3]));
        }

        public static Quaternion ParseQuaternion(string value)
        {
            string[] splitedValue = value.Split(',');
            return new Quaternion(float.Parse(splitedValue[0]), float.Parse(splitedValue[1]), float.Parse(splitedValue[2]), float.Parse(splitedValue[3]));
        }

        public static Rect ParseRect(string value)
        {
            string[] splitedValue = value.Split(',');
            return new Rect(float.Parse(splitedValue[0]), float.Parse(splitedValue[1]), float.Parse(splitedValue[2]), float.Parse(splitedValue[3]));
        }

        public static Vector2 ParseVector2(string value)
        {
            string[] splitedValue = value.Split(',');
            return new Vector2(float.Parse(splitedValue[0]), float.Parse(splitedValue[1]));
        }

        public static Vector3 ParseVector3(string value)
        {
            string[] splitedValue = value.Split(',');
            return new Vector3(float.Parse(splitedValue[0]), float.Parse(splitedValue[1]), float.Parse(splitedValue[2]));
        }

        public static Vector4 ParseVector4(string value)
        {
            string[] splitedValue = value.Split(',');
            return new Vector4(float.Parse(splitedValue[0]), float.Parse(splitedValue[1]), float.Parse(splitedValue[2]), float.Parse(splitedValue[3]));
        }
    }
}

StarForce的拓展类DataTableExtension中定义LoadDataTable(ddataTableName,dataTableAssetName,this)函数通过名字获取资源路径并执行ReadData()函数。

通过DataProvie<DataTableBase>读取并解析数据:

namespace GameFramework.DataTable
{
    private readonly DataProvider<DataTableBase> m_DataProvider;
    public DataTableBase(string name)
    {
        //dataProvider的初始化
        m_DataProvider = new DataProvider<DataTableBase>(this);
    }
    /// 数据表基类。
    public abstract class DataTableBase : IDataProvider<DataTableBase>
    {
        public void ReadData(string dataTableAssetName, int priority, object userData)
        {
            m_DataProvider.ReadData(dataTableAssetName, priority, userData);
        }
    }    
}

通过m_ResourceManager来加载数据,然后通过m_DataProviderHelper加载数据:

/// 配置表属于AssetOnFileSystem,调用ResourceManager资源管理器,执行读取数据。
public void ReadData(string dataAssetName, int priority, object userData)
{
    HasAssetResult result = m_ResourceManager.HasAsset(dataAssetName);
    switch (result)
    {
        case HasAssetResult.AssetOnFileSystem:
            m_ResourceManager.LoadAsset(dataAssetName, priority, m_LoadAssetCallbacks, userData);
            break;
        default:
            throw new GameFrameworkException(Utility.Text.Format("Data asset '{0}' is '{1}'.", dataAssetName, result.ToString()));
    }
}

///加载成功的回调,使用数据辅助器进行读取并解析数据
private void LoadAssetSuccessCallback(string dataAssetName, object dataAsset, float duration, object userData)
{
    if (!m_DataProviderHelper.ReadData(m_Owner, dataAssetName, dataAsset, userData))
    {
        throw GameFrameworkException
    }
}

(4)第四步,使用数据表
使用数据辅助类来读取数据,读取出来txt/bytes流,最后通过数据辅助类来解析数据:

public class DefaultDataTableHelper : DataTableHelperBase
{
    /// 读取数据表。
    public override bool ReadData(DataTableBase dataTable, string dataTableAssetName, object dataTableAsset, object userData)
    {
        TextAsset dataTableTextAsset = dataTableAsset as TextAsset;
        if (dataTableTextAsset != null)
        {
            return dataTable.ParseData(dataTableTextAsset.text, userData);
        }
        return false;
    }
    /// 解析数据表。
    public override bool ParseData(DataTableBase dataTable, string dataTableString, object userData)
    {
        int position = 0;
        string dataRowString = null;
        while ((dataRowString = dataTableString.ReadLine(ref position)) != null)
        {
            if (dataRowString[0] == '#') continue;
			dataTable.AddDataRow(dataRowString, userData)
        }
        return true;
    }
}

每个DR类都有ParseDataRow()函数来解析自己的数据格式,读取完毕,得到一个数据实体对象,保存在数据集合中。

三、后记

如果觉得本篇文章有用别忘了点个关注,关注不迷路,持续分享更多Unity干货文章。


你的点赞就是对博主的支持,有问题记得留言:

博主主页有联系方式。

博主还有跟多宝藏文章等待你的发掘哦:

专栏方向简介
Unity3D开发小游戏小游戏开发教程分享一些使用Unity3D引擎开发的小游戏,分享一些制作小游戏的教程。
Unity3D从入门到进阶入门从自学Unity中获取灵感,总结从零开始学习Unity的路线,有C#和Unity的知识。
Unity3D之UGUIUGUIUnity的UI系统UGUI全解析,从UGUI的基础控件开始讲起,然后将UGUI的原理,UGUI的使用全面教学。
Unity3D之读取数据文件读取使用Unity3D读取txt文档、json文档、xml文档、csv文档、Excel文档。
Unity3D之数据集合数据集合数组集合:数组、List、字典、堆栈、链表等数据集合知识分享。
Unity3D之VR/AR(虚拟仿真)开发虚拟仿真总结博主工作常见的虚拟仿真需求进行案例讲解。
Unity3D之插件插件主要分享在Unity开发中用到的一些插件使用方法,插件介绍等
Unity3D之日常开发日常记录主要是博主日常开发中用到的,用到的方法技巧,开发思路,代码分享等
Unity3D之日常BUG日常记录记录在使用Unity3D编辑器开发项目过程中,遇到的BUG和坑,让后来人可以有些参考。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/409153.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

你要不要搞副业

最近看到了几个网友关于年轻人要不要搞副业的一点讨论&#xff0c;学习到了很多。整理分享如下&#xff1a; plantegg 你要不要搞副业&#xff1f; 最近网上看到很多讨论搞副业和远程工作的&#xff0c;我也说点自己的经验看法 当然这完全是出于个人认知肯定不是完全对的、也…

第十三章 Linux——备份与恢复

第十三章 Linux——备份与恢复 基本介绍安装dump和restore使用dump完成备份dump语法说明dump应用案例1dump应用案例2dump-w查看备份时间文件备份文件或者目录备注 使用restore基本语法基本介绍restore基本语法应用案例1应用案例2应用案例3应用案例4 基本介绍 实体机无法做快照…

wcf 简单实践 数据绑定 数据校验

1.概要 1.1 说明 数据校验&#xff0c;如果数据不合适&#xff0c;有提示。 1.2 要点 class User : IDataErrorInfothis.DataContext user;<Window.Resources><Setter Property"ToolTip" Value"{Binding RelativeSource{RelativeSource Self},Pat…

【电子通识】认识FMEA(失效模式和影响分析)

FMEA是Failure Mode and Effect Analysis的英文缩写&#xff0c;中文名称为失效模式和影响分析。主要应用于航空航天、食品、汽车和核电等行业。 FMEA讨论的是事先策划以及执行措施&#xff0c;预防问题的发生或控制问题的发展&#xff0c;降低设计和过程的风险。由于问题还没…

AI:134-基于深度学习的社交媒体图像内容分析

🚀点击这里跳转到本专栏,可查阅专栏顶置最新的指南宝典~ 🎉🎊🎉 你的技术旅程将在这里启航! 从基础到实践,深入学习。无论你是初学者还是经验丰富的老手,对于本专栏案例和项目实践都有参考学习意义。 ✨✨✨ 每一个案例都附带有在本地跑过的关键代码,详细讲解供…

m估计及其c++简单实现

文章目录 什么是m估计怎么求解m估计呢&#xff1f;Huber函数时的线性m估计 什么是m估计 自20世纪60年代稳健统计建立以来&#xff0c;在国内外众多学者的研究之下&#xff0c;诞生了一系列稳健统计重要理论和成果。其中最主要且广泛使用的稳健统计有以下三类&#xff1a; L-e…

linux之前后端项目部署与发布

目录 前言 简介 一、安装Nginx 二、后端部署 2.1多个tomcat负载均衡 2.2 负载均衡 2.3 后端项目部署 三、前端部署 1.解压前端 2.Nginx配置文件修改 3.IP域名映射 4.重启Nginx服务 前言 上篇博主已经讲解过了单机项目的部署linux之JAVA环境配置JDK&Tomcat&a…

【elasticsearch】搜索结果处理

搜索结果处理 排序 elasticsearch支持对搜索结果排序&#xff0c;默认是根据相关度算分&#xff08;_score&#xff09;来排序。可以排序字段类型有&#xff1a;keyword类型、数值类型、地理坐标类型、日期类型等。 GET /indexName/_search {"query":{"match_a…

java 内存模型

程序计数器 线程私有主要字节码解释器通过读取程序计数器来选取下一条需要执行的指令&#xff0c;比如分支&#xff0c;循环&#xff0c;跳转和异常处理如果执行的是java 方法&#xff0c;那么程序计数器记录的时候虚拟机字节码指令的地址&#xff0c;如果执行的是native 方法…

【FreeRTOS】任务管理

一、任务管理介绍 1.任务状态 1&#xff09;调度器切换任务调度 2&#xff09;任务是一个死循环&#xff0c;如果想要停止这个任务则会调用在函数最后写的delete函数进行自杀 1.就绪态 1&#xff09;已经具备执行的能力&#xff0c;只等待调度器进行调度。 2&#xff09;新创建…

Linux系统前后端分离项目

目录 一.jdk安装 二.tomcat安装 三.MySQL安装 四.nginx安装 五.Nginx负载均衡tomcat 六.前端部署 一.jdk安装 1. 上传jdk安装包 jdk-8u151-linux-x64.tar.gz 进入opt目录&#xff0c;将安装包拖进去 2. 解压安装包 这里需要解压到usr/local目录下&#xff0c;在这里新建一个…

python程序设计基础:异常处理结构与程序调试、测试

第八章&#xff1a;异常处理结构与程序调试、测试 简单地说,异常是指程序运行时引发的错误,引发错误的原因有很多例如除零、下标越界、文件不存在、网络异常、类型错误、名字错误、字典键错误、磁盘空间不足,等等。 如果这些错误得不到正确的处理将会导致程序终止运行,而合理…

HuggingFists系统功能介绍(1)--系统概述

HuggingFists是一款低代码AI应用工具&#xff0c;力图发展为LangChain的低代码平替工具。HuggingFists发起于数由科技的Sengee数据科学计算框架&#xff0c;因此其界面风格继承了数据科学工具的很多特征。有别于完全基于LangChain衍生出的低代码工具Flowise&#xff0c;其风格更…

YOLO如何训练自己的模型

目录 步骤 一、打标签 二、数据集 三、跑train代码出模型 四、跑detect代码出结果 五、详细操作 步骤 一、打标签 &#xff08;1&#xff09;在终端 pip install labelimg &#xff08;2&#xff09;在终端输入labelimg打开 如何打标签&#xff1a; 推荐文章&#xf…

2.23 Day05

#include "mywidget.h" #include "ui_mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent), ui(new Ui::MyWidget) {ui->setupUi(this);//居中ui->label02->setAlignment(Qt::AlignCenter);ui->Edit1->setAlignment(Qt::Alig…

协程源码 launch 流程跟踪学习

为了更深入学习协程的底层实现原理&#xff0c;了解协程线程切换的根本本质。也为了以后在工作中可以根据不同的需求场景&#xff0c;更加随心所欲的使用不同的协程。 今天通过 launch 跟踪一下协程的执行流程。 fun getData() {Trace.beginSection("getData");Log.…

knife4j springboot3使用

简介 在日常开发中&#xff0c;写接口文档是我们必不可少的&#xff0c;而Knife4j就是一个接口文档工具&#xff0c;可以看作是Swagger的升级版&#xff0c;但是界面比Swagger更好看&#xff0c;功能更丰富 使用 我使用的是springboot3.2.3 knife4j 4.3.0,knife4j 4.4版本有…

RK3568平台开发系列讲解(Linux系统篇)字符设备驱动:主设备和次设备

🚀返回专栏总目录 文章目录 一、主设备和次设备的概念二、设备号的分配和释放沉淀、分享、成长,让自己和他人都能有所收获!😄 字符设备通过字符(一个接一个的字符)以流方式向用户程序传递数据,就像串行端口那样。字符设备驱动通过/dev目录下的特殊文件公开设备的属性和…

dolphinscheduler单机版部署教程

文章目录 前言一、安装准备1. 安装条件2. 安装jdk3. 安装MySQL 二、安装dolphinscheduler1. 下载并解压dolphinscheduler2. 修改配置文件2.1 修改 dolphinscheduler_env.sh 文件2.2 修改 application.yaml 文件 3. 配置mysql数据源3.1 修改MySQL安全策略3.2 查看数据库3.3 创建…

UE5 文字游戏(1) 仅UI截图转换为texture2d(适用于window端)

目录 需求 思路 1.截图并读取到本地 2.本地读取图片并转换为纹理2d 效果展示 找了好多的解决办法&#xff0c;都不管用。这个算是折中的。 需求 将当前的用户控件&#xff08;ui&#xff09;截图下来&#xff0c;并赋值到一个texture2d上。 我的需求&#xff1a;文字游戏…