> 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-es/escenas-sdk7/interactividad/player-physics.md).

# Física del player

Puedes aplicar fuerzas físicas al avatar del jugador desde el código de tu escena. Esto te permite crear mecánicas de juego como plataformas de lanzamiento, zonas de viento, efectos de retroceso, explosiones y más.

Hay dos tipos de fuerza que puedes aplicar:

* **Impulso**: Un empuje instantáneo de un solo uso. Úsalo para efectos bruscos y discretos, como lanzar al jugador por los aires o empujarlo hacia atrás.
* **Fuerza continua**: Un empuje sostenido aplicado en cada tick mientras esté activa. Úsalo para efectos continuos como zonas de viento, corrientes de agua o campos gravitatorios.

Ambas se aplican a través del `Physics` helper, importado desde `@dcl/sdk/ecs`.

{% hint style="warning" %}
**📔 Nota**: Estas fuerzas solo afectan al avatar del jugador local. Los demás jugadores ven los cambios en las posiciones de otros jugadores, pero las fuerzas en sí no se sincronizan con los demás jugadores en multiplayer. La física de cada jugador se ejecuta localmente en su propia instancia.
{% endhint %}

## Aplicar un impulso

Usa `Physics.applyImpulseToPlayer()` para darle al jugador un empuje de un solo uso en una dirección determinada.

* `vector`: Dirección y fuerza combinadas: la longitud del vector codifica la magnitud del impulso.

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

// Lanzar al jugador directamente hacia arriba
Physics.applyImpulseToPlayer(Vector3.create(0, 50, 0))
```

También puedes pasar una dirección y una magnitud por separado. En este caso, el vector de dirección se normaliza automáticamente:

* `direction`: Dirección a empujar: se normaliza automáticamente antes de escalarse.
* `magnitude`: Fuerza del impulso.

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

// Lanzar al jugador hacia arriba con una magnitud de 50
Physics.applyImpulseToPlayer(Vector3.create(0, 1, 0), 50)
```

Si llamas a `applyImpulseToPlayer()` varias veces dentro del mismo frame, los impulsos se acumulan: se suman y se aplican como un único impulso combinado.

### Activar un impulso al entrar el jugador

Un patrón común es activar un impulso cuando el jugador entra en un área. Usa un trigger area para detectar cuándo el jugador entra:

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

## Aplicar un impulso de retroceso

Usa `Physics.applyKnockbackToPlayer()` para empujar al jugador lejos de un punto con un solo impulso. Esto es ideal para explosiones, efectos de impacto y otros estallidos direccionales de un solo uso. La dirección se calcula automáticamente desde el punto de origen hasta la posición actual del jugador.

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

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

// Empujar al jugador alejándolo del centro de la explosión
Physics.applyKnockbackToPlayer(explosionPosition, 40)
```

Puedes limitar el área de efecto con un `radio`, y controlar cómo disminuye la magnitud con la distancia usando la opción `KnockbackFalloff` :

* `fromPosition`: Origen en world space del retroceso (centro de la explosión, posición del enemigo, etc.).
* `magnitude`: Fuerza base del impulso.
* `radio`: Distancia máxima de efecto (predeterminado: `Infinity`).
* `falloff`: Cómo disminuye la magnitud con la distancia (predeterminado: `CONSTANT`).

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

Physics.applyKnockbackToPlayer(
	Vector3.create(8, 1, 8),
	40,                          // magnitud
	10,                          // radio: no hay efecto más allá de 10 metros
	KnockbackFalloff.LINEAR      // la magnitud se desvanece hasta 0 en el borde del radio
)
```

La `KnockbackFalloff` enum controla cómo disminuye la fuerza con la distancia:

* `KnockbackFalloff.CONSTANT` — misma magnitud a cualquier distancia dentro del radio (predeterminado)
* `KnockbackFalloff.LINEAR` — disminución lineal suave hasta 0 en el borde del radio
* `KnockbackFalloff.INVERSE_SQUARE` — caída brusca y físicamente realista

Si el jugador está exactamente en la posición de origen, se le empuja directamente hacia arriba. Una magnitud negativa tira del jugador hacia el punto en lugar de empujarlo hacia afuera.

Los mismos `KnockbackFalloff` valores están disponibles para `applyRepulsionForceToPlayer()`.

## Aplicar una fuerza continua

Usa `Physics.applyForceToPlayer()` para aplicar una fuerza sostenida al jugador. A diferencia de un impulso, esta fuerza se aplica en cada tick mientras siga activa.

* `source`: Una entidad que identifica el origen de esta fuerza: úsala para actualizar o eliminar la fuerza más tarde.
* `vector`: Dirección y fuerza combinadas: la longitud del vector codifica la magnitud de la fuerza.

La posición de la entidad de origen no es relevante: solo se usa como identificador.

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

const windZoneEntity = engine.addEntity()

