> 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/mouse-movement.md).

# Movimiento del mouse

Tu scene puede leer el movimiento bruto del mouse del player en cada frame, y usarlo para impulsar interacciones en tiempo real: gestos de drag y swipe, girando o deslizand objects mientras el player los arrastra, o controlando una cámara personalizada como en un shooter en primera persona.

Para hacer esto, lee la `screenDelta` propiedad del `PrimaryPointerInfo` component en `engine.RootEntity`. Esta propiedad es un `Vector2` que informa cuántos píxeles se movió el mouse desde el último frame. Los valores positivos de `x` significan que el mouse se movió a la derecha; los valores positivos de `y` significan que se movió hacia arriba, coincidiendo con el origen de la pantalla en la esquina inferior izquierda. En los frames en que el mouse no se mueve, ambos valores son 0.

```ts
import { engine, PrimaryPointerInfo } from '@dcl/sdk/ecs'

engine.addSystem(() => {
	const delta = PrimaryPointerInfo.getOrNull(engine.RootEntity)?.screenDelta
	if (!delta) return
	console.log(`mouse moved: ${delta.x}, ${delta.y}`)
})
```

Dado que `screenDelta` solo contiene el movimiento de un solo frame, léelo siempre dentro de un [system](/creator/content-creator-es/escenas-sdk7/arquitectura/systems.md), para que ningún movimiento pase desapercibido entre frames.

{% hint style="warning" %}
**📔 Nota**: Evita hacer referencia a `engine.RootEntity` en la carga inicial de la scene, porque eso puede provocar errores si las entities aún no se han inicializado. Para evitar este problema, haz referencia a la entity siempre dentro de un system. Siempre estará disponible, porque la primera ejecución del system se llama una vez que la scene ya está correctamente inicializada.
{% endhint %}

{% hint style="warning" %}
**📔 Nota**: Lo que se describe en este documento solo es relevante para los players en desktop. En la [aplicación móvil](/creator/content-creator-es/desarrollar-para-movil/cliente-movil/overview.md), el input se basa en el tacto y no hay un cursor de movimiento libre, por lo que `screenDelta` siempre reporta 0. Consulta [Input en mobile](/creator/content-creator-es/desarrollar-para-movil/desarrollar/input-on-mobile.md) para ver cómo funciona el input en dispositivos táctiles, y [Detectar plataforma](/creator/content-creator-es/desarrollar-para-movil/desarrollar/detect-platform.md) para ofrecer controles alternativos a los players en mobile.
{% endhint %}

## El movimiento del mouse mientras el cursor está bloqueado

