在Unity当中使用GameFrameworkX框架的知识点

流程功能:

介绍:

流程主要是在项目运行的时候,存在多种不同的玩法,以前可能每个玩法制作一个场景,用转换场景来切换玩法,但是这样存在很多缺点,引入切换流程概念来达到切换场景的功能

实现功能:

当玩法改变的时候,加载新玩法需要的资源,卸载旧玩法用到的资源,在玩法进行的时候有需要类似Manager公共方法处理的循环的时候,可以代替Manager循环,静态场景可以置空

实现方法:

一、新增一个流程:

新增一个继承ProcedureBase的cs脚本,继承ProcedureBase之后会有新的生命周期函数

cs 复制代码
using GameFramework.Fsm;
using GameFramework.Procedure;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityGameFramework.Runtime;

public class LoadMenuProcedure : ProcedureBase
{
    protected override void OnInit(IFsm<IProcedureManager> procedureOwner)
    {
        //进入游戏就会加载所有流程的Init
        base.OnInit(procedureOwner);
    }
    protected override void OnEnter(IFsm<IProcedureManager> procedureOwner)
    {
        //每次进入这个流程的时候执行
        base.OnEnter(procedureOwner);
    }

    protected override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds, float realElapseSeconds)
    {
        //在这个流程运行的时候,每帧都会执行
        base.OnUpdate(procedureOwner, elapseSeconds, realElapseSeconds);
    }
    protected override void OnLeave(IFsm<IProcedureManager> procedureOwner, bool isShutdown)
    {
        //每次退出这个流程的时候执行
        base.OnLeave(procedureOwner, isShutdown);
    }

    protected override void OnDestroy(IFsm<IProcedureManager> procedureOwner)
    {
        //流程被销毁的时候执行
        base.OnDestroy(procedureOwner);
    }
}

生命周期函数共有5个:

1:OnInit (进入游戏就会加载所有流程的Init)

2:OnEnter(每次进入这个流程的时候执行)

3:OnUpdate (在这个流程运行的时候,每帧都会执行)

4:OnLeave (每次退出这个流程的时候执行)

5:OnDestroy(流程被销毁的时候执行)

在写完这个脚本之后,在Assets里找到AppConfigs,从里面的Procedures里面找到刚才写的流程并勾选,这样就算是成功的进入一个流程了

二、切换流程

cs 复制代码
ChangeState<LoadMenuProcedure>(procedureOwner);

只需要执行这一行逻辑,流程就切换了,执行切换流程的逻辑的脚本必须本身也是流程脚本,也就是必须继承ProcedureBase

三、流程之间互相传递信息

每个流程的生命周期函数当中都有一个参数,并且在方法第一个参数的位置

cs 复制代码
IFsm<IProcedureManager> procedureOwner

这个参数的作用就是让流程之间互相传递数据,用键值对传递数据

写入数据:
cs 复制代码
    protected override void OnEnter(IFsm<IProcedureManager> procedureOwner)
    {
        procedureOwner.SetData<VarString>("字符串数据1", "Value_1");
        procedureOwner.SetData<VarString>("字符串数据2", "Value_2");
        procedureOwner.SetData<VarInt32>("整数数据1", 1);
        procedureOwner.SetData<VarInt32>("整数数据2", 2);
        procedureOwner.SetData<VarFloat>("小数数据1", 1.1f);
        procedureOwner.SetData<VarFloat>("小数数据2", 1.2f);
        //每次进入这个流程的时候执行
        base.OnEnter(procedureOwner);
    }

procedureOwner.SetData方法,传入一个Var泛型代表保存的数据类型,第一个参数为键名用来记录数据存储的名字,第二个参数为键值记录具体的值

读取数据:
cs 复制代码
    protected override void OnEnter(IFsm<IProcedureManager> procedureOwner)
    {
        string str1 = procedureOwner.GetData<VarString>("字符串数据1");
        string str2 = procedureOwner.GetData<VarString>("字符串数据2");
        int i1 = procedureOwner.GetData<VarInt32>("整数数据1");
        int i2 = procedureOwner.GetData<VarInt32>("整数数据2");
        float f1 = procedureOwner.GetData<VarFloat>("小数数据1");
        float f2 = procedureOwner.GetData<VarFloat>("小数数据2");
        //每次进入这个流程的时候执行
        base.OnEnter(procedureOwner);
    }

