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

news2024/12/25 13:07:16

推荐阅读

  • 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和坑,让后来人可以有些参考。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3 easy 26. 删除有序数组中的重复项

双指针&#xff1a; //给你一个 非严格递增排列 的数组 nums &#xff0c;请你 原地 删除重复出现的元素&#xff0c;使每个元素 只出现一次 &#xff0c;返回删除后数组的新长度。元素的 相对顺序 应该保持 //一致 。然后返回 nums 中唯一元素的个数。 // // 考虑 nums 的唯…

服务器防漏扫

什么是漏扫&#xff1f; 漏扫是漏洞扫描的简称。漏洞扫描是一种安全测试方法&#xff0c;用于发现计算机系统、网络或应用程序中的潜在漏洞和安全弱点。通过使用自动化工具或软件&#xff0c;漏洞扫描可以检测系统中存在的已知漏洞&#xff0c;并提供相关的报告和建议&#xf…

如何在Linux部署Portainer并结合内网穿透远程管理本地Docker容器

文章目录 前言1. 部署Portainer2. 本地访问Portainer3. Linux 安装cpolar4. 配置Portainer 公网访问地址5. 公网远程访问Portainer6. 固定Portainer公网地址 前言 Portainer 是一个轻量级的容器管理工具&#xff0c;可以通过 Web 界面对 Docker 容器进行管理和监控。它提供了可…

【牛牛送书 | 第四期】《高效使用Redis:一书学透数据存储与高可用集群》带你快速学习使用Redis

前言&#xff1a; 当今互联网技术日新月异&#xff0c;随着数据量的爆炸式增长&#xff0c;如何高效地存储和管理数据成为了每个公司都必须面对的挑战。与此同时&#xff0c;用户对于应用程序的响应速度和稳定性要求也越来越高。在这个背景下&#xff0c;Redis 作为一个…

C++ 学习之函数对象

C 函数对象基本概念 在C中&#xff0c;函数对象&#xff08;Function Objects&#xff09;是一种类或结构体&#xff0c;它重载了函数调用运算符operator()&#xff0c;因此可以像函数一样被调用。函数对象有时也被称为仿函数&#xff08;Functor&#xff09;。 以下是关于C函…

备战蓝桥杯---基础算法刷题2

题目有一点水&#xff0c;不过还是有几个好题的&#xff0c;我在这分享一下&#xff1a; 很容易想到先往最高处跳再往最低处跳&#xff0c;依次类推&#xff0c;那怎么保证其正确性呢&#xff1f; 证法1. 在此&#xff0c;我们从0开始&#xff0c;假设可以跳到a,b,c(a<b<…

Linux中消息队列

消息队列 概念 消息队列是System V IPC对象的一种消息队列有消息队列ID来唯一标识消息队列就是一个消息列表。用户可以在消息队列中添加消息、读取信息等消息队列可以按照类型来发送/结束消息 消息队列使用步骤 打开/创建消息队列 msgget向消息队列发送信息 msgsnd从消息队…

4.4 MySQL存储

目录 1、使用前提 2、使用连接数据库最初步骤 2.1 最初步骤 2.2 connect()方法中参数简单传递 3、创建数据库(创建架构)和创建表 3.1 创建数据库(创建架构) 3.2 创建表 3.2.1 基本创建 3.2.2 创建自增主键 4、Pycharm 可视化连接 MySQL 图形界面 5、插入、更新、查询…

项目管理工具git

git 1. git介绍1.1. 版本控制系统 2. 创建本地版本库2.1 概念2.2 操作步骤 3. 修改文件4. 练习: 添加一个本地项目到仓库5. 添加远程仓库5.1 添加远程仓库5.2 本地仓库同步到远程仓库5.3 克隆远程仓库到本地5.4 SSH设置 6. 分支管理6.1 创建分支6.2 切换分支6.3 合并分支6.4 解…

基于yolov5的苹果检测(pytorch框架)【python源码+UI界面+功能源码详解】

功能演示&#xff1a; 基于yolov5的苹果检测系统&#xff0c;系统既能够实现图像检测&#xff0c;也可以进行视屏和摄像实时检测_哔哩哔哩_bilibili &#xff08;一&#xff09;简介 基于yolov5的苹果检测系统是在pytorch框架下实现的&#xff0c;这是一个完整的项目&#xf…