// Empujar al jugador hacia la derecha continuamente
Physics.applyForceToPlayer(windZoneEntity, Vector3.create(10, 0, 0))
```

El vector de fuerza siempre está en **world space**. Si necesitas una dirección relativa a una entidad rotada, usa `Transform.localToWorldDirection()` para convertirla primero: ver [Convertir una dirección local a world space](#convert-a-local-direction-to-world-space).

Al igual que con `applyImpulseToPlayer()`, también puedes pasar un `direction` y `magnitude` por separado: ver [Aplicar un impulso](#apply-an-impulse):

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

Si llamas a `applyForceToPlayer()` de nuevo con la misma entidad de origen, reemplaza la fuerza anterior de ese origen. Si varias fuentes de fuerza se acumulan, sus vectores se suman en cada tick.

### Eliminar una fuerza continua

Para dejar de aplicar una fuerza, llama a `Physics.removeForceFromPlayer()` con una referencia a la entidad de origen que se usó para crear la fuerza. Si la entidad no está aplicando una fuerza en ese momento, esta llamada se ignora de forma segura.

* `source`: La entidad usada cuando se aplicó la fuerza.

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

### Aplicar una fuerza durante una duración limitada

Usa `Physics.applyForceToPlayerForDuration()` para aplicar una fuerza durante un tiempo específico. La duración se expresa en segundos. La fuerza se elimina automáticamente cuando el tiempo expira. Si llamas de nuevo con la misma entidad de origen, se reinicia el temporizador.

* `source`: Una entidad que identifica el origen de esta fuerza.
* `duration`: Cuánto dura la fuerza, en segundos.
* `vector`: Dirección y fuerza combinadas: la longitud del vector codifica la magnitud de la fuerza.

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

const gustEntity = engine.addEntity()

// Aplicar una fuerte fuerza ascendente durante 1.5 segundos
Physics.applyForceToPlayerForDuration(gustEntity, 1.5, Vector3.create(0, 50, 0))
```

La `direction` + `magnitude` también está disponible: ver [Aplicar un impulso](#apply-an-impulse):

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

### Ejemplo de zona de viento

Este ejemplo crea un túnel de viento que empuja al jugador mientras está dentro y se detiene cuando sale:

```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))  // empujar lateralmente a lo largo del eje X
})

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

## Aplicar una fuerza de repulsión

Usa `Physics.applyRepulsionForceToPlayer()` para empujar continuamente al jugador alejándolo de un punto fijo en el espacio. Esto es adecuado para efectos como un campo de repulsión magnética, una barrera de fuerza o un objeto flotante que mantiene a los jugadores a distancia. A diferencia de `applyKnockbackToPlayer()`, esta fuerza se recalcula en cada tick a medida que el jugador se mueve. La magnitud se debilita con la distancia según el radio y el falloff: ver [Aplicar un impulso de retroceso](#apply-a-knockback-impulse) para las `KnockbackFalloff` opciones. Una magnitud negativa invierte el efecto, atrayendo continuamente al jugador hacia el punto como un vórtice o un pozo gravitatorio.

{% hint style="warning" %}
**📔 Nota**: El origen de la repulsión es el `fromPosition` vector que pasas: **no** la posición de la `source` entity. La `source` entity solo se usa como identificador para que puedas actualizar o eliminar la fuerza más tarde. Su posición, rotación y escala se ignoran por completo.
{% endhint %}

* `source`: Una entidad usada como identificador de esta fuerza: su posición no se usa.
* `fromPosition`: El punto en world space del que se aleja al jugador.
* `magnitude`: Fuerza base de la fuerza. Los valores negativos atraen en lugar de repeler.
* `radio`: Distancia máxima de efecto (predeterminado: `Infinity`).
* `falloff`: Cómo disminuye la magnitud con la distancia (predeterminado: `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) })

// Pasar explícitamente la posición de la entidad como origen de la repulsión
Physics.applyRepulsionForceToPlayer(
	repulsionSource,
	Transform.get(repulsionSource).position,  // origen de la repulsión: pasado explícitamente, no leído automáticamente
	50,                                         // magnitud
	10,                                         // radio de efecto en metros
)

// Eliminar la fuerza después de medio segundo
timers.setTimeout(() => {
    Physics.removeForceFromPlayer(repulsionSource)
}, 500)
```

## Fuerzas mientras planea

Mientras el jugador está planeando, las fuerzas continuas se comportan de manera diferente:

* Las fuerzas continuas — de `applyForceToPlayer()`, `applyForceToPlayerForDuration()`, o `applyRepulsionForceToPlayer()` — son **1.5 veces más fuertes**, ya que el planeador abierto capta el flujo de aire. Las zonas de viento y las corrientes se sienten más receptivas para un jugador que está planeando.
* El componente ascendente de una fuerza continua puede **elevar** a un jugador que está planeando. El límite de velocidad de caída del planeador solo limita qué tan rápido desciende el jugador; no cancela el movimiento ascendente, así que una corriente de viento vertical o en ángulo empuja al jugador siguiendo toda la dirección de la fuerza.

Los impulsos de un solo uso — de `applyImpulseToPlayer()` o `applyKnockbackToPlayer()` — no se ven afectados por el planeo. Se comportan igual tanto si el planeador está abierto como cerrado.

Puedes combinar estos comportamientos para construir mecánicas como corrientes térmicas ascendentes que lleven hacia arriba a los jugadores que planean, o corredores de viento que sean más fáciles de atravesar con el planeador abierto. Para ajustar la velocidad de caída o la velocidad hacia adelante del planeador, usa el componente `AvatarLocomotionSettings` consulta [Configuración de locomoción](/creator/content-creator-es/escenas-sdk7/interactividad/player-avatar.md#locomotion-settings).

## Convertir una dirección local a world space

Usa `Transform.localToWorldDirection()` para transformar un vector de dirección desde el espacio de coordenadas local de una entidad al world space, teniendo en cuenta toda la jerarquía de padres. Esto es útil al aplicar fuerzas relativas a una entidad rotada; por ejemplo, empujar al jugador lejos de una cara específica de un obstáculo giratorio.

* `entity`: La entidad de origen cuyo espacio local define la dirección.
* `localDirection`: Vector de dirección en las coordenadas locales de la entidad.

Devuelve el vector de dirección en coordenadas del mundo.

Esto aplica **solo la rotación** — no tiene en cuenta la traslación ni la escala —, por lo que es directamente adecuado para los vectores de dirección que se pasan a funciones de fuerza e impulso.

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

// Empujar al jugador en la dirección en la que apunta el eje local +Z de la entidad en world space
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-es/escenas-sdk7/interactividad/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.