procedureOwner.GetData方法,传入一个Var泛型代表读取的数据类型,参数传入想要获取的数据的键名,返回键名保存的键值数据

其他数据操作:
cs 复制代码
procedureOwner.RemoveData("字符串数据");

移除一个键名和其保存的键值,这个尽量每次有使用完数据后,数据没用了都移除,降低内存损耗

cs 复制代码
procedureOwner.HasData("字符串数据")

返回一个bool,判断是否存在这个值,如果这个值存在就返回true,不存在就返回false

其余注意点:
cs 复制代码
GF.BuiltinView.HideLoadingProgress();

使用GFX框架中的切换场景的功能之后,在流程初始要关闭加载页面,关闭加载页面的方法就是这个GF.BuiltinView.HideLoadingProgress();方法,调用之后就关闭加载页面了


DataTable数据表

介绍:

读取本地文件当中配置的数据,比如每个单位的生命值,攻击力,以及其他的数值,用数据表的形式输入,然后生成值类型保存起来

使用方式:

一、新建数据表:

在AppConfigs中的DataTable页面,点击那个页面中的最下方有一个可以输入的地方,在那个地方输入数据表的名字,然后点击输入框最右边的NewDataTable,就能新建数据表了

二、找到数据表:

在AppConfigs的DataTable页面,点击页面中的Revel按钮,会打开一个文件夹,在这个文件夹中打开DataTables子文件夹,然后找到和数据表名字对应的Excel文档,这个文档就是数据表,修改数据表就需要编辑这个文档中的内容

三、编辑数据表:

注意:数据表中最左边一列效果是如果输入#号,则这一行不作为数据处理

数据表中的第二行为变量的名称,第三行为变量的类型,这两个是在代码中固定写好的,其中变量名称必须为大写字母开头,剩余字符为小写字母或者下划线,变量类型一般有下拉框可以选择必须是可识别的变量类型,比如string,float,int。

在第二行和第三行的第二列,变量名必须为Id,变量类型必须为int,因为这个变量的解析是框架中固定好的,后续填写的数值的时候,Id需要根据数字依次递增

第四行一般在第一列输入一个#号,然后后面的格子作为每个属性的备注

第五行开始就是每个单位具体的数值了,比如在Name下面写Player,在Hp下面写1000

第六行,第七行,第八行,都是同理,下面就全都是填写具体数值的地方

最后填写完成就是这个样子的:

最后点击AppConfig页面中的DataTable页面中的Export按钮,等待进度条完成,就会根据表格填写的数据生成代码了

四、使用数据表:

生成出来的代码里面包含了上面数据表中第二行和第三行定义的所有变量名和变量类型生成变量,有多少列生成多少变量。

然后通过:

cs 复制代码
var data = GF.DataTable.GetDataTable<SoliderData>();
SoliderData soliderData = data.GetDataRow(0);

GF.DataTable.GetDataTable方法获取指定数据表,在泛型中传入DataTable页面中数据表名字

然后调用GetDataRow方法,其中的参数为一个int值,int的值为获取Id为几的数据,比如

传入0时获取到的就是上表MyPlayer的数据,Hp为1000,Attack为100

传入1获取的就是就是上表Enemy1的数据,Hp为100,Attack为10

cs 复制代码
var data = GF.DataTable.GetDataTable<SoliderData>();
int i = data.Count;

调用GF.DataTable.GetDataTable方法返回值的Count属性,可以获得一共有多少条数据


DataModel动态存储

介绍

在开发项目时,经常需要在单例存储一些临时数据以及一些本地存储的数据

临时数据:生命值,角色当前buff,场景敌人数量

本地存储:金币数量,钻石数量

这种情况下不用GFX框架就需要创建一个单例类来储存这些每个类都要访问的数值,需要保存的数值还需要做数据本地化

现在GFX框架提供了方便快捷的方式

创建临时数据

需要一个类来继承DataModelBase,然后实现OnCreat方法,在里面填写初始值

cs 复制代码
public class TestDataModel : DataModelBase
{
    public float hp;

    public float attack;

    protected override void OnCreate(RefParams userdata)
    {
        base.OnCreate(userdata);
        hp = 1000;
        attack = 100;
    }
}

这些数据都是既存即用,每次退出游戏后数据就会丢失