Go语言必知必会100问题-06 生产者端接口

生产者端接口 Go语言必知必会100问题-05 接口污染中介绍了程序中使用接口是有价值的。在编码的时候&#xff0c;接口应该放在哪里呢&#xff1f;这是Go开发人员经常有误解的一个问题&#xff0c;本文将深入分析该问题。 在深入探讨问题之前&#xff0c;先对提及的术语做一个定…

如何使用Inno Setup制作Unity构建程序的Windows安装程序

1. 准备 &#xff08;1&#xff09;准备好Unity构建的程序集合 必须包括&#xff1a; Data文件夹&#xff08;xxx_Data&#xff09; Mono文件夹&#xff08;MonoBleedingEdge&#xff09; 打包的应用程序文件&#xff08;xxx.exe&#xff09; Unity播放器dll文件&#xff…

mac flutter 配置

下载Flutter Sdk 直接访问官网无法下载&#xff0c;需要访问中国镜像下载 Flutter SDK 归档列表 - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter Start building Flutter Android apps on macOS - Flutter 中文文档 - Flutter 中文开发者网站 - Flutter 下载后解压…

HCIA-Datacom实验指导手册:5.1 实验一:FTP SFTP TFTP 基础配置实验

HCIA-Datacom实验指导手册&#xff1a;5.1 实验一&#xff1a;FTP 基础配置实验 一、实验介绍&#xff1a;二、实验拓扑&#xff1a;三、实验目的&#xff1a;四、配置步骤&#xff1a;步骤 1 设备基础配置步骤 2 在 Router 上配置 FTP 和SFTP服务器功能及参数步骤 3 配置本地 …

大厂经验谈之OKR目标管理

前言 这是大厂经验谈系列第一篇文章,来看看互联网公司是如何制定和管理目标的。OKR是目前互联网公司经常采用的目标管理工具,最开始也是由国外著名公司推崇,比如Google、微软、亚马逊等,后面才逐步引入国内。既然是工具就有用得好和不好的地方,很多团队仍然把OKR当做KPI来…

【人工智能高频面试题--基本篇】

&#x1f680; 作者 &#xff1a;“码上有前” &#x1f680; 文章简介 &#xff1a;人工智能高频面试题 &#x1f680; 欢迎小伙伴们 点赞&#x1f44d;、收藏⭐、留言&#x1f4ac; 人工智能高频面试题--基本篇 1.深度学习和过往的神经网络训练方法有什么区别&#xff1f;列举…

2024年 前端JavaScript入门到精通 第四天 笔记

4.1 函数的基本使用以及封装练习 ★ 函数命名规范 4.2 函数的参数以及默认参数 函数的灵魂&#xff01;&#xff01;&#xff01; 4.3 函数封装数组求和案例 4.4 函数返回值return 4.5 函数返回值细节以及上午总结 4.6 函数返回值案例-求最大值和最 4.7 函数复习以及断点进入函…

php脚本输出中文在浏览器中显示乱码

问题说明 这个问题一般出现在较低版本的php中&#xff0c;原因是php和浏览器的字符解析方式不对应 &#xff0c;导致中文字符被错误解析成乱码 &#xff08;注&#xff0c;此处的php版本任意切换是依赖于小皮面板&#xff08;phpstudy&#xff09;实现的&#xff0c;感兴趣可以…

132 Linux 系统编程9 ,IO操作,lseek 函数,truncate函数,查看文件的表示形式

一 lseek 函数 函数说明&#xff1a;此函数用于文件偏移 Linux中可使用系统函数lseek来修改文件偏移量(读写位置) 每个打开的文件都记录着当前读写位置&#xff0c;打开文件时读写位置是0&#xff0c;表示文件开头&#xff0c;通常读写多少个字节就会将读写位置往后移多少个字…

2024国际生物发酵展览会全面揭秘-西尼尔过程控制

参展企业检查 西尼尔&#xff08;南京&#xff09;过程控制有限公司成立于2007年&#xff0c;坐落于美丽的六朝古都南京&#xff0c;占地面积20000平方米&#xff0c;现有员工130人&#xff0c;其中70%为本科及以上学历&#xff0c;高级、中级专业技术人员占比30%以上。 公司为…