> 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-basicos-del-motor/interactables.md).

# Interactivos

<figure><img src="/files/9d15db561b74f6cc0fb142a362bf58ea745219c1" alt="An interact prompt near a world object"><figcaption></figcaption></figure>

### El componente Interactable

<figure><img src="/files/49d9a413efe9eee6e19fd0cbfde44f69d737bd0c" alt="Interactable component fields in the inspector"><figcaption></figcaption></figure>

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

El radio de interacción escala con la escala del mundo de la entidad, así que mantén la raíz interactable en escala 1 y escala un hijo visual cuando quieras que el alcance de interacción se mantenga fijo.

Para responder a la pulsación del interactable por parte del jugador, necesitarás escribir código CSL.

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

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 interactable 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 recogida de basura

```go
// Obtén monedas por recoger la basura :D
Trash :: class : Interactable {
    coins: s64 @ao_serialize;
    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 interactable que “agranda” una entidad (una sola vez):

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

    ao_start :: method() {
        this.set_listener(this);
        this.set_text("Agrandar");
        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 solicitud de compra

Un interactable que solicita la compra de un producto:

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

    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 restricción: ocultar si ya se posee (game pass)
        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 del aviso (interacción con toque)
    get_text :: method() -> string;
    set_text :: method(text: string);

    // Texto del aviso mientras se mantiene pulsado (para interactuar manteniendo pulsado)
    get_hold_text :: method() -> string;
    set_hold_text :: method(text: string);

    get_subtitle :: method() -> string;
    set_subtitle :: method(text: string);

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

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

### Hooks opcionales del jugador (reglas globales)

También puedes implementarlos en tu `Player` clase para aplicar reglas de todo el juego (p. ej., no puedes usar interactables 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) {
    }
}
```
