抱歉,您的浏览器无法访问本站
本页面需要浏览器支持(启用)JavaScript
了解详情 >

目前的UI Toolkit比较适合做画面覆盖ui

暂时的缺陷如下:

image-20221119130244980

教程来自b站:

阿严_独立游戏开发

本篇是笔记.

创建UIBuilder

第一种,直接在window中创建

image-20221119135543774

第二种资产文件夹下创建UI document

image-20221119140813450

image-20221119140743326

打开后就是一样的画面,并且带着根节点

按住ctrl+alt+左键可以移动窗口(可能鼠标中键也行,但是今天我忘了带鼠标)

image-20221119141125755

画布设置

image-20221119141237141

不过我们不使用这个功能,手动设定窗口宽高1920*1080.


制作画面

画布已经创建好,现在开始做画面吧!效果图:

image-20221123162036048

这方面就不细说了,类似安卓的前端页面,也类似web前端的操作方式,值得一提的是这里也有xml代码

image-20221123162532523

创建uss(类似css)

image-20221123163048406

红色框内去掉.,添加Label,选中Label即可对所有文本的样式进行编辑.

image-20221123163219110


在游戏内显示

场景内右键创建UIdocument,就会出现一个搭载ui Document脚本的对象

image-20221123163407846

image-20221123163506651

此处可以选展示的页面

image-20221123163533876

空格显示/隐藏画面

新建脚本PartyDataScreen.cs附加到该对象上.

image-20221123163622836

getcomponent获取uidocument,然后获取rootVisualElement根视觉元素,根据根视觉元素的样式是否为flex,来展示/隐藏画面.

public class PartyDataScreen : MonoBehaviour
{
VisualElement rootvisualElement;//根部视觉部分
private void Awake()
{
rootvisualElement = GetComponent<UIDocument>().rootVisualElement;
}
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
rootvisualElement.style.display =
rootvisualElement.style.display == DisplayStyle.Flex ?
DisplayStyle.None :
DisplayStyle.Flex;
}
}
}

查找多个元素进行操作(批量操作)

rtvElement.Query()函数可以对多个元素进行操作

public class PartyDataScreen : MonoBehaviour
{
VisualElement rtvElement;//根部视觉部分
private void Awake()
{
rtvElement = GetComponent<UIDocument>().rootVisualElement;
rtvElement.Query("CharacterDataPanel").ForEach(OnSelectedMultipleElements);
rtvElement.Query<Label>("NameLabel").ForEach(OnSelectLabelElements);
}

private void OnSelectLabelElements(Label obj)
{
obj.style.color = Color.red;
obj.text = "冒险家";
}

private void OnSelectedMultipleElements(VisualElement obj)
{//设定背景色为黄色
obj.style.backgroundColor = Color.yellow;
}
}

查找单个元素

首先查找到索引1的个体,然后再通过q()单项设置

public class PartyDataScreen : MonoBehaviour
{
[SerializeField] Texture2D cat;
[SerializeField] string catName;
VisualElement rtvElement;//根部视觉部分
private void Awake()
{
rtvElement = GetComponent<UIDocument>().rootVisualElement;
var secondDataPanel = rtvElement.Query("CharacterDataPanel").AtIndex(1);
secondDataPanel.Q<Label>().text = catName;
secondDataPanel.Q("Avatar").style.backgroundImage = cat;
}
}

脚本中拖入图片素材,还有输入名字

image-20221128145220485

运行结果

image-20221128145309482

我们可以看到第二个框内部已更换为新的.


数据独立性

为了以后更好地维护和管理数据,我们有必要设计一个专门的类存放并处理这些数据,这也是从数据独立性方面来考虑.将游戏的逻辑和数据分开.

思路:创建一个继承于ScriptableObject的角色数据类:CharacterData,再创建四个实例分别存储四个角色数据.

创建队伍数据类,管理角色数据

角色属性类

创建白板,角色属性类CharacterStats.cs

