包含此页的版本:
不含此页的版本:
此示例演示如何动态设置视觉元素实例化或派生自 C# 的可视化树的节点VisualElement类。您可以设置外观样式、定义行为并将其作为 UI 的一部分显示在屏幕上。更多信息
请参阅术语表在运行时。在运行时移动元素的推荐最佳实践是使用style.translate并将DynamicTransform移动元素上的用法提示。这种方法对于性能来说是最佳的,因为它可以避免弄脏布局,并将更新限制在转换阶段。有关更多信息,请参阅在运行时优化移动元素的性能。
此示例创建了一个预制件:一种资产类型,允许您存储包含组件和属性的游戏对象。预制件充当模板,你可以从中在场景中创建新的对象实例。更多信息
请参阅术语表在场景场景包含游戏的环境和菜单。将每个唯一的场景文件视为一个独特的关卡。在每个场景中,你放置你的环境、障碍物和装饰品,基本上是将你的游戏设计和构建成碎片。更多信息
请参阅术语表.预制件表示在指定范围内随机移动的非玩家角色 (NPC)。NPC 后面有一个名称标签,并根据与相机在场景中创建特定视点图像的组件。输出要么绘制到屏幕上,要么作为纹理捕获。更多信息
请参阅术语表.
您可以在此 GitHub 存储库中找到此示例创建的已完成文件。
本指南适用于熟悉 Unity 编辑器、UI 工具包和 C# 脚本的开发人员。在开始之前,请熟悉以下内容:
在项目中创建一个UXML,并在其中定义一个VisualElement。VisualElment 充当您计划在运行时动态移动的任何子元素的父容器。
Assets文件夹(项目选项卡)更多信息UI以存储 UXML 和 USS 文件。UI文件夹中,创建一个名为NameTagContainer.uxml.NameTagContainer.uxml文件以在 UI Builder 中打开它。BaseContainer.完成的NameTagContainer.uxml文件如下所示:
<engine:UXML xmlns:engine="UnityEngine.UIElements" >
<engine:VisualElement name="BaseContainer" style="flex-grow: 1;" />
</engine:UXML>
创建一个 USS 文件来设置名称标签的样式,并创建一个 UXML 文件来定义名称标签模板。名称标签模板是一个 Label 元素,用于显示 NPC 的名称。名称标签跟随场景中的 NPC。
在UI文件夹中,创建一个名为NameTag.uss内容如下:
#NameTag {
/* This sets the position of the Label element to be absolute, rather than relative to the parent container. */
position: absolute;
/* This ensures that the pivot point of the Label element is centered, rather than in the top left corner.*/
translate: -50% -50%;
-unity-font-style: bold;
color: rgb(181, 210, 248);
-unity-text-outline-width: 1px;
-unity-text-outline-color: rgb(11, 60, 123);
}
在UI文件夹中,创建一个名为NameTag.uxml.
双击NameTag.uxml文件以在 UI Builder 中打开它。
将标签添加到“层次结构”面板并将其命名NameTag.
在检查器一个Unity 窗口,显示有关当前选定游戏对象、资产或项目设置的信息,允许您检查和编辑值。更多信息
请参阅术语表面板中,请执行以下作:
NPC. 此值表示 NPC 的名称。Ignore. 这可以防止 Label 元素响应鼠标事件,这对性能来说更优化。在“样式表”面板中,选择“+”>“添加现有 USS”。
按照说明添加NameTag.uss文件。
检查视口用户在屏幕上应用的可见区域。
在术语表中查看. 这translate: -50% -50%style 将 Label 元素的枢轴点居中,使其显示在视口的左上角。这是预期行为。名称标签将相对于 NPC 定位游戏对象Unity 场景中的基本对象,可以表示角色、道具、风景、相机、航路点等。游戏对象的功能由附加到它的组件定义。更多信息
请参阅术语表在场景中。

