实体定位
如何设置场景中实体的位置、旋转和缩放
你可以设置 位置, 旋转 和 缩放 任意实体的,方法是使用 Transform 组件。它可用于 3D 空间中的任何实体,并影响实体的渲染位置。这包括基本形状(立方体、球体、平面等)、3D 文本形状、NFT 形状和 3D 模型(GltfContainer).
在 Creator Hub 中使用场景编辑器
通过场景编辑器向场景添加项目时,它会隐式包含一个 Transform 组件。随后,通过更改实体的位置、旋转或缩放,你可以隐式更改实体 Transform 组件中的值。你还可以使用场景编辑器的 UI 以数值方式提供更精确的值。
代码基础

若要在一段时间内移动、旋转或调整场景中的实体大小,请逐帧增量地更改此组件中的值。参阅 移动实体 了解更多详情和最佳实践。
📔 注意: Vector3 和 Quaternion 必须通过以下方式导入
import { Vector3, Quaternion } from "@dcl/sdk/math"
参阅 导入 了解如何轻松处理这些内容。
位置
位置 是一个 三维向量,它设置实体中心在全部三个轴上的位置, x, y,以及 z。参阅 几何类型 了解更多详情。
设置位置时,请牢记以下注意事项:
位置向量中的数值表示 米 (除非该实体是经缩放实体的子实体)。
由单个地块组成的场景尺寸为 16m x 16m。场景中心(地面高度)位于
x:8, y:0, z:8。如果场景由多个地块组成,中心位置将取决于它们的排列方式。x:0, y:0, z:0指的是 西南 场景基础地块在地面高度的角落。提示:查看场景预览时,场景的 (0,0,0) 点会显示一个指南针,并标有各轴标签作为参考。
注意:你可以通过编辑
base的属性 scene.json.为了更好地确定方向,请使用你的 左 手:
你的食指(指向前方)是 z 轴
你的中指(指向侧方)是 x 轴
你的拇指(指向上方)是 y 轴。
如果一个实体是另一个实体的子实体,则
x:0, y:0, z:0指的是其父实体的中心,无论父实体位于场景中的何处。场景中的每个实体必须始终位于其所占地块的边界内。如果实体离开这些边界,将引发错误。
提示:在预览模式下查看场景时,超出边界的实体会以 红色.
场景的高度也有限制。无论占用多少地块,每个场景的最大高度均为 330 米。放置在 200 米以上的实体可能会出现多人同步问题。参阅 场景限制 了解更多详情。
旋转
旋转 存储为一个 四元数,即由四个数字组成的系统, x, y, z 和 w。这些数字中的每一个取值范围均为 -1 到 1。参阅 几何类型 了解更多详情。
你也可以使用以下方式设置旋转字段: 欧拉 角,这是一种更常见的 x, y 和 z 表示法,使用大多数人熟悉的 0 到 360 的数字。要使用欧拉角,请采用以下表示法之一:
使用一个 三维向量 来表示欧拉角时, x, y 和 z 表示该轴上的旋转,以度为单位。完整旋转一圈需要 360 度。
获取实体的旋转时,默认返回四元数。要获得以欧拉角表示的旋转,请使用 Quaternion.toEulerAngles():
获取实体的全局位置和旋转
该 getWorldPosition 和 getWorldRotation 函数会返回实体的全局位置和旋转。这意味着它会返回玩家看到该物品时所感知的位置或旋转,忽略任何父级层级结构。
getWorldPosition(engine, entity: Entity): Vector3Type:此函数会返回实体的世界位置,并考虑所有父实体的位置(如果实体本身有父实体),若{x: 0, y: 0, z: 0}实体没有 Transform,则返回该值。
getWorldRotation(engine, entity: Entity): QuaternionType:此函数会返回实体的世界旋转,并考虑所有父实体的旋转(如果实体本身有父实体)。它返回一个Quaternion类型,并返回单位四元数{x: 0, y: 0, z: 0, w: 1}实体没有 Transform,则返回该值。
面向玩家
添加一个 Billboard 组件到实体,使其始终旋转以面向玩家。
广告牌是 20 世纪 90 年代 3D 游戏中常用的一种技术,当时大多数实体都是始终面向玩家的 2D 平面。同样的理念也可用于旋转 3D 模型。
你可以通过以下参数配置广告牌的行为:
billboardMode:使用BillboardMode的值,以设置哪些旋转轴自动旋转来面向玩家:BillboardMode.BM_ALL:实体会在所有旋转轴上旋转以面向玩家。如果玩家位于实体上方很高处,实体将朝上。BillboardMode.BM_NONE:实体完全不会旋转。BillboardMode.BM_X:实体仅在其 x 旋转轴上旋转。BillboardMode.BM_Y:实体仅在其 y 旋转轴上旋转。它仅左右旋转,不会上下旋转。如果玩家位于实体上方或下方,它会保持垂直于地面。BillboardMode.BM_Z:实体仅在其 z 旋转轴上旋转。
targetEntity:(可选)广告牌旋转以面向的实体,而非玩家的摄像机。如果引用的实体不存在(例如尚未创建或已被移除),广告牌将停止旋转并保持最后的朝向,直到该实体再次存在。将此项设置为engine.CameraEntity等同于不设置它。
该 旋转 实体的 Transform 组件的值不会随着广告牌跟随玩家而改变。
如果一个实体同时拥有 Billboard 组件和 Transform 带有 旋转 值的组件,玩家将看到该实体像广告牌一样旋转。如果广告牌不影响所有轴,其余轴将根据 Transform 组件旋转。
📔 注意:如果同时存在多名玩家,每名玩家都会看到处于广告牌模式的实体面向自己。广告牌旋转会针对每名玩家在本地计算,且不会影响其他玩家所见的内容。这不适用于带有 targetEntity的广告牌:由于目标的位置是场景的一部分,所有玩家都会看到这些广告牌朝向相同方向。
面向一组坐标
使实体 A 面向实体 B:
缩放
缩放 也是一个 三维向量,存储为一个 Vector3 对象,包括各个 x, y 和 z 轴上的缩放因子。无论实体的形状是基本形状还是 3D 模型,都会相应地缩放。
默认缩放为 1,因此赋予大于 1 的值可拉伸实体,赋予小于 1 的值可缩小实体。
继承父级变换
当一个实体嵌套在另一个实体内时,子实体会继承父实体的组件。这意味着如果父实体被定位、缩放或旋转,其子实体也会受到影响。子实体的位置、旋转和缩放值不会覆盖父实体的值,而是会与之叠加。
通过设置子实体的 parent 字段,将一个实体指定为另一个实体的父实体 Transform 组件旋转。
如果父实体被缩放,其所有子实体的位置值也会被缩放。
在此示例中,子实体会缩小至 0.5,因为其父实体具有该缩放比例。子实体的位置也将相对于其父实体。我们必须将父实体的位置与子实体的位置相加。在本例中,由于父实体缩放为原来的一半,子实体的变换也会按比例缩小。以绝对坐标计,子实体位于 { x: 3, y: 1.5, z: 1 }。如果父实体具有 旋转,这也会影响子实体的最终位置,因为它会改变子实体偏移所依据的轴。
如果子实体的 Transform 上没有 位置 ,默认值为 0,0,0,这会使其保持在与父实体相同的位置。
你可以使用没有形状组件的不可见实体作为父实体,以包装一组其他实体。该实体不会在渲染的场景中可见,但可用于对其子实体进行分组,并对它们全部应用变换。
📔 注意:避免在层级结构中创建循环,即某个实体最终成为自己的祖先。SDK 会检测这些循环,并记录一条警告,注明涉及的实体。在修复父子关系之前,受影响的实体无法正确定位。
将实体附加到虚拟形象
有三种将实体附加到玩家的方法:
将其设为以下对象的子实体: 虚拟形象实体
将其设为以下对象的子实体: 摄像机实体
使用 AvatarAttach 组件
将实体附加到虚拟形象的最简单方法是将父级设置为 保留实体 engine.PlayerEntity。该实体随后将随玩家的位置一起移动。
你也可以将实体设为 保留实体 engine.CameraEntity。在第一人称模式下使用摄像机实体时,附加的实体将跟随摄像机的移动。这非常适合让某些物体始终保持在视野中,例如即使摄像机朝上,也始终让枪的 3D 模型保持在视野中。
要将对象附加到虚拟形象的一块骨骼上,并使其随虚拟形象的动画一起移动,请添加一个 AvatarAttach 组件到实体。
你可以在虚拟形象上选择不同的锚点,其中大多数点都与玩家的骨架关联,并跟随玩家的动画。例如,使用右手锚点时,附加的实体会在虚拟形象挥手或跑步时摆动手臂时移动,就像玩家正用手拿着该实体一样。
创建一个 AvatarAttach 组件时,传入包含以下数据的对象:
avatarId: 可选 要附加到的玩家 ID。对于使用以太坊钱包连接的玩家,此 ID 与玩家的以太坊地址相同。如果未指定,则将实体附加到本地玩家的虚拟形象。anchorPointId:使用枚举中的值,指定要将实体附加到虚拟形象骨架上的哪个锚点AvatarAnchorPointType.
📔 注意:如果你希望场景中的所有玩家都看到一个对象附加到同一位玩家,例如所有人都看到玩家 A 拾起一个物体并将其拿在左手上,那么你必须为 avatarId提供一个值。如果未指定,则所有玩家都会看到该对象附加到自己的虚拟形象上。
以下示例将一个实体附加到特定虚拟形象,以便所有其他玩家都看到它附加在该同一虚拟形象上。
以下锚点可用于 AvatarAnchorPointType 枚举:
AAPT_RIGHT_HAND:固定在玩家的右手上AAPT_LEFT_HAND:固定在玩家的左手上AAPT_HEAD:固定在玩家头部中心。AAPT_NECK:固定在玩家颈部底部。AAPT_SPINE:固定在脊柱上部。AAPT_SPINE1:固定在脊柱中部。AAPT_SPINE2:固定在脊柱下部。AAPT_HIP:固定在髋骨上。AAPT_LEFT_SHOULDER:固定在左肩上。AAPT_LEFT_ARM:固定在左侧第一块臂骨上,位于肩部高度。AAPT_LEFT_FOREARM:固定在左前臂骨上。AAPT_LEFT_HAND_INDEX:固定在左手食指指尖。AAPT_RIGHT_SHOULDER:固定在右肩上。AAPT_RIGHT_ARM:固定在右侧第一块臂骨上,位于肩部高度。AAPT_RIGHT_FOREARM:固定在右前臂骨上。AAPT_RIGHT_HAND_INDEX:固定在右手食指指尖。AAPT_LEFT_UP_LEG:固定在左腿上部的腿骨上。AAPT_LEFT_LEG:固定在左腿下部的腿骨上。AAPT_LEFT_FOOT:固定在左腿的脚踝上。AAPT_LEFT_TOE_BASE:固定在左腿脚趾尖上。AAPT_RIGHT_UP_LEG:固定在右腿上部的腿骨上。AAPT_RIGHT_LEG:固定在右腿下部的腿骨上。AAPT_RIGHT_FOOT:固定在右腿的脚踝上。AAPT_RIGHT_TOE_BASE:固定在右腿脚趾尖上。.AAPT_NAME_TAG:浮动在玩家姓名标签正上方,不受玩家动画影响。注意:姓名标签的高度会根据玩家所穿戴物品的高度动态调整。因此,戴着高帽子的玩家,其姓名标签会比其他人高一点。
AAPT_POSITION已弃用:玩家的整体位置。它显示在玩家脚下方 0.8 的高度处。
> **📔 注**:`AAPT_POSITION` 已弃用。要跟随玩家的整体位置,最好将实体设为 Avatar Entity 的子实体。示例请参见本节开头。 >

