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

# Player Physics

Aplica fuerzas e impulsos al avatar 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 empujón instantáneo de un solo uso. Úsalo para efectos repentinos y discretos, como lanzar al jugador por los aires o hacer que retroceda.
* **Fuerza continua**: Un empujón sostenido que se aplica en cada tick mientras esté activa. Úsala para efectos continuos como zonas de viento, corrientes de agua o campos gravitatorios.

Ambas se aplican mediante el `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 otros 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 empujón de un solo uso en una dirección dada.

* `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'

// Lanza 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'

// Lanza 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.

### Desencadenar un impulso al entrar el jugador

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

```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 alejándolo de un punto con un único impulso. Esto es ideal para explosiones, efectos de impacto y otras detonaciones 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)

// Hacer retroceder al jugador desde el centro de la explosión
Physics.applyKnockbackToPlayer(explosionPosition, 40)
```

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

* `fromPosition`: Origen en el espacio mundial del retroceso (centro de la explosión, posición del enemigo, etc.).
* `magnitude`: Fuerza base del impulso.
* `radius`: Distancia máxima del efecto (valor predeterminado: `Infinity`).
* `falloff`: Cómo disminuye la magnitud con la distancia (valor 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,                          // radius: sin efecto más allá de 10 metros
	KnockbackFalloff.LINEAR      // la magnitud se desvanece hasta 0 en el borde del radius
)
```

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

* `KnockbackFalloff.CONSTANT` — misma magnitud a cualquier distancia dentro del radius (predeterminado)
* `KnockbackFalloff.LINEAR` — disminución lineal suave hasta 0 en el borde del radius
* `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 alejarlo.

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 actualizarla o eliminarla 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()

// Empuja al jugador hacia la derecha de forma continua
Physics.applyForceToPlayer(windZoneEntity, Vector3.create(10, 0, 0))
```

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

Al igual que con `applyImpulseToPlayer()`, también puedes pasar un `direction` y `magnitude` por separado — mira [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 esa fuente. Si se acumulan varias fuentes de fuerza, 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 un tiempo limitado

Usa `Physics.applyForceToPlayerForDuration()` para aplicar una fuerza durante una cantidad específica de tiempo. La duración se expresa en segundos. La fuerza se elimina automáticamente cuando transcurre el tiempo. Llamar de nuevo con la misma entidad de origen 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()

// Aplica una fuerza fuerte hacia arriba durante 1.5 segundos
Physics.applyForceToPlayerForDuration(gustEntity, 1.5, Vector3.create(0, 50, 0))
```

El `direction` + `magnitude` la sobrecarga también está disponible — mira [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))  // empuja 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 radius y el falloff — mira [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 de gravedad.

{% hint style="warning" %}
**📔 Nota**: El origen de repulsión es el `fromPosition` vector que pasas — **no** la posición de la `source` entidad. La `source` entidad 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 el espacio mundial desde el que se aleja al jugador.
* `magnitude`: Fuerza base de la fuerza. Los valores negativos atraen en lugar de repeler.
* `radius`: Distancia máxima del efecto (valor predeterminado: `Infinity`).
* `falloff`: Cómo disminuye la magnitud con la distancia (valor 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) })

// Pasa 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: se pasa explícitamente, no se lee automáticamente
	50,                                         // magnitud
	10,                                         // radius del efecto en metros
)

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

## Fuerzas mientras se planea

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

* Las fuerzas continuas — de `applyForceToPlayer()`, `applyForceToPlayerForDuration()`, o `applyRepulsionForceToPlayer()` — son **1.5 veces más fuertes**, ya que el planeador abierto atrapa el flujo de aire. Las zonas de viento y las corrientes resultan más sensibles para un jugador que planea.
* El componente ascendente de una fuerza continua puede **elevar** a un jugador que planea. 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 inclinada o vertical empuja al jugador en 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 si está cerrado.

Puedes combinar estos comportamientos para crear mecánicas como corrientes ascendentes térmicas que lleven a los jugadores que planean hacia arriba, o pasillos 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` ; mira [Configuración de locomoción](/creator/content-creator-es/scenes-sdk7/interactividad/avatars/locomotion.md#locomotion-settings).

## Convertir una dirección local a espacio mundial

Usa `Transform.localToWorldDirection()` para transformar un vector de dirección desde el espacio de coordenadas local de una entidad a espacio mundial, teniendo en cuenta toda la jerarquía de padres. Esto es útil cuando se aplican fuerzas relativas a una entidad rotada; por ejemplo, empujar al jugador alejándolo 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 mundiales.

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

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

// Empuja al jugador en la dirección hacia la que apunta el eje local +Z de la entidad en espacio mundial
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/scenes-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.