保存您的更改。
完成的NameTag.uxml文件可能如下所示:
<engine:UXML xmlns:engine="UnityEngine.UIElements">
<Style src="NameTag.uss" />
<engine:Label text="NPC" name="NameTag" picking-mode="Ignore" />
</engine:UXML>
创建一个RandomMovement处理 NPC 预制件随机移动的类。NPC 在指定范围内移动,并在到达边界时改变方向。
将DynamicTransform移动元素上的使用提示以优化性能。
注意:建议的最佳实践是将使用提示应用于转换后的元素,在本例中是名称标记模板容器,而不是子标签。
Scripts以存储 C#脚本一段代码,允许您创建自己的组件、触发游戏事件、随时间修改组件属性以及以您喜欢的任何方式响应用户输入。更多信息Scripts文件夹中,创建一个名为RandomMovement.cs内容如下:using UnityEngine;
using Random = UnityEngine.Random;
public class RandomMovement : MonoBehaviour
{
public float moveSpeed;
public float movementRange;
public Vector3 targetPosition;
private float m_PositionY;
// Initialize the starting position and target position of the GameObject.
void Start()
{
m_PositionY = transform.position.y;
targetPosition = new Vector3(0, m_PositionY, 0);
}
// Updates the position of the GameObject at fixed intervals.
// Move the GameObject towards the target position, and sets a new random target position when the current target is reached.
void FixedUpdate()
{
if (transform.position != targetPosition)
{
transform.position = Vector3.MoveTowards(transform.position, targetPosition, moveSpeed * Time.deltaTime);
}
else
{
targetPosition = new Vector3(Random.Range(-movementRange, movementRange), m_PositionY, Random.Range(-movementRange, movementRange));
}
}
}
创建一个MovingNameTag管理名称标签的位置和比例的类。名称标签跟随场景中的 NPC 游戏对象。名称标签根据与摄像机的距离进行缩放,当名称标签距离太远或在摄像机后面时,该名称标签会被剔除。
Scripts文件夹中,创建一个名为MovingNameTag.cs内容如下:using System;
using UnityEngine;
using UnityEngine.UIElements;
public class MovingNameTag : MonoBehaviour
{
[SerializeField]
VisualTreeAsset m_NameTagTemplate;
[SerializeField]
UIDocument m_BaseContainerDocument;
[SerializeField]
Transform m_UITransform;
[SerializeField]
float m_ScaleMultiplier;
[SerializeField]
float m_DistanceCullingRange;
VisualElement m_Root;
VisualElement m_BaseContainer;
VisualElement m_NpcNameTag;
Camera m_MainCamera;
void Awake()
{
m_MainCamera = Camera.main;
m_BaseContainer = m_BaseContainerDocument.rootVisualElement.Q<VisualElement>("BaseContainer");
m_NpcNameTag = m_NameTagTemplate.Instantiate();
// Set DynamicTransform hint on the moving element to optimize performance.
m_NpcNameTag.usageHints = UsageHints.DynamicTransform;
m_BaseContainer.Add(m_NpcNameTag);
m_NpcNameTag.style.position = new StyleEnum<Position>(Position.Absolute);
}
void Update()
{
SetNameTagPositionAndScale();
}
void SetNameTagPositionAndScale()
{
var cameraSpaceLocation = GetCameraSpaceLocation(m_UITransform);
// Use style.translate to set the position of the name tag.
m_NpcNameTag.style.translate = new Translate(cameraSpaceLocation.x, cameraSpaceLocation.y);
// Get distance of NPC from camera.
var distance = Vector3.Distance(m_UITransform.position, m_MainCamera.transform.position);
// Calculate 1/distance so the name tag get smaller as the distance gets bigger.
var scale = 1 / distance * m_ScaleMultiplier;
m_NpcNameTag.style.scale = new Scale(new Vector2(scale, scale));
// Display name tag based on whether it's in front of the camera and within culling range.
if (cameraSpaceLocation.z < 0 || distance > m_DistanceCullingRange)
{
m_NpcNameTag.style.display = DisplayStyle.None;
}
else
{
m_NpcNameTag.style.display = DisplayStyle.Flex;
}
}
Vector3 GetCameraSpaceLocation(Transform objectTransform)
{
// Get the size of the parent visual element of the name tag.
var containerSize = m_BaseContainer.layout.size;
var screenPoint = m_MainCamera.WorldToViewportPoint(objectTransform.position);
var output = new Vector3(screenPoint.x * containerSize.x, (1 - screenPoint.y) * containerSize.y, screenPoint.z);
return output;
}
}
创建一个SortElements类,根据名称标签的比例对名称标签进行排序,该比例基于它们所遵循的物体的距离。
Scripts文件夹中,创建一个名为SortElements.cs内容如下:using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UIElements;
public class SortElements : MonoBehaviour
{
[SerializeField]
UIDocument m_MovingElements;
VisualElement m_BaseContainer;
MovingNameTag[] m_MovingNameTags;
void Start()
{
m_MovingNameTags = FindObjectsByType<MovingNameTag>(FindObjectsSortMode.None);
m_BaseContainer = m_MovingElements.rootVisualElement.Q<VisualElement>("BaseContainer");
}
void Update()
{
m_BaseContainer.Sort(CompareOrder);
}
static int CompareOrder(VisualElement x, VisualElement y)
{
// Compare the scale of the visual elements in the base container, which is
// determined by the distance of the object it follows in the MovingNameTag component
return x.style.scale.value.value.x.CompareTo(y.style.scale.value.value.x);
}
}
使用地板和 UI 文档游戏对象设置场景。地板是表示场景地板的平面游戏对象。
UI 文档游戏对象是包含运行时移动的视觉元素的 UI。UI 包含SortElements组件,它根据名称标签的比例对名称标签进行排序。
在 SampleScene 中,添加名为Floor.
将材质添加到地板。
在“层次结构”窗口中,选择“UI 工具包”>“UIDocument”,并将其命名为UI.
在 UI 文档游戏对象的 Inspector 窗口中,执行以下作:
NameTagContainer.SortElements元件。在“对元素排序”组件字段中,将“移动元素”设置为UI.这使得SortElements组件引用 UI 文档组件,而 UI 文档组件又引用NameTagContainer源资产。
创建一个在指定范围内随机移动的 NPC 预制件。它包含三个子游戏对象:
UI_NameTag代表 NPC 后面的名牌UI_Transform表示姓名标签的位置这UI_TransformGameObject 充当名称标签的参考点。 这MovingNameTag组件根据UI_TransformGameObject 中。这种设置允许更好的组织和灵活性。如果您需要调整名称标签的位置,只需修改UI_TransformGameObject 的位置,而不会影响 NPC GameObject 或其他组件。
在 SampleScene 中,创建一个名为NPC.
在 Inspector 窗口中NPCGameObject,添加RandomMovement元件。 该组件管理 NPC 的随机移动。
在“随机移动”组件字段中,执行以下作:
将速度设置为2. 该值决定了 NPC 移动的速度。
将范围设置为10. 该值决定了 NPC 移动的范围。
注意:随机移动组件包含一个目标位置一个关节属性,用于设置关节的驱动力应将其移动到的目标位置。更多信息
请参阅术语表字段,表示 NPC 的下一个目标位置,在脚本中随机设置。该字段主要用于调试目的,不需要手动设置。
NPC 预制件包含三个子游戏对象:一个胶囊游戏对象和两个游戏对象。
Capsule GameObject 表示场景中的 NPC。一个 GameObject 表示 NPC 后面的名称标签。第二个 GameObject 表示名称标签相对于 NPC 的位置。此 GameObject 充当名称标签的参考点或锚点,定义名称标签相对于 NPC 的位置。
右键单击NPCGameObject 并选择“创建空”以添加子游戏对象并将其命名为UI_NameTag.
添加MovingNameTag组件添加到UI_NameTagGameObject 的 GameObject 中。此组件管理名称标签的位置和比例。
在“移动名称标记”组件字段中,执行以下作:
NameTag.UI (UI Document).此值表示在运行时移动的 UI 元素的容器。UI_Transform.此值表示名称标签的位置。50.此值根据与摄像机的距离缩放名称标签。20.当名称标签距离太远或在摄像机后面时,此值会剔除名称标签。右键单击NPCGameObject,然后选择 3D Object > Capsule 以添加子 Capsule GameObject。然后将其 Y 位置设置为1这样它就不会夹在地板平面上。
将所需的材质添加到 Capsule 游戏对象,例如蓝色表面材质(如果有)。
右键单击NPCGameObject 并选择“创建空”以添加另一个空子游戏对象并将其命名UI_Transform.
在 Inspector 窗口中UI_TransformGameObject,选择右上角的箭头图标,然后为其选择一个图标。此图标可让您轻松识别场景视图:您正在创建的世界的交互式视图。您可以使用场景视图来选择和定位场景、角色、摄像机、灯光和所有其他类型的游戏对象。更多信息
请参阅术语表用于调试目的。
![]()
在 Inspector 窗口中UI_TransformGameObject,将位置设置为(0, 3, 0).此值表示名称标签相对于 NPC 游戏对象的位置。
复制 NPC 预制件以在场景中创建多个 NPC。名称标签跟随 NPC,并根据与摄像机的距离进行缩放。
NPCGameObject 并选择“复制”。