实体渲染由场景的每个实例本地决定。将实体附加到某个玩家身上,并不会让其他正在看到该玩家的玩家也看到它。如果实体附加到默认的本地玩家身上,每个玩家都会把该实体体验为附加在自己的头像上。
📔 注意:附加到头像上的实体必须保持在场景边界内才能被渲染。如果玩家走出你的场景,任何已附加的实体都会停止渲染,直到玩家重新走回场景中。智能穿戴物没有这个限制。
该 AvatarAttach 组件会覆盖以下 Transform 组件中的值。你放入 Transform 组件中的任何值都会被替换为该实体相对于玩家 Transform 的相对位置,这些值会随着玩家移动和动画逐帧更新。
如果你需要让实体相对于头像锚点带有偏移,或者使用不同的旋转或缩放,请通过父实体来实现。
创建一个不可见实体,只包含一个
Transform和一个AvatarAttach组件。其Transform值会随着玩家移动而被覆盖将你想附加的实体设为这个父实体的子实体。其
Transform值可以描述相对于锚点的偏移。
📔 注意:如果附加的实体带有碰撞体,这些碰撞体可能会阻挡玩家移动或造成抖动效果。你可能需要禁用附加实体碰撞体的物理层。参见 碰撞层
📔 注意:如果你有一个子实体,并且想知道它的全局位置和/或旋转,可以使用 getWorldPosition 和 getWorldRotation 函数。你可以在 获取全局位置和旋转 部分查看。
附加到其他玩家
你可以使用 AvatarAttach 组件将实体附加到另一位玩家。为此,你必须知道该玩家的 id。
要将实体附加到另一位玩家的头像上,你必须在字段 avatarId中提供该用户的 ID。获取这些数据有 多种方式 。
📔 注意:对于使用 Ethereum 钱包连接的玩家,他们的 userId 与其 Ethereum 地址相同。
获取 userId 为附近所有其他玩家的 getPlayer()
将它与 AvatarAttach一起使用时,你可以用以下代码在场景中每位其他玩家头顶添加一个悬浮立方体:
查看获取其他用户 ID 的其他方法,请参见 获取玩家数据.
场景边界
场景中的所有实体都必须位于场景边界内,因为边界外的区域是属于其他玩家的地块。
如果你的模型在预览运行时有任何部分超出这些限制,这些超出的部分将会被裁掉,并且不会被渲染,无论是在预览中还是在已发布的场景中都是如此。
场景中实体的位置在它们移动时会持续被检查,如果某个实体离开场景后又返回,它将被移除,然后再次正常渲染。
场景地面上的网格显示了场景的边界,默认情况下其范围在 x 和 z 轴上从 0 到 16,并在 y 轴上最高到 20。你可以自由地将实体放置在地下,在 y 轴。
最后更新于