---
name: tags-y-servicios
description: Tags y atributos para que cada cosa del mundo la atienda un servicio, y los errores típicos de Touched. Úsala al escribir servicios del mundo.
enabled: true
---

# Tags y servicios: cómo el mundo le habla al código

## El patrón

- Todo lo que el mundo **hace** se declara con un **tag** de CollectionService en la parte, y si necesita un dato,
  con un **atributo** en esa misma parte. Un checkpoint es un tag más un número; un power-up, un tag más un nombre;
  una puerta, un tag más el nombre de la llave que la abre.
- **Cada tag lo atiende un único servicio.** El servicio usa `GetTagged` para lo que ya existe al arrancar y
  `GetInstanceAddedSignal` para lo que se añada después. Así una parte nueva con su tag funciona sola: no hay que
  tocar ningún script para añadir contenido.
- Un objeto puede llevar **varios tags** si hace varias cosas, y cada una la atiende su servicio: una barra que
  gira **y** mata lleva el tag de girar y el de matar.
- Los nombres de tags y atributos son un **contrato** entre el mapa y los servicios: úsalos tal cual, sin
  renombrarlos ni «mejorarlos», porque los demás pasos y los demás servicios cuentan con ellos.
- Los datos que cambian por jugador (progreso, inventario, monedas) **no** van en atributos de las partes del
  mundo: van en el servicio que los guarda por jugador.

## Vocabulario de ejemplo (recorridos y coleccionables)

| Tag | Atributo | Qué hace el servicio |
|---|---|---|
| `Checkpoint` | `Stage: number` | guarda el progreso del jugador y lo hace reaparecer encima al morir |
| `KillBrick` | — | mata al tocarla, salvo si el jugador tiene protección activa |
| `Coin` | `Value: number` | da esa cantidad y reaparece pasado un tiempo |
| `PowerUp` | `Type: string` | aplica el power-up de ese nombre y reaparece pasado un tiempo |
| `Disappearing` | — | se desvanece poco después de pisarla y vuelve pasados unos segundos |
| `Spinner` | `Speed: number` | gira sobre su centro a esa velocidad |
| `Mover` | `Offset: Vector3` | va y viene entre su posición y su posición más `Offset` |
| `LevelPortal` | `TargetLevel: number` | lleva al inicio de esa zona; `0` devuelve al punto de partida y da la recompensa final |

El mismo patrón sirve para puertas (`Door` con `Key`), interruptores (`Switch` con `Target`), zonas de daño
(`Damage` con `PerSecond`) o cualquier otra cosa que el mundo haga.

## Cómo evitar los errores típicos

- **`Touched` se dispara muchas veces por un solo toque.** Pon un debounce por jugador (una tabla con el jugador
  como clave y un `task.delay` que lo borre).
- **Saca al jugador desde la parte que tocó:** busca el `Model` ancestro de esa parte y pásaselo a
  `Players:GetPlayerFromCharacter`. Si no hay jugador, ignora el toque: también tocan las monedas, los NPC y los
  objetos sueltos.
- **Reaparecer sin destruir:** para que algo desaparezca un rato, pon la parte transparente y sin colisión, y
  devuélvela pasado el tiempo. Destruir y clonar rompe los tags y las conexiones.
- **El progreso solo sube.** Pisar un checkpoint viejo no puede bajar la etapa guardada.
- **Reaparece al jugador unos studs por encima** del checkpoint, o aparecerá dentro de la parte.
- **Nunca te fíes de nada que mande el cliente** para estos servicios: el que decide si un checkpoint cuenta, si
  una moneda se recoge o si una puerta se abre es el servidor.
