> 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/jiao-hu-xing/an-niu-shi-jian/register-callback.md).

# 注册回调

了解如何处理场景中的用户点击。

处理按钮事件最简单的方法，是为某个实体注册一个回调函数。每当使用特定按钮与该实体交互时，就会调用这个回调函数。

如果你需要为多个相似实体添加相同的行为，可以考虑使用 [基于系统的](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/an-niu-shi-jian/system-based-events.md) 方法，而不是为每个实体添加回调。随着你遍历相似实体列表，基于系统的方法通常会更高效。

注册回调的方法尤其适合用来描述影响单个实体的行为，因为它更直接。

{% hint style="warning" %}
**📔 注意**：\
要让一个实体可交互，它 **都必须** 必须有一个 [碰撞体](/creator/content-creator-zh/chang-jing-sdk7/3d-nei-rong-ji-chu/colliders.md)。参见 [障碍物](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/an-niu-shi-jian/click-events.md#obstacles) 了解更多详情。
{% endhint %}

## 指针按下

使用 `pointerEventsSystem.onPointerDown()` 以检测特定按钮的按下。

该语句需要两个参数：

* `数据`：包含以下内容的对象：
  * `实体`：要处理的实体
  * `opts`：一个带有可选附加数据的对象：
    * `button`：要监听哪个按钮。参见 [指针按钮](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/an-niu-shi-jian/click-events.md#pointer-buttons) 了解受支持的选项。如果未指定按钮，则会监听所有按钮，包括前进和跳跃之类的移动按钮。
    * `maxDistance`：实体与玩家 **化身**之间的最大距离，单位为米。默认值为 10。参见 [距离限制](#distance-limits).
    * `maxCameraDistance`：实体与 **活动摄像机**之间的最大距离，单位为米。默认未设置。参见 [距离限制](#distance-limits).
    * `hoverText`：在悬停反馈提示中显示的字符串内容。默认值为“交互”。
    * `showFeedback`：如果为 false，则会同时隐藏该实体的悬停提示和边缘高亮。 *true* 。
    * `showHighlight`：如果为 true，当玩家将光标悬停在实体上时，会看到边缘高亮。 *true* 默认值。仅当 `showFeedback` 为 *true*.
* `cb`：每当指向实体时发生按下按钮事件，就运行一次的回调函数

```ts
pointerEventsSystem.onPointerDown(
	{
		entity: myEntity,
		opts: { button: InputAction.IA_PRIMARY, hoverText: '点击' },
	},
	function () {
		console.log('已点击实体')
	}
)
```

上述命令会保留已注册的回调函数，并且每次发生相关按钮事件时都会调用它。请注意，回调必须是同步函数； `异步` 函数在这里不受支持，并且会导致错误。

{% hint style="warning" %}
**📔 注意**：\
只有一个 `pointerEventsSystem.onPointerDown` 可以按实体注册。添加后，它会一直监听事件，直到监听器被移除。不要在系统中反复运行此操作，否则会不断重写指针事件行为。
{% endhint %}

## 悬停反馈

让玩家知道某个实体可以交互，这一点非常重要。

当使用 `EventsSystem`注册输入动作时，默认情况下玩家将看到：

* 实体上的边缘高亮
* 光标附近的一个悬停提示，带有他们需要按下的按钮图标，以及显示“Interact”的字符串。

这些元素都可以切换开关并自定义。

UI 上的悬停反馈会根据你在 `button` 字段中选择的输入而显示不同的图标。在 PC 上，它会显示一个 `E` 用于 `InputAction.IA_PRIMARY`，一个 `F` 用于 `用于`InputAction.IA\_SECONDARY `的鼠标，以及一个鼠标用于`.

通过修改 `hoverText` 值来更改字符串。保持此字符串简短，以便快速阅读，并且不会对屏幕造成太大干扰。

```ts
pointerEventsSystem.onPointerDown(
	{
		entity: myEntity,
		opts: { button: InputAction.IA_PRIMARY, hoverText: '打开门' },
	},
	function () {
		// 打开门
	}
)
```

要隐藏悬停提示但保留边缘高亮，请将 `hoverText` 的值设为“”。

```ts
pointerEventsSystem.onPointerDown(
  {entity: myEntity, opts: { button: InputAction.IA_PRIMARY, hoverText: ''}},
  function () {
    console.log("点击了意外的可交互物品")
  }
)
```

要隐藏边缘高亮但保留悬停提示，请设置 `showHighlight` 为 *false*.

```ts
pointerEventsSystem.onPointerDown(
	{
		entity: myEntity,
		opts: {
			button: InputAction.IA_PRIMARY,
			hoverText: '打开门',
			showHighlight: false,
		},
	},
	function () {
		console.log('已打开秘密门')
	}
)
```

要同时隐藏悬停提示和边缘高亮，请设置 `showFeedback` 为 *false*。执行此操作时，光标不会显示任何图标、文本或边缘高亮。

```ts
pointerEventsSystem.onPointerDown(
  {entity: myEntity, opts: { button: InputAction.IA_PRIMARY, showFeedback: false}},
  function () {
    console.log("已打开秘密门")
  }
)
```

### 更改现有反馈

当使用 `EventsSystem`，这会在后台创建一个 `PointerEvents` 组件并将其添加到可交互实体中。该组件负责处理 UI 悬停提示的行为。要更改悬停反馈的行为，请修改此组件。参见 [显示反馈](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/an-niu-shi-jian/system-based-events.md#show-feedback) ，了解如何处理此组件。

```ts
const hoverFeedback = PointerEvents.getMutable(myEntity)

if (hoverFeedback.pointerEvents[0]?.eventInfo) {
	hoverFeedback.pointerEvents[0].eventInfo.hoverText = '关闭门'
}
```

## 距离限制

默认情况下，玩家只有在其 **化身** 化身距离实体 10 米以内时才能与之交互。如果玩家离得太远，实体的高亮效果会变成红色而不是绿色，并且不会触发指针事件。

使用 `maxDistance` 来更改该范围：

```ts
// 仅当玩家头像在 5 米以内时才可点击
pointerEventsSystem.onPointerDown(
	{ entity: myEntity, opts: { maxDistance: 5 } },
	function () {
		console.log('已点击实体')
	}
)
```

### 按摄像机距离限制

`maxCameraDistance` 从 **当前活动摄像机** 而不是头像进行测量。当你的场景使用一个 [虚拟摄像机](/creator/content-creator-zh/chang-jing-sdk7/3d-nei-rong-ji-chu/camera.md#using-virtual-cameras) 放置在玩家远处的摄像机，并且你希望实体是否可点击取决于摄像机能看到什么时，这很有用。

```ts
// 仅当活动摄像机在 15 米以内时才可点击
pointerEventsSystem.onPointerDown(
	{ entity: myEntity, opts: { maxCameraDistance: 15 } },
	function () {
		console.log('已点击实体')
	}
)
```

### 两种限制如何组合

这两个选项是独立检查。实际运行哪些检查取决于你设置了什么：

| 你设置的内容                | 玩家需要满足的条件                |
| --------------------- | ------------------------ |
| 都不设置                  | 化身在 10 米以内（默认值）          |
| `maxDistance` 仅       | 化身在 `maxDistance`        |
| `maxCameraDistance` 仅 | 摄像机在 `maxCameraDistance` |
| 两者都满足                 | **任一满足** 任一检查通过即可        |

同时设置两者，表示“足够近，可以走过去， **或** 也足够近，可以清楚地看到它”：

```ts
// 当头像在 3 米内，或者摄像机在 20 米内时可点击
pointerEventsSystem.onPointerDown(
	{ entity: myEntity, opts: { maxDistance: 3, maxCameraDistance: 20 } },
	function () {
		console.log('已点击实体')
	}
)
```

{% hint style="warning" %}
**📔 注意**: `maxCameraDistance` 需要 `@dcl/sdk` 7.28.0 或更高版本。Bevy 基础的浏览器中已经提供了对它的支持。如果你的场景今天必须在每个客户端上表现完全一致，请依赖 `maxDistance` 并将 `maxCameraDistance` 视为增强功能。
{% endhint %}

### maxPlayerDistance 已弃用

`maxPlayerDistance` 是 `maxDistance`的弃用别名：二者都从头像测量距离。在新场景中请使用 `maxDistance` 。

如果场景同时设置了两者，则会使用 **较大的** 那个作为头像距离限制。

## 指针抬起

使用 `pointerEventsSystem.onPointerUp` 用于注册一个回调函数，当指定玩家在指向实体时松开按钮时会调用该函数。

```ts
pointerEventsSystem.onPointerUp(
	{
		entity: myEntity,
		opts: { button: InputAction.IA_PRIMARY, hoverText: '按钮抬起' },
	},
	function () {
		console.log('按钮抬起')
	}
)
```

该语句需要两个参数：

* `数据`：包含以下内容的对象：
  * `实体`：要处理的实体
  * `opts`：一个带有可选附加数据的对象：
    * `button`：要监听哪个按钮。参见 [指针按钮](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/an-niu-shi-jian/click-events.md#pointer-buttons) 了解受支持的选项。如果未指定按钮，则会监听所有按钮，包括前进和跳跃之类的移动按钮。
    * `hoverText`：在悬停反馈提示中显示的字符串内容。默认值为“交互”。
    * `showFeedback`：如果为 false，则会隐藏该实体的悬停提示。 *true* 。
    * `maxDistance`：玩家头像可以离实体多远仍能与之交互，单位为米。默认值为 10。如果玩家离得太远，将不会有悬停反馈，并且指针事件也不会工作。参见 [距离限制](#distance-limits).
* `cb`：每当指向实体时发生按钮抬起事件，就运行一次的回调函数。

同一个实体可以注册两个不同的回调，一个用于 `pointerEventsSystem.onPointerDown` ，一个用于 `pointerEventsSystem.onPointerUp`。每种回调实体只能注册一个， [处理多个按钮](#handle-multiple-buttons) ，以便在同一个回调中检测不同按钮。

{% hint style="warning" %}
**📔 注意**：按钮抬起事件的悬停反馈只有在按钮当前正处于按下状态时才会显示。如果玩家在未按住按钮的情况下指向实体，他们将看不到任何反馈，或者如果有的话，只会看到按钮按下事件的反馈。
{% endhint %}

## 悬停进入与离开

使用 `pointerEventsSystem.onPointerHoverEnter` 用于在玩家光标开始指向某个实体时运行回调， `pointerEventsSystem.onPointerHoverLeave` 用于在光标停止指向它时运行回调。

```ts
pointerEventsSystem.onPointerHoverEnter(
    {
        entity: myEntity,
        opts: { button: InputAction.IA_POINTER },
    },
    function () {
        console.log('光标开始悬停在实体上')
    }
)

pointerEventsSystem.onPointerHoverLeave(
    {
        entity: myEntity,
        opts: { button: InputAction.IA_POINTER },
    },
    function () {
        console.log('光标停止悬停在实体上')
    }
)
```

这些回调对于自定义悬停效果很有用，例如当玩家瞄准实体时播放声音或为实体播放动画。

## 移除回调

要移除回调函数，请使用相应的移除函数：

```ts
pointerEventsSystem.removeOnPointerDown(myEntity)
pointerEventsSystem.removeOnPointerUp(myEntity)
pointerEventsSystem.removeOnPointerHoverEnter(myEntity)
pointerEventsSystem.removeOnPointerHoverLeave(myEntity)
```

移除后，实体上的悬停反馈应不再显示，并且该实体也应不再可交互。

每个移除函数只会移除其对应注册函数添加的那条记录。反复注册并移除同一个回调不会在实体上留下过期条目。

## 近距离交互

对于基于玩家接近而不是光标瞄准触发的交互，请参见 [**近距离事件**](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/an-niu-shi-jian/proximity-events.md)。 `pointerEventsSystem` 包括等效的辅助函数（`onProximityDown`, `onProximityUp`, `onProximityEnter`、以及 `onProximityLeave`），其模式与本页描述的函数相同。

同一个实体可以同时拥有一个光标处理器和一个近距离处理器来处理同一事件类型。两个回调都会运行，各自在自己的条件满足时触发。

### 来自输入动作的数据

获取来自输入动作的数据，例如按下的按钮、被击中的实体、射线的方向和长度等。参见（[查看文档](https://github.com/decentraland/docs/tree/main/README.md)）以了解所有可用数据的说明。

要获取这些数据，请向回调函数传递一个参数。该参数包含输入事件的完整数据结构。

```ts
pointerEventsSystem.onPointerDown(
	{ entity: myEntity, opts: { button: InputAction.IA_PRIMARY } },
	function (cmd) {
		console.log(cmd.hit?.entityId)
	}
)
```

### 处理多个按钮

你不能注册超过一个 `onPointerDown` 在单个实体上。理想情况下，你应该使用 [基于系统的](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/an-niu-shi-jian/system-based-events.md) 方法，因为这样你可以按需处理尽可能多的不同输入，并为每个按钮显示一个 UI 悬停反馈提示。

作为替代，你可以使用注册回调的方法，并将 `button` 字段设为 `InputAction.IA_ANY`.

```ts
pointerEventsSystem.onPointerDown(
  {entity: myEntity, opts: { button: InputAction.IA_ANY}},
  function (cmd) {
      if(cmd.button === InputAction.IA_POINTER){
        // 执行 X
      } else if (cmd.button === InputAction.IA_PRIMARY){
        // 执行 Y
      }
  }
)
```

这种方法并不理想，因为悬停提示只会显示一个字符串，不会说明要激活什么动作。请注意，这会让回调函数对每个输入动作都运行，包括移动键，因此你必须只筛选出你关心的动作。


---

# 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/jiao-hu-xing/an-niu-shi-jian/register-callback.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.
