> 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/player-physics.md).

# 玩家物理效果

对玩家头像施加力和冲量

你可以从场景代码中对玩家的化身施加物理力。这使你能够创建诸如跳板、风区、击退效果、爆炸等游戏机制。

你可以施加两种力：

* **冲量**：一次性的瞬时推动。用于诸如将玩家弹向空中或击退他们之类的突发离散效果。
* **持续力**：只要处于激活状态，就会在每个 tick 施加的持续推动。用于诸如风区、水流或重力场之类的持续效果。

两者都通过 `Physics` 辅助工具施加，从 `@dcl/sdk/ecs`.

{% hint style="warning" %}
**📔 注意**：这些力只会影响本地玩家的化身。其他玩家会看到其他玩家位置的变化，但这些力本身不会在多人游戏中同步给其他玩家。每个玩家的物理效果都在各自的实例上本地运行。
{% endhint %}

## 施加冲量

使用 `Physics.applyImpulseToPlayer()` ，在给定方向上向玩家施加一次性推动。

* `向量`：方向和强度的组合——向量的长度表示冲量大小。

```ts
import { Physics } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

// 将玩家直接向上弹起
Physics.applyImpulseToPlayer(Vector3.create(0, 50, 0))
```

你也可以分别传入方向和大小。在这种情况下，方向向量会自动标准化：

* `方向`：推动方向——在缩放前会自动标准化。
* `大小`：冲量强度。

```ts
import { Physics } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

// 以 50 的大小将玩家向上弹起
Physics.applyImpulseToPlayer(Vector3.create(0, 1, 0), 50)
```

如果你在同一帧内多次调用 `applyImpulseToPlayer()` ，这些冲量会被累积——它们会相加并作为一个合并后的单一冲量施加。

### 在玩家进入时触发冲量

一种常见模式是在玩家走入某个区域时触发冲量。使用触发区域来检测玩家何时进入：

```ts
import { engine, Physics, TriggerArea, triggerAreaEventsSystem, ColliderLayer, MeshRenderer, Transform } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

const launchPad = engine.addEntity()
Transform.create(launchPad, { position: Vector3.create(8, 0, 8) })
MeshRenderer.setBox(launchPad)
TriggerArea.setBox(launchPad, ColliderLayer.CL_PLAYER)

triggerAreaEventsSystem.onTriggerEnter(launchPad, (result) => {
	if (result.trigger?.entity !== engine.PlayerEntity) return
	Physics.applyImpulseToPlayer(Vector3.create(0, 50, 0))
})
```

## 施加击退冲量

使用 `Physics.applyKnockbackToPlayer()` 通过单个冲量将玩家从某个点推开。非常适合爆炸、碰撞效果以及其他一次性的定向爆发。方向会自动从源点计算到玩家当前的位置。

```ts
import { Physics } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

const explosionPosition = Vector3.create(8, 1, 8)

// 将玩家从爆炸中心击退
Physics.applyKnockbackToPlayer(explosionPosition, 40)
```

你可以用 `半径`来限制作用范围，并使用 `KnockbackFalloff` 选项来控制强度如何随距离衰减：

* `fromPosition`：击退的世界空间原点（爆炸中心、敌人位置等）。
* `大小`：基础冲量强度。
* `半径`：作用的最大距离（默认： `无限`).
* `衰减`：强度如何随距离减弱（默认： `恒定`).

```ts
import { Physics, KnockbackFalloff } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

Physics.applyKnockbackToPlayer(
	Vector3.create(8, 1, 8),
	40,                          // 强度
	10,                          // 半径：10 米之外不生效
	KnockbackFalloff.LINEAR      // 强度在半径边缘衰减到 0
)
```

该 `KnockbackFalloff` 枚举控制力如何随距离减弱：

* `KnockbackFalloff.CONSTANT` ——在半径内任意距离都具有相同强度（默认）
* `KnockbackFalloff.LINEAR` ——平滑线性下降，到半径边缘衰减为 0
* `KnockbackFalloff.INVERSE_SQUARE` ——陡峭且符合物理规律的衰减

