> 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。参见 **化身**，单位为米。默认是 10。参见 [距离限制](#distance-limits).
    * `maxCameraDistance`：实体与 **当前活动摄像机**之间的最大距离，单位为米。默认未设置。参见 [距离限制](#distance-limits).
    * `hoverText`：在悬停反馈提示中显示的字符串。默认是“Interact”。
    * `showFeedback`：如果为 false，则会隐藏该实体的悬停提示和边缘高亮。 *真* 。
    * `showHighlight`：如果为 true，玩家将会在光标悬停在实体上时看到边缘高亮。 *真* 默认如此。只有在以下情况下才会考虑此值： `showFeedback` 为 *真*.
* `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`，以及一个鼠标图标，用于 `InputAction.IA_POINTER`.

通过修改 `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`：在悬停反馈提示中显示的字符串。默认是“Interact”。
    * `showFeedback`：如果为 false，则会隐藏该实体的悬停提示。 *真* 。
    * `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 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/jiao-hu-xing/an-niu-shi-jian/register-callback.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.