[System.Serializable]//可序列化
public class CharacterStats
{//角色属性,暂时用int
public int initiative;//主动权\速度
public int maxHp;//血量
public int manMp;//魔法
public int attack;//攻击力
public int defense;//防御力
}

创建角色数据类

创建角色数据类CharacterData.cs

详细可以看代码注释

image-20221128150254092

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(menuName = ("Data/CharacterData"), fileName = ("CharacterData_"))]
public class CharacterData : ScriptableObject
{
[SerializeField] Texture2D characterAvatarImage;//角色头像
[SerializeField] string characterName;//角色名
[SerializeField] int characterStartLevel = 1;//角色初始等级
[SerializeField] CharacterStats characterStats;//角色属性类

//公有属性,防止数据被修改
public Texture2D CharacterAvatarImage => characterAvatarImage;
public string CharacterName => characterName;
public int CharacterStartLevel1 => characterStartLevel;
public CharacterStats ChStats => characterStats;
}

资源文件夹中创建CharacterData实例

image-20221128151552868

所有角色实例

image-20221128152033900

image-20221128152130857

队伍数据类

创建队伍数据类PartyData.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// 队伍数据类
/// </summary>
[CreateAssetMenu(menuName = ("Data/PartyData"), fileName = ("PartyData_"))]
public class PartyData : ScriptableObject
{
[SerializeField] List<CharacterData> characterDataList;
public List<CharacterData> CharacterDataList => characterDataList;
}

拖入角色实例,这样队伍里增加减少或角色更加方便.

image-20221128153719899

这样,就可以通过序列化PartyData对象获取整个队伍的数据.


CustomControls自定义控件

CustomControls是ui Toolkit的一个高级功能,我们可以通过c#脚本创建拥有自定义逻辑的复杂ui元素,自定义控件的创建从相应的c#类开始

实时生成角色数据面板

创建CharacterDataPanel角色数据面板类

using UnityEngine.UIElements;
public class CharacterDataPanel : VisualElement
{//继承VisualElement
/// <summary>
/// 使自定义控件曝露到uxml文件中,让它可以像其他默认UI元素一样,在UI Builder里使用.
/// <para>|模板,不需要特地记</para>
/// </summary>
public new class UxmlFactory : UxmlFactory<CharacterDataPanel> { }
//声明构造函数
public CharacterDataPanel()
{
}
}

保存后打开UI Builder,在下面project中可以找到该控件

image-20221128162642351

给自定义控件添加内容

使用UI Toolkit的Template模板功能.

创建模板

image-20221128163144657

将模板存放到Assets\Data\UIDocuments\Resources中,注意Resources文件夹创建的时候不可以有任何大小写拼写错误.

image-20221128163426882

控件显示如下图

image-20221128163656419

显示成这个样子是因为创建的控件自动多了一个容器

image-20221128163752772

我们在存放目录这,右键从UIBuilder打开模板的uxml文件

image-20221128163913210

重置basis属性,grow设为1

image-20221128165002650

然后保存后回到主页面,将basis设为25%

image-20221128165032262

image-20221128165103409

全部替换掉,就得到了原来的样子

image-20221128165228905

现在,我们有了数据面板的模板,那么接下来实现用c#脚本生成模板

代码生成模板

打开CharacterDataPanel.cs

using UnityEngine;
using UnityEngine.UIElements;
public class CharacterDataPanel : VisualElement
{//继承VisualElement

readonly TemplateContainer templateContainer;
/// <summary>
/// 使自定义控件曝露到uxml文件中,让它可以像其他默认UI元素一样,在UI Builder里使用.
/// <para>|模板,不需要特地记</para>
/// </summary>
public new class UxmlFactory : UxmlFactory<CharacterDataPanel> { }

//声明构造函数
public CharacterDataPanel()
{
//加载模板资产文件,这个模板是uxml文件,Instantiate:实例化ui
templateContainer = Resources.Load<VisualTreeAsset>("CharacterDataPanel").Instantiate();
templateContainer.style.flexGrow = 1.0f;//设grow为1
hierarchy.Add(templateContainer);//添加到游戏操作界面
}
}

评论