创建本地数据

需要一个类来继承DataModelStorageBase,然后实现OnInitialDataModel方法,在里面填写初始值

cs 复制代码
public class TestDataModelStorage : DataModelStorageBase
{
    public int gold;

    public int diamond;

    protected override void OnInitialDataModel()
    {
        gold = 1000;
        diamond = 100;
    }
}

这些数据不需要再代码中进行任何的本地化处理,底层逻辑已经做好自动本地化处理了,只需要直接访问和修改数值,代码中的数据会自动本地化

访问动态数据

只需要一句话就可以访问到

cs 复制代码
TestDataModel tdm = GF.DataModel.GetOrCreate<TestDataModel>();
TestDataModelStorage tdms = GF.DataModel.GetOrCreate<TestDataModelStorage>();

获取到这个类型之后,可以直接访问或者修改里面的值,同时继承DataModelStorageBase类的脚本会对数值自动本地化,自动保存和读取


Entity实体对象

介绍

每当游戏中需要涉及到GameObject.Instantiate()从资源中加载物体到场景的时候,都可以用GFX框架提供的创建Entity对象的方法覆盖,通过GFX将对象加载到场景时,有以下几个优点:

1.自带对象池,同时自动配有完善的销毁库存机制

2.创建对象的时候可以使用异步方式创建,这种情况下可以同时创建几千个不卡顿

3.使用Entity的实体对象有全新的生命周期函数,同时继承了Mono的生命周期函数

4.使用Entiy实例对象或者隐藏对象的时候比自己写的效率要高

使用方式

一、新建实体对象

先创建预制体,然后将预制体保存到GFX框架下的Prefabs/Entity的文件夹下,这个预制体可以不挂载任何代码,GFX框架创建实体时会自动为其挂载脚本

二、挂载脚本

挂载到实体的脚本需要继承EntityBase,同时可以使用来自EntityBase的生命周期函数

OnInit:当实体第一次被创建到场景中执行,主要用来获取实体中各个组件

OnShow:当实体被唤醒时执行,主要用来初始化实体状态,比如回满生命值

OnHide:当实体被隐藏时执行,可以用来从单位管理器中移除这个单位

三、创建用来给实体传递信息的EntityParams

创建实体之前,需要先创建要传递给实体的数据,比如创建实体的时候这个实体的血量,阵营,颜色,以及其他的数值,然后将这些数值打包传入实体

cs 复制代码
EntityParams entity = EntityParams.Create(Vector3.zero,Vector3.zero);
entity.Set<VarString>("Name", "Solider");
entity.Set<VarInt32>("Hp", 100);

EntityParams.Create这个静态方法可以返回一个EntityParams类型的值,这个方法的两个参数都是Vector3,第一个参数是实体创建出来的位置,第二个参数是实体创建出来的角度

entity.Set则是一个方法,泛型是保存的类型,VarString就是string,两个参数为键值对

四、实体创建到场景

存在两种创建,一种时同步创建,一种异步创建

异步创建会高效率的逐步将单位创建出来,但是创建之后无法立刻调用单位,只能返回一个单位的Id用来销毁实体或取消实体的异步创建过程

同步创建会立刻将单位创建出来,立刻就能调用单位执行某些逻辑,但是同时同步创建多个单位会非常卡顿,影响运行效率

异步创建方法:

cs 复制代码
int i = GF.Entity.ShowEntity<TestEntity>("ShowEntity",Const.EntityGroup.Bullet, entity);

调用GF.Entity.ShowEntity方法异步创建一个实体单位到场景中

方法的泛型为要挂载到实体的脚本,必须是继承EntityBase基类的脚本

方法的第一个参数为预制体的路径,这个路径以GFX框架下Prefabs/Entity/为基础路径

方法的第二个参数为预制体创建的组别,每个组别可以容纳的最大实体数量和自动销毁间隔都不相同,后面会讲调节组别的数值

方法的第三个参数为EntityParams,也就是上面说的需要传入实体的参数

方法的返回值为int,返回一个实体编号,这个编号基本就是用来隐藏实体的时候作为参数传入

同步创建方法:

cs 复制代码
TestEntity te = await GF.Entity.ShowEntityAwait<TestEntity>("ShowEntity",Const.EntityGroup.Bullet, entity) as TestEntity;