`screenDelta` se comporta de manera diferente de las otras propiedades de `PrimaryPointerInfo` cuando el cursor está [bloqueado](/creator/content-creator-es/escenas-sdk7/interactividad/eventos-de-boton/click-events.md#lock-or-unlock-the-cursor): `screenCoordinates` se congela en el centro de la pantalla y `worldRayDirection` siempre reporta el rayo en el centro de la pantalla, pero `screenDelta` sigue reportando el movimiento bruto del mouse en cada frame. Esto lo convierte en la única forma de leer el movimiento del mouse mientras el cursor está bloqueado, que es exactamente lo que necesitas para controles personalizados de camera o puntería.

## Arrastra para girar un objeto

El siguiente ejemplo permite al player girar un cubo arrastrando el mouse lateralmente mientras mantiene presionado el botón del puntero:

```ts
import {
	engine,
	InputAction,
	inputSystem,
	MeshCollider,
	MeshRenderer,
	PrimaryPointerInfo,
	Transform,
} from '@dcl/sdk/ecs'
import { Quaternion, Vector3 } from '@dcl/sdk/math'

const DRAG_SENSITIVITY = 0.5

export function main() {
	const cube = engine.addEntity()
	Transform.create(cube, { position: Vector3.create(8, 1, 8) })
	MeshRenderer.setBox(cube)
	MeshCollider.setBox(cube)

	engine.addSystem(() => {
		// solo gira mientras el botón del puntero esté presionado
		if (!inputSystem.isPressed(InputAction.IA_POINTER)) return

		const delta = PrimaryPointerInfo.getOrNull(engine.RootEntity)?.screenDelta
		if (!delta || delta.x === 0) return

		const transform = Transform.getMutable(cube)
		transform.rotation = Quaternion.multiply(
			transform.rotation,
			Quaternion.fromEulerDegrees(0, delta.x * DRAG_SENSITIVITY, 0)
		)
	})
}
```

El mismo patrón funciona para cualquier interacción de drag: desliza una entity a lo largo de un riel usando `delta.x` como desplazamiento, recorre una animación, o detecta un swipe rápido comprobando valores de delta grandes.

## Controles de cámara mouselook

Porque `screenDelta` sigue funcionando mientras el cursor está bloqueado, puedes usarlo para crear controles mouselook para una [cámara virtual](/creator/content-creator-es/escenas-sdk7/fundamentos-del-contenido-3d/camera.md#using-virtual-cameras). Para hacerlo, acumula el movimiento del mouse en ángulos de yaw y pitch, y luego aplícalos a la rotación de la camera en cada frame.

En el siguiente ejemplo, el player hace clic en una caja para cambiar a una cámara virtual que puede controlar con el mouse, y presiona el botón secundario (*F* o clic derecho) para volver a la camera predeterminada. Mientras la cámara virtual está activa, la scene también bloquea el cursor y congela el avatar con un [InputModifier](/creator/content-creator-es/escenas-sdk7/interactividad/player-avatar.md#freeze-the-player), para que el player no camine sin ver mientras controla la camera.

```ts
import {
	engine,
	Entity,
	InputAction,
	InputModifier,
	inputSystem,
	MainCamera,
	MeshCollider,
	MeshRenderer,
	PointerEventType,
	pointerEventsSystem,
	PointerLock,
	PrimaryPointerInfo,
	Transform,
	VirtualCamera,
} from '@dcl/sdk/ecs'
import { Quaternion, Vector3 } from '@dcl/sdk/math'

// grados de rotación de la camera por píxel de movimiento del mouse
const SENSITIVITY = 0.15

let cameraEntity: Entity
let cameraActive = false
let yaw = 0
let pitch = 0

export function main() {
	// la entity que sigue la camera
	cameraEntity = engine.addEntity()
	Transform.create(cameraEntity, { position: Vector3.create(8, 3, 8) })
	VirtualCamera.create(cameraEntity, {
		defaultTransition: { transitionMode: VirtualCamera.Transition.Time(0.5) },
	})

	// haz clic en esta caja para entrar en modo mouselook
	const box = engine.addEntity()
	Transform.create(box, { position: Vector3.create(8, 1, 4) })
	MeshRenderer.setBox(box)
	MeshCollider.setBox(box)
	pointerEventsSystem.onPointerDown(
		{
			entity: box,
			opts: { button: InputAction.IA_POINTER, hoverText: 'Controlar cámara' },
		},
		() => activateCamera(true)
	)

	// controla la camera con el mouse
	engine.addSystem(() => {
		if (!cameraActive) return
		if (!PointerLock.getOrNull(engine.CameraEntity)?.isPointerLocked) return

		const delta = PrimaryPointerInfo.getOrNull(engine.RootEntity)?.screenDelta
		if (!delta) return

		yaw += delta.x * SENSITIVITY
		// limita el pitch para que la camera no pueda voltearse
		pitch = Math.max(-85, Math.min(85, pitch - delta.y * SENSITIVITY))

		Transform.getMutable(cameraEntity).rotation = Quaternion.fromEulerDegrees(pitch, yaw, 0)
	})

	// salir del modo mouselook con el botón secundario
	engine.addSystem(() => {
		if (!cameraActive) return
		if (inputSystem.isTriggered(InputAction.IA_SECONDARY, PointerEventType.PET_DOWN)) {
			activateCamera(false)
		}
	})
}

function activateCamera(active: boolean) {
	cameraActive = active

	// asigna o libera la cámara virtual
	MainCamera.createOrReplace(engine.CameraEntity, {
		virtualCameraEntity: active ? cameraEntity : undefined,
	})

	// congela el avatar mientras se controla la camera
	InputModifier.createOrReplace(engine.PlayerEntity, {
		mode: InputModifier.Mode.Standard({ disableAll: active }),
	})

	// bloquea el cursor, para que el mouse controle la camera de inmediato
	PointerLock.createOrReplace(engine.CameraEntity, { isPointerLocked: active })
}
```

Algunas cosas a tener en cuenta de este ejemplo:

* El system resta `delta.y` del pitch, de modo que mover el mouse hacia arriba incline la camera hacia arriba. Invierte ese signo si prefieres controles verticales invertidos.
* El pitch se limita a un rango de -85 a 85 grados, así que la camera nunca puede volcarse hacia atrás.
* El `SENSITIVITY` constant expresa grados de rotación por píxel de movimiento del mouse; ajústala a tu gusto.

{% hint style="info" %}
**💡 Consejo**: El player puede desbloquear el cursor en cualquier momento presionando *Esc* o haciendo clic derecho, lo que hace que la camera deje de responder al mouse. Siempre ofrece a los players una forma clara de salir por completo del modo de camera, como el botón secundario en el ejemplo anterior. También puedes volver a bloquear el cursor desde el código, consulta [Bloquear o desbloquear el cursor](/creator/content-creator-es/escenas-sdk7/interactividad/eventos-de-boton/click-events.md#lock-or-unlock-the-cursor).
{% endhint %}

## Temas relacionados

Para leer la posición absoluta del cursor en la pantalla en lugar de su movimiento, usa la `screenCoordinates` propiedad del mismo component. Consulta [Comprobar la posición del cursor del player](/creator/content-creator-es/escenas-sdk7/interactividad/user-data.md#check-the-players-cursor-position).

Para averiguar qué entity está bajo el cursor, combina la `worldRayDirection` propiedad con un raycast. Consulta [Raycasting](/creator/content-creator-es/escenas-sdk7/interactividad/raycasting.md).

{% hint style="info" %}
**💡 Consejo**: Para ver ejemplos funcionales del estado del pointer, consulta la [`0,5-primary-cursor-info`](https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/0,5-primary-cursor-info) escena de prueba, que lee `PrimaryPointerInfo` cada frame y alimenta `worldRayDirection` en un raycast; [`31,20-pointer-lock-control`](https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/31,20-pointer-lock-control), que solicita y libera la captura del cursor escribiendo `PointerLock.isPointerLocked`; y [`32,20-virtual-camera-mouse-look`](https://github.com/decentraland/sdk7-test-scenes/tree/main/scenes/32,20-virtual-camera-mouse-look), que muestra `screenDelta` que sigue reportando movimiento mientras `screenCoordinates` está congelado en el centro de la pantalla durante el bloqueo.
{% endhint %}


---

# 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/mouse-movement.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.
