> 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/ru-men/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\&token=43fa7d3f-2ed6-48b5-9fcd-842c8a75c4dc)

## 基本形状上的碰撞体

该 `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/blob/main/creator/3d-modeling/3d-models.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-yu-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`，但仅针对本地玩家。mask 中包含 `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\&token=7e7dbaa9-0e4f-47b7-8efe-13456cb1761b)

这两个 `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\&token=63d0c60e-c267-45df-a44a-f2c5c58f37b7)

在第二个示例中，相机可以穿过墙壁，因为 `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` 组件才能响应指针事件。The `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 by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

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

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

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.