这个方法的泛型和参数都和异步相同,必须通过添加await同步执行,后面还需要进行强制转换,通过这种方式立刻返回创建出来的实体对象

五、隐藏实体对象

分三种情况,分别是实体对象隐藏自己,隐藏指定的实体对象,以及根据编号隐藏实体对象

1.实体对象隐藏自己
cs 复制代码
GF.Entity.HideEntity(this.Entity);

调用GF.Entity.HideEntity方法,参数传入this.Entity就行,格式固定不用改变

2.隐藏指定的实体对象
cs 复制代码
GF.Entity.HideEntity(te.Entity);

也是调用GF.Entity.HideEntity方法,不过传入的参数是通过同步创建方法创建出来的对象

3.根据编号隐藏实体对象
cs 复制代码
GF.Entity.HideEntity(i);

也是调用GF.Entity.HideEntity方法,传入的参数是异步创建时返回的编号,如果还没有被创建出来就会取消这个实体单位的创建过程

六、设置实体的组别

在Appconfig文件中,找到DataTable,点击Reveal,打开文件夹,找到DataTables/Core/EntityGroupTable。这个文件是用来记录组别的所有数据的

ReleaseInterval:每隔多少秒检测一次是否有需要被从对象池移除的对象

ReleaseInterval:对象池能保存的最大实体数量

ExpireTime:实体被隐藏多长时间之后被判定为需要被移除的对象

Priority:优先级,暂时没研究出作用,保持默认为0。


事件系统

介绍

当不同的类,实体,UI,想要相互调用,不应该获取彼此的实例然后调用方法,而是应该由调用方直接发送一个事件,然后由执行方接受事件然后执行对应方法

使用方式

一、新建事件类型

GF框架中,事件类型的脚本必须要继承GameEventArgs基类,然后重写公共变量Id,重写公共方法Clear

cs 复制代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using GameFramework;
using GameFramework.Event;

public class TestChangeValueEvent : GameEventArgs
{
    public static readonly int EventId = typeof(TestChangeValueEvent).GetHashCode();
    public override int Id => EventId;

    public int intValue;

    public string strValue;

    public float floatValue;

    //其余数据可自行添加

    public static TestChangeValueEvent Create(int intValue, string strValue, float floatValue)
    {
        var instance = ReferencePool.Acquire<TestChangeValueEvent>();
        //在下面给这些值初始化数据
        instance.intValue = intValue;
        instance.strValue = strValue;
        instance.floatValue = floatValue;
        return instance;
    }

    public override void Clear()
    {
        //将数据重置为默认值
        intValue = 0;
        floatValue = 0;
        strValue = "";
    }
}

public static readonly int EventId = typeof(TestChangeValueEvent).GetHashCode();

public override int Id => EventId;

第一句为将自己当前类型的哈希值转换为这个事件的Id,第二句是将这个事件Id赋值给基类的访问Id,这两行逻辑不要变,每次定义事件类型最好都有这两行

Create方法中的var instance = ReferencePool.Acquire<TestChangeValueEvent>();

作用为从对象池中寻找一个泛型中的类并返回,等同于new了一个新类,不过这种写法效率更高

二、订阅事件

cs 复制代码
    protected override void OnOpen(object userData)
    {
        base.OnOpen(userData);
        GF.Event.Subscribe(TestChangeValueEvent.EventId, ChangeValue);
    }

    private void ChangeValue(object sender, GameEventArgs e)
    {
        TestEntity entity = sender as TestEntity;
        if(entity != null)
        {
            varText_1.text = entity.name;
        }
        TestChangeValueEvent tcve = (TestChangeValueEvent)e;
        int i = tcve.intValue;
        string str = tcve.strValue;
        float f = tcve.floatValue;
    }

订阅事件的方法是GF.Event.Subscribe,其中第一个参数为想要订阅的事件Id,通常情况下传入事件类根据哈希值生成的EventId这个公开变量

第二个参数为事件的回调,回调方法包含两个参数,第一个参数为发送事件时传入的脚本,第二个参数为GameEventArgs事件类,想要应用事件类的变量需要强制转换成继承GameEventArgs基类的自定义事件类

第一个参数sender为发送事件时传入的脚本,需要先把sender强制转换成为可能发送事件的脚本,然后在判断不为空的时候,调用转换好的脚本的方法或者使用其中的变量

三、发送事件

