> 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)
```

你可以使用 `radius`来限制作用范围，并通过 `KnockbackFalloff` 选项控制力度随距离衰减的方式：

* `fromPosition`：击退的世界空间原点（爆炸中心、敌人位置等）。
* `大小`：基础脉冲强度。
* `radius`：最大作用距离（默认： `Infinity`).
* `falloff`：力度如何随距离递减（默认： `CONSTANT`).

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

Physics.applyKnockbackToPlayer(
	Vector3.create(8, 1, 8),
	40,                          // magnitude
	10,                          // radius: no effect beyond 10 meters
	KnockbackFalloff.LINEAR      // magnitude fades to 0 at the radius edge
)
```

该 `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`：玩家被推离的世界空间点。
* `大小`：基础力强度。负值表示吸引而不是排斥。
* `radius`：最大作用距离（默认： `Infinity`).
* `falloff`：力度如何随距离递减（默认： `CONSTANT`).

```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,                                         // magnitude
	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/player-avatar.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 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/player-physics.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.
