> For the complete documentation index, see [llms.txt](https://docs.decentraland.org/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.decentraland.org/creator/content-creator-zh/chang-jing-sdk7/3d-nei-rong-ji-chu/colliders.md).

# 碰撞体

了解为实体赋予 3D 形状和碰撞的不同组件。

具有碰撞器的实体会占据空间并阻挡玩家的路径，没有碰撞器的实体则可以被玩家的头像穿过。

要让实体可点击也需要碰撞器。按钮事件基于实体的碰撞器形状，而不是其可见形状。

用于与玩家物理交互或与指针事件交互的碰撞层是分开的，碰撞器可以配置为只与其中一种交互。它们也可以配置为与自定义层交互，这些自定义层可以与 [光线投射](/creator/content-creator-zh/chang-jing-sdk7/3d-nei-rong-ji-chu/colliders.md) 一起使用，以便根据场景处理任何合适的内容。

{% hint style="warning" %}
**📔 注意**：碰撞器不会影响其他实体彼此之间的交互，实体始终可以重叠。碰撞设置只影响实体与玩家头像以及按钮事件的交互。Decentraland 没有原生物理引擎，所以如果你希望实体下落、碰撞或弹跳，必须在场景中编写这种行为，或者导入库来处理。
{% endhint %}

## 使用场景编辑器

管理实体碰撞器的最简单方法是使用 [场景编辑器](/creator/content-creator-zh/chang-jing-bian-ji-qi/kai-shi-shi-yong/about-editor.md).

你可以添加一个 **网格碰撞器** 组件到你的实体，为其指定一个基本形状（立方体、平面、球体、圆柱体或圆锥体）。然后你可以从下拉菜单中选择 [碰撞层](#collision-layers) 。

你还可以在一个 **GLTF** 组件上配置碰撞层，以更改默认的 [碰撞层](#collision-layers) 用于碰撞器几何体或模型可见几何体的默认值。参见 [添加组件](/creator/content-creator-zh/chang-jing-bian-ji-qi/gou-jian/components.md#add-components).

![](https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-a1566c33728b1ef858f518365390d2ce5c97fe82%2Fgltf-component.png?alt=media)

## 基础形状上的碰撞器

该 `MeshCollider` 组件会根据基础形状（盒子、球体、平面、圆柱体或圆锥体）为实体提供一个简单的碰撞器。

具有一个 `MeshRenderer` 组件来为它们提供一个 [基础形状](/creator/content-creator-zh/chang-jing-sdk7/3d-nei-rong-ji-chu/shape-components.md#primitive-shapes) 默认情况下没有碰撞器。你还必须为实体添加一个 `MeshCollider` 组件。

以下碰撞器形状可用于 `MeshCollider`。某些形状包含可选的附加字段，且各形状特定。

* **盒子**:

  使用 `MeshCollider.setBox()`，传入该实体。
* **平面**:

  使用 `MeshCollider.setPlane()`，传入该实体。
* **球体**:

  使用 `MeshCollider.setSphere()`，传入该实体。
* **圆柱体**:

  使用 `MeshCollider.setCylinder()`，传入该实体。传入 `radiusTop` 和 `radiusBottom` 作为额外的可选字段，以修改该圆柱体。

{% hint style="info" %}
**💡 提示**：将 `radiusTop` 或 `radiusBottom` 设为 0 可创建一个圆锥体。
{% endhint %}

此示例定义了一个不能被穿过的盒子实体。

```ts
// 创建实体
const myCollider = engine.addEntity()

// 可见形状
MeshRenderer.setBox(myCollider)

// 碰撞器
MeshCollider.setBox(myCollider)
```

该 `MeshCollider` 使用的形状不一定必须与 `MeshRenderer`使用的形状一致。你还可以将一个 `MeshCollider` 添加到一个具有来自 `GltfContainer` 组件的 3D 模型的实体，或者添加到一个完全没有可见形状的实体。

{% hint style="warning" %}
**📔 注意**： `MeshCollider` 组件和 `ColliderLayer` 必须通过

`import { MeshCollider, ColliderLayer } from "@dcl/sdk/ecs"`

参见 [导入](/creator/content-creator-zh/chang-jing-sdk7/ru-men/coding-scenes.md#imports) 了解如何轻松处理这些。
{% endhint %}

## 3D 模型上的碰撞器

3D 模型可以在两个不同的几何层级上分配碰撞器：

* `visibleMeshesCollisionMask`: 指代模型的可见几何体。默认情况下，这种几何体没有碰撞器。
* `invisibleMeshesCollisionMask`: 指代碰撞器网格，其名称以 `_collider`结尾。默认情况下，这种几何体会被视为同时用于物理和指针事件的碰撞器。

嵌入在 3D 模型中的任何网格，只要其名称以 `_collider` 结尾，就会被视为 `invisibleMeshesCollisionMask` 层的一部分，并且默认会被解释为碰撞器。

将碰撞器几何体定义为单独的不可见层，可以带来更大的控制力，而且比使用可见几何体对系统的负担要小得多，因为碰撞对象通常比原始模型简单得多（顶点更少）。

如果模型没有任何碰撞器几何体，而你希望让它影响物理或指针事件系统，你可以：

* 直接通过 `visibleMeshesCollisionMask`.

{% hint style="warning" %}
**📔 注意**: 如果对象的可见几何体有很多顶点，请注意这可能会带来更高的性能开销。
{% endhint %}

* 为实体添加一个 `MeshCollider` 组件，为其提供一个基础形状碰撞器。
* 叠加一个不可见实体，该实体具有一个 `MeshCollider` 组件。
* 在 Blender 等外部工具中编辑模型，以包含一个 *碰撞器网格*。碰撞器必须命名为 *x\_collider*，其中 *x* 是模型的名称。因此，对于名为 *house*的模型，碰撞器必须命名为 *house\_collider*.

你可能还想将指针事件碰撞层分配给 `visibleMeshesCollisionMask` ，以便悬停提示和指针事件能更准确地响应实体轮廓。请注意，这会对性能要求更高。

{% hint style="warning" %}
**📔 注意**: 请确保没有将相同的层（物理、指针事件或自定义层）同时分配给 `visibleMeshesCollisionMask` 和 `invisibleMeshesCollisionMask`，因为那样会非常低效地使用资源。你可以让二者使用不同的层，例如不可见层使用物理层，可见层使用指针事件层。
{% endhint %}

```ts
// 创建实体
const myEntity = engine.addEntity()

// 分配 GLTF 形状
GltfContainer.create(myEntity, {
	src: '/models/myModel.gltf',
	invisibleMeshesCollisionMask: ColliderLayer.CL_PHYSICS,
	visibleMeshesCollisionMask: ColliderLayer.CL_POINTER,
})
```

参见 [3D 模型](https://github.com/decentraland/docs-creator/blob/main/creator/3d-modeling/3d-models/README.md) 了解更多关于如何为 3D 模型添加碰撞器不可见几何体的更多细节。

{% hint style="warning" %}
**📔 注意**： `GltfContainer` 组件和 `ColliderLayer` 必须通过

> `import { GltfContainer, ColliderLayer } from "@dcl/sdk/ecs"`

参见 [导入](/creator/content-creator-zh/chang-jing-sdk7/ru-men/coding-scenes.md#imports) 了解如何轻松处理这些。
{% endhint %}

### 动画模型

当为包含 [基于骨架的动画](/creator/content-creator-zh/3d-jian-mo-he-dong-hua/animations.md)的模型设置使用可见几何体的碰撞器时，动画不会被碰撞器跟随。碰撞器网格会保持其原始形状。如果动画涉及变形网格的几何体，动画播放时，碰撞器网格会保留未动画化的形状。

当播放涉及移动整个网格但不改变其形状的动画时，这些变化会被碰撞器准确反映。例如，如果平台作为动画的一部分移动，那么平台的碰撞器也会随动画移动。

## 碰撞层

场景可以处理具有不同行为的独立碰撞层。

你可以配置一个 `MeshCollider` 组件或 `GltfContainer` 组件，使其只响应一种交互、几种交互或者不响应任何交互。为此，在 `MeshCollider` 上设置 `collisionMask` 属性，并在 `GltfContainer` 上设置 `visibleMeshesCollisionMask` 或 `invisibleMeshesCollisionMask` 属性上设置以下一个或多个值：

* `ColliderLayer.CL_PHYSICS`：阻挡玩家移动（场景墙壁、地板、平台）。不影响指针事件。
* `ColliderLayer.CL_POINTER`：只响应指针事件。不阻挡玩家移动。
* `ColliderLayer.CL_PLAYER`：将碰撞器标记为头像标记。以 `CL_PLAYER` 为目标的光线投射和触发区域会检测到它，但玩家胶囊会直接穿过它（没有物理阻挡）。在场景网格上，这可用于将网格标记为“仅用于检测的类头像目标”。
* `ColliderLayer.CL_MAIN_PLAYER`：与 `CL_PLAYER`类似，但仅针对本地玩家。掩码中带有 `CL_MAIN_PLAYER` 的光线投射和触发区域会检测到它；远程头像的光线投射/触发区域则不会。
* `ColliderLayer.CL_CUSTOM1` 到 `CL_CUSTOM8`：可与光线投射和触发区域一起使用，只检测特定自定义层上的碰撞。
* `ColliderLayer.CL_NONE`：不响应任何类型的碰撞。

{% hint style="info" %}
**💡 提示**: `CL_PLAYER` 和 `CL_MAIN_PLAYER` 在一个 `MeshCollider` / `GltfContainer` 中是 **仅检测** 层——玩家胶囊会穿过它们。如果你希望网格既可被检测为头像，又能实际阻挡玩家，请将头像层与 `CL_PHYSICS` （例如 `CL_PHYSICS | CL_MAIN_PLAYER`).
{% endhint %}

{% hint style="warning" %}
**📔 注意**：要禁用 `MeshCollider` 组件的碰撞，请删除该组件。不要将碰撞层设置为 `ColliderLayer.CL_NONE`。 `MeshCollider` 组件存在一个已知问题。不要通过禁用所有碰撞来处理，它会将该值等同于默认值（`ColliderLayer.CL_PHYSICS | ColliderLayer.CL_POINTER`).
{% endhint %}

```ts
// 创建实体
const myEntity = engine.addEntity()
// 可见形状
MeshRenderer.setBox(myEntity)

// 创建一个仅响应玩家物理的 MeshCollider 组件
MeshCollider.setBox(myEntity, ColliderLayer.CL_PHYSICS)
```

单个碰撞掩码可以响应多个碰撞层。使用 `|` 字符作为 *或*，以包含尽可能多的层。MeshCollider 的默认值是 `ColliderLayer.CL_PHYSICS | ColliderLayer.CL_POINTER`.

```ts
MeshCollider.setBox(
	myEntity,
	ColliderLayer.CL_CUSTOM1 |
		ColliderLayer.CL_CUSTOM3 |
		ColliderLayer.CL_PHYSICS |
		ColliderLayer.CL_POINTER
)
```

你可以将 8 个不同的自定义层用于最适合你场景的用途，例如一个可用于 NPC 视线计算，另一个可用于估算下落物体的轨迹。为不同系统使用不同的层可以减少资源消耗，因为在每种情况下，你只需检查与相关实体的碰撞。

参见 [光线投射](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/raycasting.md) 了解更多关于如何使用自定义碰撞层。

### 摄像机和碰撞器

当玩家的摄像机在第三人称模式下移动时，摄像机可能会被碰撞器阻挡，也可能不会，这取决于分配给实体的碰撞层。设计场景时要注意这一点，你可能希望防止摄像机穿过墙壁或其他实体。

要避免摄像机穿过墙壁，你必须同时将 `ColliderLayer.CL_PHYSICS` 和 `ColliderLayer.CL_POINTER` 层分配给你希望阻挡摄像机的实体。重要的是这两个层都分配给实体上的同一几何体。因此，如果你把 `ColliderLayer.CL_PHYSICS` 层分配给实体的可见层，你也必须把 `ColliderLayer.CL_POINTER` 层分配给同一几何体。

例如，在 Creator Hub 中，以下设置组合将阻止摄像机穿过墙壁：

![](https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-426b56fda6516e2c2e63296a534d02aa089a566e%2Fcolliders-camera.png?alt=media)

这两个 `ColliderLayer.CL_PHYSICS` 和 `ColliderLayer.CL_POINTER` 层都分配给了实体几何体的同一不可见层。如果它们都分配给可见层，结果也会相同。这是默认行为，无论是通过 Creator Hub 还是通过代码添加实体都是如此。

![](https://2460066822-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FoPnXBby9S6MrsW83Y9qZ%2Fuploads%2Fgit-blob-6c77ca6fce6934f939ce70f2146d972718a25556%2Fcolliders-no-camera.png?alt=media)

在第二个示例中，摄像机可以穿过墙壁，因为 `ColliderLayer.CL_PHYSICS` 层分配给了实体的不可见层，而 `ColliderLayer.CL_POINTER` 层分配给了实体的可见层，即使这两种几何体的总体形状相同。

```ts
// 不会让摄像机穿过墙壁
// 默认（指针和物理都使用不可见几何体）
GltfContainer.create(myEntity, {
	src: '/models/myModel.gltf',
})

// 不会让摄像机穿过墙壁
// 两者都使用同一不可见几何体
GltfContainer.create(myEntity2, {
	src: '/models/myModel.gltf',
	invisibleMeshesCollisionMask:
		ColliderLayer.CL_PHYSICS | ColliderLayer.CL_POINTER,
})

// 不会让摄像机穿过墙壁
// 两者都使用同一可见几何体
GltfContainer.create(myEntity2, {
	src: '/models/myModel.gltf',
	visibleMeshesCollisionMask:
		ColliderLayer.CL_PHYSICS | ColliderLayer.CL_POINTER,
})

// 会让摄像机穿过墙壁
// 物理和指针位于不同层
GltfContainer.create(myEntity2, {
	src: '/models/myModel.gltf',
	invisibleMeshesCollisionMask: ColliderLayer.CL_PHYSICS,
	visibleMeshesCollisionMask: ColliderLayer.CL_POINTER,
})

// 会让摄像机穿过墙壁
// 物理和指针位于不同层
GltfContainer.create(myEntity2, {
	src: '/models/myModel.gltf',
	invisibleMeshesCollisionMask: ColliderLayer.CL_POINTER,
	visibleMeshesCollisionMask: ColliderLayer.CL_PHYSICS,
})
```

### 指针阻挡

只有具有碰撞器的形状才能被 [指针事件](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/an-niu-shi-jian/click-events.md)激活。实体也需要有碰撞器来阻止指针事件穿过它并防止击中其后方的实体。因此，例如，如果箱子周围有碰撞器，玩家就不能拾取锁在箱子里的东西。玩家的指针事件只受该层中处于活动状态的网格影响。 `ColliderLayer.CL_POINTER` 层。

默认情况下，MeshCollider 会同时影响 Physics 和 Pointer 两个层，但你可以将此值更改为只影响其中一个、都不影响，或改为影响自定义层。你也可以用同样的方式配置可见几何体层。

{% hint style="warning" %}
**📔 注意**除碰撞器外，实体还需要有一个 `PointerEvents` 组件才能响应指针事件。 `pointerEventsSystem` 辅助函数也会负责处理这个要求。
{% endhint %}

```ts
// 仅响应玩家物理
// 例如一个你无法走过去但可以点击穿过的不可见墙
MeshCollider.setBox(myEntity, ColliderLayer.CL_PHYSICS)

// 仅响应玩家指针
// 例如一个可以点击拾取但可以直接走过去的物品
MeshCollider.setBox(myEntity2, ColliderLayer.CL_POINTER)
```

默认情况下， `GltfContainer` 的可见几何体不会映射到任何碰撞层，但不可见几何体会影响 Physics 和 Pointer 两个层。你可以将此值更改为只影响其中一个、都不影响，或改为影响自定义层。你也可以用同样的方式配置可见几何体层。

```ts
// 默认（指针和物理都使用不可见几何体）
GltfContainer.create(myEntity, {
	src: '/models/myModel.gltf',
})

// 玩家物理使用更简单的不可见几何体
// 指针事件使用可见几何体更完整、更精细的轮廓
GltfContainer.create(myEntity2, {
	src: '/models/myModel.gltf',
	invisibleMeshesCollisionMask: ColliderLayer.CL_PHYSICS,
	visibleMeshesCollisionMask: ColliderLayer.CL_POINTER,
})

// 玩家物理和指针事件都使用可见几何体更完整、更精细的轮廓
// 将更简单的不可见几何体映射为 ColliderLayer.CL_NONE，以避免同时计算两者
GltfContainer.create(myEntity, {
	src: '/models/myModel.gltf',
	invisibleMeshesCollisionMask: ColliderLayer.CL_NONE,
	visibleMeshesCollisionMask:
		ColliderLayer.CL_POINTER | ColliderLayer.CL_PHYSICS,
})

// 不对任何类型的碰撞作出响应，无论是可见几何体还是不可见几何体：
GltfContainer.create(myEntity, {
	src: '/models/myModel.gltf',
	invisibleMeshesCollisionMask: ColliderLayer.CL_NONE,
})
```

## 高级 MeshCollider 语法

创建 `MeshCollider` 组件的完整语法，不借助任何简化它的辅助函数，如下所示：

```ts
MeshCollider.create(myBox, {
	mesh: {
		$case: 'box',
		box: {},
	},
})

MeshCollider.create(myPlane, {
	mesh: {
		$case: 'plane',
		plane: {},
	},
})

MeshCollider.create(myShpere, {
	mesh: {
		$case: 'sphere',
		sphere: {},
	},
})

MeshCollider.create(myCylinder, {
	mesh: {
		$case: 'cylinder',
		cylinder: {},
	},
})
```

这就是基础协议解析 MeshCollider 组件的方式。辅助函数将其抽象掉，并提供更友好的语法，但它们在后台输出的就是这种语法。

该 `$case` 字段允许你指定一种允许的类型。每种类型都支持不同的一组参数。

对 `$case` 支持的值如下：

* `盒子`
* `平面`
* `球体`
* `圆柱体`

根据 `$case`的值，定义相应形状的对象并传入任何相关属性都是有效的。


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.decentraland.org/creator/content-creator-zh/chang-jing-sdk7/3d-nei-rong-ji-chu/colliders.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