如果玩家正好位于源位置，玩家会被直接向上推。负数强度则会将玩家拉向该点，而不是将其推开。

相同的 `KnockbackFalloff` 值也适用于 `applyRepulsionForceToPlayer()`.

## 施加持续力

使用 `Physics.applyForceToPlayer()` 向玩家施加持续力。与冲量不同，只要它保持激活状态，这个力就会在每个 tick 施加一次。

* `来源`：用于标识该力来源的实体——可用它在稍后更新或移除该力。
* `向量`：方向和强度的组合——向量的长度表示力的大小。

来源实体的位置并不重要——它仅用作标识符。

```ts
import { engine, Physics } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

const windZoneEntity = engine.addEntity()

// 持续将玩家向右推动
Physics.applyForceToPlayer(windZoneEntity, Vector3.create(10, 0, 0))
```

该力向量始终处于 **世界空间**。如果你需要相对于旋转实体的方向，请先使用 `Transform.localToWorldDirection()` 进行转换——参见 [将本地方向转换为世界空间](#convert-a-local-direction-to-world-space).

与 `applyImpulseToPlayer()`相同，你也可以单独传入一个 `方向` 和 `大小` ——参见 [施加冲量](#apply-an-impulse):

```ts
Physics.applyForceToPlayer(windZoneEntity, Vector3.create(0, 1, 0), 50)
```

如果你在同一帧内多次调用 `applyForceToPlayer()` 再次使用相同的来源实体调用时，它会替换该来源之前的力。如果累积了多个力来源，则它们的向量会在每个 tick 中求和。

### 移除持续力

要停止施加力，请调用 `Physics.removeForceFromPlayer()` 并传入用于创建该力的来源实体引用。如果该实体当前没有施加力，这次调用会被安全忽略。

* `来源`：施加该力时所使用的实体。

```ts
Physics.removeForceFromPlayer(windZoneEntity)
```

### 在有限时间内施加力

使用 `Physics.applyForceToPlayerForDuration()` 用于在指定时长内施加力。持续时间以秒为单位。时间到后会自动移除该力。再次使用相同来源实体调用时会重置计时器。

* `来源`：用于标识该力来源的实体。
* `持续时间`：力持续的时间，单位为秒。
* `向量`：方向和强度的组合——向量的长度表示力的大小。

```ts
import { engine, Physics } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

const gustEntity = engine.addEntity()

// 施加一个强向上的力，持续 1.5 秒
Physics.applyForceToPlayerForDuration(gustEntity, 1.5, Vector3.create(0, 50, 0))
```

该 `方向` + `大小` 也提供重载——参见 [施加冲量](#apply-an-impulse):

```ts
Physics.applyForceToPlayerForDuration(gustEntity, 1.5, Vector3.create(0, 1, 0), 50)
```

### 风区示例

此示例创建一个风洞：玩家在其中时会被推动，离开后则停止：

```ts
import { engine, Physics, TriggerArea, triggerAreaEventsSystem, ColliderLayer, MeshRenderer, MeshCollider, Transform } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

const windTunnel = engine.addEntity()
Transform.create(windTunnel, {
	position: Vector3.create(8, 1, 8),
	scale: Vector3.create(4, 3, 4),
})
MeshRenderer.setBox(windTunnel)
TriggerArea.setBox(windTunnel, ColliderLayer.CL_PLAYER)

triggerAreaEventsSystem.onTriggerEnter(windTunnel, (result) => {
	if (result.trigger?.entity !== engine.PlayerEntity) return
	Physics.applyForceToPlayer(windTunnel, Vector3.create(15, 0, 0))  // 沿 X 轴向侧面推动
})

triggerAreaEventsSystem.onTriggerExit(windTunnel, (result) => {
	if (result.trigger?.entity !== engine.PlayerEntity) return
	Physics.removeForceFromPlayer(windTunnel)
})
```

## 施加排斥力

使用 `Physics.applyRepulsionForceToPlayer()` 以持续将玩家从空间中的固定点推开。这适用于磁性排斥场、力场屏障，或让玩家保持距离的悬浮物体等效果。与 `applyKnockbackToPlayer()`不同，这种力会随着玩家移动而在每个 tick 重新计算。强度会根据半径和衰减随距离减弱——有关 [施加击退冲量](#apply-a-knockback-impulse) 请参见 `KnockbackFalloff` 选项。负数强度会反转效果，持续将玩家拉向该点，就像漩涡或引力井一样。

{% hint style="warning" %}
**📔 注意**：排斥源是 `fromPosition` 你传入的向量—— **不是** 实体的位置。 `来源` 实体 `来源` 仅用作标识符，以便你稍后更新或移除该力。其位置、旋转和缩放都会被完全忽略。
{% endhint %}

* `来源`：用作该力标识符的实体——其位置不会被使用。
* `fromPosition`：玩家被推离的世界空间点。
* `大小`：基础力强度。负值则为吸引而不是排斥。
* `半径`：作用的最大距离（默认： `无限`).
* `衰减`：强度如何随距离减弱（默认： `恒定`).

```ts
import { engine, Physics, Transform, timers } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

const repulsionSource = engine.addEntity()
Transform.create(repulsionSource, { position: Vector3.create(8, 1, 8) })

// 将实体的位置显式传入作为排斥源
Physics.applyRepulsionForceToPlayer(
	repulsionSource,
	Transform.get(repulsionSource).position,  // 排斥源——显式传入，而不是自动读取
	50,                                         // 强度
	10,                                         // 作用半径（米）
)

// 半秒后移除力
timers.setTimeout(() => {
    Physics.removeForceFromPlayer(repulsionSource)
}, 500)
```

## 滑翔时的力

当玩家处于滑翔状态时，持续力的表现不同：

* 持续力——来自 `applyForceToPlayer()`, `applyForceToPlayerForDuration()`，或 `applyRepulsionForceToPlayer()` ——会 **强 1.5 倍**，因为打开的滑翔器会接住气流。风区和水流对滑翔中的玩家会感觉更灵敏。
* 持续力的向上分量可以 **抬升** 滑翔中的玩家。滑翔器的下落速度上限只会限制玩家下降的速度，并不会抵消向上的运动，因此斜向或垂直的风流会让玩家沿着整个力的方向移动。

一次性冲量——来自 `applyImpulseToPlayer()` 或 `applyKnockbackToPlayer()` ——不受滑翔影响。无论滑翔器是打开还是关闭，它们的表现都相同。

你可以结合这些行为来构建诸如热气流之类的机制，把滑翔玩家带向上方，或者构建在滑翔器打开时更容易通过的风道。若要调整滑翔器的下落速度或前进速度，请使用 `AvatarLocomotionSettings` 组件，参见 [移动设置](/creator/content-creator-zh/chang-jing-sdk7/jiao-hu-xing/tou-xiang/locomotion.md#locomotion-settings).

## 将本地方向转换为世界空间

使用 `Transform.localToWorldDirection()` 将一个方向向量从实体的本地坐标空间转换到世界空间，并考虑完整的父级层级结构。当施加相对于旋转实体的力时，这很有用——例如，将玩家从旋转障碍物的某一侧推开。

* `实体`：定义该方向的源实体本地空间。
* `localDirection`：实体本地坐标中的方向向量。

返回世界坐标中的方向向量。

这只应用 **旋转** ——不考虑平移或缩放——因此它可直接用于传递给力和冲量函数的方向向量。

```ts
import { Physics, Transform } from '@dcl/sdk/ecs'
import { Vector3 } from '@dcl/sdk/math'

// 按实体本地 +Z 轴在世界空间中指向的方向推动玩家
const worldDir = Transform.localToWorldDirection(myEntity, Vector3.create(0, 0, 1))
Physics.applyImpulseToPlayer(worldDir, 20)
```


---

# 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/player-physics.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.
