Version: 6000.3
语言: 中文
管理元素的最佳实践
视觉元素参考

使用逻辑封装 UXML 文档

一个预制件:一种资产类型,允许您存储包含组件和属性的游戏对象。预制件充当模板,你可以从中在场景中创建新的对象实例。更多信息
请参阅术语表
是预制的游戏对象Unity 场景中的基本对象,可以表示角色、道具、风景、相机、航路点等。游戏对象的功能由附加到它的组件定义。更多信息
请参阅术语表
您可以在场景场景包含游戏的环境和菜单。将每个唯一的场景文件视为一个独特的关卡。在每个场景中,你放置你的环境、障碍物和装饰品,基本上是将你的游戏设计和构建成碎片。更多信息
请参阅术语表
.预制件对于创建可重用的组件很有用。视觉元素实例化或派生自 C# 的可视化树的节点VisualElement类。您可以设置外观样式、定义行为并将其作为 UI 的一部分显示在屏幕上。更多信息
请参阅术语表
在 UI Toolkit 中不是游戏对象,因此预制件不适用。但是,可以将自定义控件创建为可重用的 UI 组件,该组件使用逻辑封装元素的特定层次结构。由于 UI 工具包鼓励您将 UI 与游戏或应用程序代码分开,因此您可以使用 UXML 来定义结构,使用 USS 定义外观,并使用 C# 来定义自定义控件的逻辑。

创建可重用的 UI 组件

例如,假设您要创建一个纸牌游戏。您想要显示具有不同统计数据的卡片,例如生命和攻击。

示例卡
示例卡

可以创建名为CardElement显示角色的图像、生命和攻击统计数据,然后对游戏中的每张卡牌重复使用此自定义控件。

以下是实现此目的的一般步骤:

  1. 在 C# 中,声明名为 CardElement 的自定义元素类型

  2. 在 UXML 中,定义自定义控件的层次结构。您可以使用两种方法。这两种方法都支持实例化CardElement在 C# 和父 UXML 中。

  3. 查找对自定义控件的子元素的引用。

  4. 公开属性和方法,并将逻辑封装在自定义控件中,其方式与使用任何 C# 类的方式相同。

  5. 将自定义控件与游戏或应用程序代码连接起来。您还可以注册事件回调来实现用户交互。

UXML 优先方法

使用这种方法,您可以在层次结构 UXML 文档中包含自定义元素 CardElement,并在其直接下方声明其子元素,并将层次结构 UXML 文档用作模板。这种方法提供了一种更简单的解决方案,在层级UXML文档中具有固定的UI结构。

以下 C# 和 UXML 示例演示了如何使用 UXML 优先方法创建可重用的 UI。

创建自定义控件类

创建定义 CardElement 自定义控件的 C# 脚本。自定义控件类将图像和锁屏提醒值分配给 CardElement。

using UnityEngine;
using UnityEngine.UIElements;

// Define the custom control type.
[UxmlElement]
public partial class CardElement : VisualElement
{

    private VisualElement portraitImage => this.Q("image");
    private Label attackBadge => this.Q<Label>("attack-badge");
    private Label healthBadge => this.Q<Label>("health-badge");

    // Use the Init() approach instead of a constructor because 
    // we don't have children yet.
    public void Init(Texture2D image, int health, int attack)
    {
        portraitImage.style.backgroundImage = image;
        attackBadge.text = health;
        healthBadge.text = attack;
    }

    // Custom controls need a default constructor. 
    public CardElement() {}
}

定义自定义控件的层次结构

创建 UXML 文档 (CardElement.uxml) 定义 CardElement 的层次结构。此示例使用 USS 文件设置 CardElement 的样式。

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
    <Style src="CardElementUI.uss" />
    <CardElement> 
        <ui:VisualElement name="image" />
        <ui:VisualElement name="stats">
            <ui:Label name="attack-badge" class="badge" />
            <ui:Label name="health-badge" class="badge" />
        </ui:VisualElement>
    </CardElement> 
</ui:UXML>

将自定义控件连接到游戏

您可以通过以下方式将自定义控件连接到游戏:

  • 例示CardElement.uxml在父 UXML 文档中。您可以在 UI Builder 中在层次结构 UXML 和此 UXML 文档之间来回导航
  • 例示CardElement.uxmlCardElement来自 MonoBehaviour C# 脚本。在将CardElement添加到场景之前,必须先使用UQuery查找CardElement。

您调用Init()将自定义控件添加到场景中后。

UXML 优先方法的工作流程
UXML 优先方法的工作流程

您还可以添加与游戏相关的作,例如与元素交互的点击事件。

在父UXML中实例化

下面显示了 UXML 中实例化的示例:

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
    <ui:Template name="CardElement" src="CardElement.uxml"/>
    <ui:Instance template="CardElement"/>
    <ui:Instance template="CardElement"/>
    <ui:Instance template="CardElement"/>
</ui:UXML>

有关如何在游戏中渲染UXML文档的信息,请参阅在游戏视图中渲染UI

直接在 C 中实例化#

注意:出于学习目的,本页的示例代码使用 Resources 文件夹方法加载 UXML 文件,这很方便。但是,这种方法不能很好地扩展。建议使用其他方法加载生产项目的引用。

下面显示了 C# 中的实例化示例:

using UnityEngine;
using UnityEngine.UIElements;