cs 复制代码
GF.Event.Fire(this, TestChangeValueEvent.Create(100,"abc",10.0f));

发送事件方法为GF.Event.Fire

其中第一个参数为回调方法第一个参数访问到的sender,可以传入任何脚本,这里传入自己

第二个参数为继承了GameEventArgs的自定义事件类,这里用的是事件类的静态Creat方法返回一个创建好的自定义事件类,事件类创建的时候会自动分配Id,这里只需要填写需要传递给接受事件方的数值就可以

四、取消订阅事件

cs 复制代码
GF.Event.Unsubscribe(TestChangeValueEvent.EventId, ChangeValue);

和订阅方法的参数和使用方式都一样能,执行之后就能取消订阅这个事件


UI系统

介绍

GFX框架中有一套独立的UI系统,有着界面类型和优先级,有一套完整的生命周期,能够在编辑器页面快捷指定UI页面会引用到的组件,对比自己手动编写UI逻辑要方便许多

使用方式

一、创建UI页面

1.创建UI预制体

先创建一个UI预制体,这个预制体下面子物体可以有任意UI相关子物体,例如Image,Text之类的,然后将预制体的路径放置在GFX框架下的Prefabs/UI目录下,如果想在这个目录下的子目录下的时候,需要在后面的配置表里写明

2.挂载UI脚本

UI脚本需要继承UIFormBase基类,而且必须带有关键字partial,这个关键字用来和框架中自动生成的变量代码组合,这个基类有着自己的可重写的生命周期函数

OnInit(object userData) UI界面第一次被创建出来执行(仅创建时)

OnOpen(object userData) UI界面每次被打开时

OnClose(bool isShutdown, object userData)UI界面每次被关闭的时候执行

OnButtonClick(object sender, Button btSelf)每次有界面中的Button被点击时会调用的方法(需要手动设置引用)

OnButtonClick(object sender, string btId)同上,不过传入的不是Button而是Button设置的Id

cs 复制代码
using GameFramework.Event;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityGameFramework.Runtime;

public partial class TestUI : UIFormBase
{
    protected override void OnInit(object userData)
    {
        base.OnInit(userData);
    }

    protected override void OnOpen(object userData)
    {
        base.OnOpen(userData);
    }

    protected override void OnClose(bool isShutdown, object userData)
    {
        base.OnClose(isShutdown, userData);
    }

    protected override void OnButtonClick(object sender, Button btSelf)
    {
        base.OnButtonClick(sender, btSelf);
    }
}

然后为预制体添加这个脚本

3.操作编辑器为脚本添加组件

想要生成变量代码还需要在编辑器中进行如下设置:

A.为要生成变量代码的组件设置标签

首先右键想要设置标签的组件,然后选UIFormTools选项,子菜单栏中最上方的三个选项分别是:

Add private 创建一个私有变量组件(多选时创建私有数组)

Add protected 创建一个可继承变量组件(多选时创建可继承数组)

Add split 多选时使用Add split创建可以将每个组件单独创建为一个变量,而不是创建数组

选择三个选项之一,然后在弹出的菜单中选择想要创建的组件类型,就完成标签的设置

B.为按钮设置点击事件

右键想要设置按钮事件的Button,然后选择UIFormTools

在弹出的菜单中选择AddButtonOnClick(Button)按钮点击会调用Button参数的回调

在弹出的菜单中选择AddButtonOnClick(string)按钮点击会调用sring参数的回调(string数值在Button组件的点击回调指令中设置)

C.生成变量代码

添加了带有继承UIFormBase基类的自定义UI界面类,在组件的检查器页面就会生成这样的按钮

点击上图中的生成变量代码按钮,会自动在GFX框架下的Scripts\UI\UIVariables路径创建一个变量代码,生成完之后点击查看变量代码就能打开生成的变量代码进行查看

二、在DataTable中设置新的UI页面

找到AppConfig文件,在右侧检查器找到DataTable页面中的Reveal按钮并点击,打开一个文件夹,在文件夹下找到DataTables\Core\UITable文件,这个里面的文件按照DataTable数据表的形式记录着每一个需要被创建出的UI和绑定的信息

Id:根据表内的行数依次往下填充

SortOrder:表示UI的显示层级,数字越大UI盖住数字小的UI

UIPrefab:代表了加载的UI预制体相对于Prefabs/UI目录下的位置

