> For the complete documentation index, see [llms.txt](https://docs.allout.game/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.allout.game/all-out-docs/docs-es/conceptos-centrales-del-motor/interactables.md).

# Interactivos

<figure><img src="https://864968843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FzA8RGUKJ88fD0oXVALlz%2Fuploads%2Fgit-blob-29d531efc3ba62fe4342df6008264afb7d552819%2Finteractable.png?alt=media" alt="An interact prompt near a world object"><figcaption></figcaption></figure>

### El componente interactuable

<figure><img src="https://864968843-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FzA8RGUKJ88fD0oXVALlz%2Fuploads%2Fgit-blob-ca76aa70b048f6a2a55fc2c45d1993889341e38e%2Fimage.png?alt=media" alt="Interactable component fields in the inspector"><figcaption></figcaption></figure>

Agregar un componente Interactable a una entidad mostrará automáticamente la UI cuando los jugadores estén dentro del `radio` que especifiques.

El radio de interacción escala con la escala mundial de la entidad, así que mantén la raíz interactuable con escala 1 y escala un hijo visual cuando quieras que el rango de interacción permanezca fijo.

Para responder a que el jugador presione el interactuable, necesitarás escribir código CSL.

Una entidad puede tener más de una `Interactable`. Usa `prioridad` cuando varias indicaciones puedan estar disponibles al mismo tiempo.

{% hint style="warning" %}
La selección de la indicación es por jugador, pero el contenido de la indicación no lo es. `can_use(player)` controla si un jugador puede ver y usar un interactuable; `set_text`, `set_hold_text`, `set_subtitle`y `subtitle_color` cambia el único componente compartido que ve cada jugador. No actualices esos valores a partir del estado de misión, inventario o progresión específico del jugador: la última escritura de Player A también se mostraría a Player B.

Para acciones diferentes por jugador, como "Aceptar misión" y "Entregar", usa una etiqueta compartida neutral como "Hablar", o agrega interactuables separados con etiqueta fija y controla cada uno con `can_use(player)`. Entonces cada jugador seleccionará entre los interactuables válidos para su propio estado.
{% endhint %}

El patrón más común es:

* Crea una clase que herede de `Interactable`
* Llama a `this.set_listener(this)` en `ao_start`
* Implementa `can_use` y `on_interact` en tu clase

{% hint style="info" %}
Si agregas una nueva clase interactuable en código, todavía necesitas agregar ese componente a una entidad en el editor (o generar una entidad y agregar el componente en tiempo de ejecución).
{% endhint %}

#### Ejemplo de basura

```go
// Obtén monedas por recoger la basura :D
Trash :: class : Interactable {
    @ao_serialize coins: s64;
    used: bool;

    ao_start :: method() {
        this.set_listener(this);
        this.set_text("Recoger basura");
        this.set_hold_text("Recogiendo...");
        required_hold_time = 0.25;
        radius = 1.25;
    }

    can_use :: method(player: Player) -> bool {
        if used return false;
        return true;
    }

    on_interact :: method(player: Player) {
        used = true;
        Economy.deposit_currency(player, "Coins", coins);
        entity.destroy();
    }
}
```

#### Ejemplo de crecimiento

Un interactuable que “hace crecer” una entidad (una vez):

```go
Grow_Button :: class : Interactable {
    @ao_serialize scale_multiplier: float;
    used: bool;

    ao_start :: method() {
        this.set_listener(this);
        this.set_text("Crecer");
        radius = 1.25;
        required_hold_time = 0;
    }

    can_use :: method(player: Player) -> bool {
        return !used;
    }

    on_interact :: method(player: Player) {
        used = true;
        new_scale := entity.local_scale * scale_multiplier;
        entity.set_local_scale(new_scale);
        this.set_text("Ya usado");
    }
}
```

#### Ejemplo de compra mediante indicación

Un interactuable que solicita la compra de un producto:

```go
Buy_Admin_Pass :: class : Interactable {
    @ao_serialize product_id: string;

    ao_start :: method() {
        this.set_listener(this);
        this.set_text("Comprar pase de administrador");
        radius = 1.25;
    }

    can_use :: method(player: Player) -> bool {
        // Ejemplo de control: ocultar si ya se posee (pase de juego)
        return !Purchasing.owns_product(player, product_id);
    }

    on_interact :: method(player: Player) {
        Purchasing.prompt_purchase(player, product_id);
    }
}
```

### Referencia de la API

```go
Interactable :: class : Component {
    // Texto compartido de la indicación (interacción por toque); no por jugador.
    get_text :: method() -> string;
    set_text :: method(text: string);

    // Texto compartido de la indicación mientras se mantiene pulsado (para mantener para interactuar).
    get_hold_text :: method() -> string;
    set_hold_text :: method(text: string);

    // Subtítulo compartido de la indicación.
    get_subtitle :: method() -> string;
    set_subtitle :: method(text: string);

    // Vincula un objeto oyente que implementa:
    // - can_use(player: Player) -> bool
    // - on_interact(player: Player)
    // - on_holding(player: Player) [opcional]
    set_listener :: method(new_listener: Component);

    // Campos comunes (configurados en el editor o en código)
    offset: v2;
    prompt_offset: v2;
    radius: float;
    required_hold_time: float;
    priority: s64;
    subtitle_color: v4;
}
```

### Ganchos opcionales del jugador (reglas globales)

También puedes implementar estos en tu `Player` clase para aplicar reglas de todo el juego (por ejemplo, no poder usar interactuables antes de reaparecer):

```go
Player :: class : Player_Base {
    ao_can_use_interactable :: method(interactable: Interactable) -> bool {
        return true;
    }

    ao_on_interactable_used :: method(interactable: Interactable) {
    }

    ao_on_holding_interactable :: method(interactable: Interactable) {
    }
}
```