public class UIManager : MonoBehaviour
{
    public void Start()
    {
        UIDocument document = GetComponent<UIDocument>();

        // Load the UXML document that defines the hierarchy of CardElement.
        // It assumes the UXML file is placed at the "Resources" folder.
        VisualTreeAsset template = Resources.Load<VisualTreeAsset>("CardElement");

        // Create a loop to modify properties and perform interactions 
        // for each card.  It assumes that you have created a function 
        // called `GetCards()` to get all the cards in your game.
        foreach(Card card in GetCards())
        {
            // Instantiate a template container.
            var templateContainer = template.Instantiate();

            // Find the custom element inside the template container.
            var cardElement = templateContainer.Q<CardElement>();

            // Add the custom element into the scene.
            document.rootVisualElement.Add(cardElement);

            // Initialize the card.
            cardElement.Init(card.image, card.health, card.attack);

            // Register an event callback for additional interaction.
            cardElement.RegisterCallback<ClickEvent>(SomeInteraction);
        }
    }

    private void SomeInteraction(ClickEvent evt)
    {
        // Interact with the elements here.
    }
}

元素优先方法

使用此方法,只需在层次结构 UXML 文档中包含子元素,并使用 C# 将层次结构 UXML 文档加载到 CardElement 类定义中。此方法为自定义控件提供了灵活的 UI 结构。例如,您可以根据特定条件加载不同的层次结构 UXML 文档。

以下C#和UXML示例演示了如何使用元素优先方法创建可重用的UI。

创建自定义控件类

创建定义 CardElement 自定义控件的 C# 脚本。除了定义构造函数以将图像和徽章值分配给 CardElement 之外,自定义控件还在其类定义中加载层次结构 UXML 文档。

using UnityEngine;
using UnityEngine.UIElements;

// Define the custom control type.
[UxmlElement]
public partial class CardElement : VisualElement
{
    private VisualElement portraitImage => this.Q("image");
    private Label attackBadge => this.Q<Label>("attack-badge");
    private Label healthBadge => this.Q<Label>("health-badge");

    // Custom controls need a default constructor. This default constructor 
    // calls the other constructor in this class.
    public CardElement() {}

    // Define a constructor that loads the UXML document that defines 
    // the hierarchy of CardElement and assigns an image and badge values.
    public CardElement(Texture2D image, int health, int attack)
    {
        // It assumes the UXML file is called "CardElement.uxml" and 
        // is placed at the "Resources" folder.
        var asset = Resources.Load<VisualTreeAsset>("CardElement");
        asset.CloneTree(this);

        portraitImage.style.backgroundImage = image;
        attackBadge.text = health.ToString();
        healthBadge.text = attack.ToString();
    }
}

注意:如果您有性能问题,请使用延迟初始化来保留字段以缓存引用,并避免过于频繁地重新评估查询。

定义自定义控件的层次结构

创建 UXML 文档 (CardElement.uxml) 定义 CardElement 子元素的层次结构。该示例使用 USS 文件设置 CardElement 的样式。

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
    <Style src="CardElementUI.uss" /> 
    <ui:VisualElement name="image" />
    <ui:VisualElement name="stats">
        <ui:Label name="attack-badge" class="badge" />
        <ui:Label name="health-badge" class="badge" />
    </ui:VisualElement>
</ui:UXML>

将自定义控件连接到游戏

可以通过执行以下作将自定义控件连接到游戏:

  • 例示CardElement.uxml在父 UXML 文档中。在 UI Builder 中,您无法在层次结构 UXML 和此 UXML 文档之间来回导航,因为子元素是从 C# 加载的。
  • 例示CardElement.uxmlCardElement来自 MonoBehaviour C# 脚本。

在将自定义控件添加到场景之前,调用构造函数。

元素优先方法的工作流程
元素优先方法的工作流程

您还可以添加与游戏相关的作,例如与元素交互的点击事件。

在父UXML中实例化

下面显示了 UXML 中实例化的示例:

<ui:UXML xmlns:ui="UnityEngine.UIElements" xmlns:uie="UnityEditor.UIElements" editor-extension-mode="False">
   <CardElement />
   <CardElement />
   <CardElement />
</ui:UXML>

有关如何在游戏中渲染UXML文档的信息,请参阅在游戏视图中渲染UI

直接在 C 中实例化#

下面显示了 C# 中的实例化示例:

using UnityEngine;
using UnityEngine.UIElements;

public class UIManager : MonoBehaviour
{
    public void Start()
    {
        UIDocument document = GetComponent<UIDocument>();

        // Create a loop to modify properties and perform interactions 
        // for each card. It assumes that you have created a function 
        // called `GetCards()` to get all the cards in your game.
        foreach(Card card in GetCards())
        {
            var cardElement = new CardElement(card.image, card.health, card.attack);

            // Register an event callback for additional interaction.
            cardElement.RegisterCallback<ClickEvent>(SomeInteraction);

            // Add the custom element into the scene.
            document.rootVisualElement.Add(cardElement);
        }
    }

    private void SomeInteraction(ClickEvent evt)
    {
        // Interact with the elements here.
    }
}

构建更复杂的元素

随着项目的 UI 变得越来越复杂,最好将逻辑隔离到更高级别的组件中。这使得游戏或应用程序的其余部分更容易编排 UI。

您可以应用本页上的概念,从更小、更通用的组件中逐步构建专用组件。例如,要构建一个主标题屏幕,用户可以从中访问 选项(Options) 菜单和 关于(About) 部分,你可以创建一个包含三个不同子UXML文档的TitleScreenManager元素。每个元素都定义了自己的元素:Title、Options 和 About。

主标题屏幕示例
主标题屏幕示例

其他资源

管理元素的最佳实践
视觉元素参考