PauseCoveredUI:如果是True,打开同组内的别的UI就把自己关闭,False则不关闭

UIGroupId:表示UI是哪一组的,数字越大盖住数字小的,先判断组再判断层

EscapeClose:是否触发返回键关闭

在添加完成想要的信息之后,关闭Excel,然后再AppConfig面板的DataTable页面点击Export重新生成一下项目数据

三、创建为UI传递的参数

cs 复制代码
UIParams uIParams = UIParams.Create();
uIParams.Set<VarString>("标题", "abc");
uIParams.Set<VarInt32>("整数", 123);
uIParams.Set<VarFloat>("小数", 123.123f);

通过UIParams.Creat方法创建一个UIParams类型的变量,然后通过Set方法为变量添加各种数据,数据通过键值对添加,方法泛型传入的是Var数据类型,参数一为键名,参数二为键值

四、开启UI页面

cs 复制代码
int i = GF.UI.OpenUIForm(UIViews.TestUI, uIParams);

创建好预制体,挂好脚本,配置好数据表,创建好UI参数,剩下的创建就非常简单

调用GF.UI.OpenUIForm方法,配置好数据表后参数一的枚举就会有刚才写好的UI脚本同名的枚举值,传入枚举值后,第二个参数传入上面创建好的UIParams类型的参数

返回值为创建UI的编号,主要用来在关闭的时候作为参数传递

五、UI脚本中使用传递过来的数据

cs 复制代码
    protected override void OnOpen(object userData)
    {
        base.OnOpen(userData);
        string str = Params.Get<VarString>("标题");
        int i = Params.Get<VarInt32>("整数");
        float f = Params.Get<VarFloat>("小数");
    }

在继承了UIFormBase的类的方法中,通过Params.Get方法获取传入的数据,Params为基类的变量,这个变量已经在基类经过自动处理获取了所有的数据,通过Get可以直接获取

Get方法的泛型为Var数据类型,传入的方法为键名,返回键名下保存的键值

六、关闭UI页面

1.打开的UI页面想要在脚本中关闭自己的时候,执行:

cs 复制代码
GF.UI.CloseUIForm(this.UIForm);

2.外界想要关闭UI页面的时候,传入创建UI时返回的UI编号

cs 复制代码
int i = GF.UI.OpenUIForm(UIViews.TestUI, uIParams);
GF.UI.CloseUIForm(i);

UI页面的组件:UIItem

介绍

有时候UI页面当中需要存在一些需要动态创建出来的UI元素,比如排行榜,有时可能是10个人,有时是100个人,这种时候就应该在每一条UI元素上挂载一个UIItem组件,这个组件可以不用像UIFrom一样打开一个新界面,而是在当前页面的基础上动态创建一些UI元素

使用方式

一、创建UI预制体

和创建UI界面相同,在子物体中创建好自己会使用到的UI组件,然后拖拽成预制体,这个UIItem的路径不需要必须放在指定位置,可以直接动态引用,不过仍然推荐方法在Prefab/UI/UIItem中,方便UI维护

二、挂载UI脚本

UIIteam脚本需要继承基类UIItemBase,其中最重要的生命周期函数为OnInit

OnInit:在第一次实例化时执行一次,通常用来获取组件或者为组件添加对应事件

还有就是记得在脚本里写一个接受外部信息的公开方法,后续通过这个方法传递数值

cs 复制代码
public partial class TestItem : UIItemBase
{
    protected override void OnInit()
    {
        base.OnInit();
    }

    public void SetData(SoliderData data)
    {
        varT1.text = data.Name;
        varT2.text = data.Hp.ToString();
        varT3.text = data.Attack.ToString();
        varT4.text = data.Id.ToString();
    }
}

三、为脚本创建变量代码

创建变量代码的方式和UIForm完全相同

右键想要添加变量的组件,然后选择UIFormTools,然后选择Add split,选择想要生成的类型

对按钮右键选择UIFromTools,然后选择AddButtonOnClick添加按钮回调事件

最后点击生成变量代码

四、创建UI元素

创建UI元素的方法必须要写在继承UIFormBase基类的自定义UI页面的脚本中

cs 复制代码
var data = GF.DataTable.GetDataTable<SoliderData>();
for (int i = 0; i < data.Count; i++)
{
    var uiIteam = this.SpawnItem<UIItemObject>(varTestIteam,varContent);
    (uiIteam.itemLogic as TestItem).SetData(data.GetDataRow(i));
}

第一行代码中的SoliderData是一个自定义的DataTable数据表,循环会根据数据表的内容总数传值

循环中的第一行代码:

cs 复制代码
var uiIteam = this.SpawnItem<UIItemObject>(varTestIteam,varContent);

this.SpawnItem<UIItemObject>方法,SpawnItem存在于UIFormBase基类中,泛型<UIItemObject>为固定写法,至少我不知道还有没有什么其他写法

方法的参数一为GameObject类型,表示需要创建的挂载着UIIteam脚本的预制体,声明公共变量然后从编辑器拖拽也可以,生成UI元素的方式获取也可以

方法的参数二为Transform类型,表示创建出的UI元素的父物体,一般通过生成变量代码获取

方法的返回值一般用var接受,主要作用是用来在下一行代码中强制转换成需要的格式

循环中的第二行代码:

cs 复制代码
(uiIteam.itemLogic as TestItem).SetData(data.GetDataRow(i));

将上一行代码中的返回值强制转换成继承UIIteam的脚本,然后调用前文中脚本的传递数据的方法,把UI界面想要传递给UI元素的数据传递过去

创建出来的UI元素会随着代码关闭回收到对象池,一般不需要主动回收


其余小功能

1.显示加载场景页面

cs 复制代码
GF.BuiltinView.ShowLoadingProgress();

2.隐藏加载场景页面

cs 复制代码
GF.BuiltinView.HideLoadingProgress();

3.设置相机优先级

在GFX默认启动框架下的Launch场景,其中的UICamera为渲染背景的Base模式,在这种情况下切换为其他场景的时候UICamera相机渲染的画面会遮挡新场景中主相机渲染的画面

为了解决这种情况,需要在加载到主场景之后,将Launch场景的UICamera设置为只渲染UI的Overlay属性的相机,并添加到主相机的cameraStack中

cs 复制代码
UniversalAdditionalCameraData uiCamera = GFBuiltin.UICamera.GetComponent<UniversalAdditionalCameraData>();
uiCamera.renderType = CameraRenderType.Overlay;
UniversalAdditionalCameraData mainCamera = Camera.main.GetComponent<UniversalAdditionalCameraData>();
mainCamera.cameraStack.Add(GFBuiltin.UICamera);

Launch场景的UICamera可以通过GFBuiltin.UICamera属性直接获取到,然后获取相机物体上挂载的UniversalAdditionalCameraData脚本,将脚本的renderType属性设置为CameraRenderType.Overlay,就可以让UI相机不渲染背景

然后需要找到主相机的UniversalAdditionalCameraData脚本,然后把UI相机添加到主相机的cameraStack属性当中,就可以让UI相机渲染的画面悬浮在主相机之上

4.调用当前流程的方法

cs 复制代码
(GF.Procedure.CurrentProcedure as GameOverProcedure).BackHome();

通过GF.Procedure.CurrentProcedure返回当前流程,返回的是流程基类,然后将流程基类强制转换成当前流程,然后调用流程的方法

待添加......

相关推荐
季明洵2 小时前
二叉树的最小深度、完全二叉树的节点个数、平衡二叉树、路径总和、从中序与后序遍历序列构造二叉树
java·数据结构·算法·leetcode·二叉树
AD钙奶-lalala2 小时前
SpringBoot 4.0.3配置Swagger
java·spring boot·后端
seven97_top2 小时前
NIO:解开非阻塞I/O高并发编程的秘密
java
小六溜了2 小时前
模块二十.双列集合
java
23.2 小时前
【Java】NIO 中的多路复用(Selector / Channel)机制
java·面试·nio
七夜zippoe2 小时前
Docker容器化实战:核心概念、镜像制作与多阶段构建全解析
java·jvm·数据库·docker·oracle·容器化
TimberWill2 小时前
优化if else过多的方案(含设计模式处理方式)
java·设计模式
东离与糖宝3 小时前
GraalVM+Project Leyden实战:Spring Boot应用原生编译,Serverless冷启动自由
java·人工智能
今天你TLE了吗3 小时前
JVM学习笔记:第七章——对象实例化、内存布局&访问定位
java·jvm·笔记·学习