# Avatares NPC

Muestra un avatar como una entidad en una escena.

{% hint style="info" %}
**💡 Consejo**: Prueba el [NPC Toolkit library](https://github.com/decentraland-scenes/dcl-npc-toolkit) para una experiencia más fácil al tratar con NPCs, especialmente si necesitas interactuar mediante un árbol de conversación.
{% endhint %}

## Crear un avatar

El siguiente fragmento crea un avatar con wearables y body shape aleatorios, y nombre "NPC".

```ts
const myAvatar = engine.addEntity()
AvatarShape.create(myAvatar)

Transform.create(myAvatar, {
	position: Vector3.create(4, 0.25, 5),
})
```

Al pasar datos para generar un `AvatarShape`, los siguientes campos son obligatorios:

* `id`: (obligatorio) Identificador interno para el Avatar

También están disponibles los siguientes campos opcionales:

* `name`: Nombre para mostrar sobre la cabeza del Avatar. Por defecto: "NPC".
* `bodyShape`: String para definir qué body shape usar. Las opciones válidas son 'urn:decentraland:off-chain:base-avatars:BaseMale' y 'urn:decentraland:off-chain:base-avatars:BaseFemale'.
* `wearables`: Array con la lista de URNs de wearables que el avatar lleva puestos actualmente. Si los wearables entran en conflicto (por ejemplo, dos son sombreros), el último en la lista reemplaza al otro.
* `emotes`: Array con la lista de URNs de emotes NFT que el avatar puede reproducir
* `eyeColor`: *Color3* para el color de los ojos (cualquier color es válido)
* `skinColor`: *Color3* para el color de la piel (cualquier color es válido)
* `hairColor`: *Color3* para el color del cabello (cualquier color es válido)
* `talking`: Si *true*, muestra un conjunto de barras verdes junto al nombre, como cuando los jugadores usan chat de voz en el mundo.
* <div data-gb-custom-block data-tag="hint" data-style="info" class="hint hint-info"><p><strong>💡 Consejo</strong>: Ver <a href="../conceptos-esenciales-de-contenido-3d/color-types">color types</a> para más detalles sobre cómo establecer colores.</p></div>

{% hint style="warning" %}
**📔 Nota**: El `AvatarShape`component must be imported via

> `import { AvatarShape } from "@dcl/sdk/ecs"`

Ver [Imports](https://docs.decentraland.org/creator/content-creator-es/primeros-pasos/coding-scenes#imports) para cómo manejarlos fácilmente.
{% endhint %}

{% hint style="warning" %}
**📔 Nota**: Los campos URN deben seguir el mismo formato usado para [NFTShapes](https://docs.decentraland.org/creator/content-creator-es/scenes-sdk7/media/display-a-certified-nft): `urn:decentraland:<CHAIN>:<CONTRACT_STANDARD>:<CONTRACT_ADDRESS>:<TOKEN_ID>`
{% endhint %}

## Animaciones

Los Avatars reproducen animaciones idle por defecto mientras están quietos.

Para reproducir animaciones en el avatar, asigna el `expressionTriggerId` string al nombre de la animación que quieres reproducir.

```ts
const myAvatar = engine.addEntity()
AvatarShape.create(myAvatar, {
	id: '',
	emotes: [],
	wearables: [],
	expressionTriggerId: 'robot',
})

Transform.create(myAvatar, {
	position: Vector3.create(4, 0.25, 5),
})
```

El `expressionTriggerId` campo admite todas las [default animations](https://docs.decentraland.org/creator/content-creator-es/scenes-sdk7/player-avatar#default-animations), así como animaciones personalizadas [from a scene file](https://docs.decentraland.org/creator/content-creator-es/scenes-sdk7/player-avatar#custom-animations), e incluso URNs de emotes que están publicados en el Marketplace.

### Animaciones en bucle

Las animaciones en un `AvatarShape` se reproducen una vez; si quieres que el avatar siga repitiendo una animación, deberías crear un sistema que le indique reproducir la animación de nuevo cada un par de segundos.

Usa el `expressionTriggerTimestamp` para volver a reproducir un mismo emote. El valor de este campo es un [lamport timestamp](https://en.wikipedia.org/wiki/Lamport_timestamp), lo que significa que no es un valor de tiempo, sino más bien un índice que se incrementa en 1 por cada repetición del emote.

Así que la primera vez que reproduces un emote, estableces `expressionTriggerTimestamp` a *0*. Para reproducir el emote de nuevo, debes actualizar este valor a 1. Así es como el engine sabe que ésta es una nueva instrucción, y no una instrucción sobre la que ya actuó.

El siguiente fragmento crea un sistema que ejecuta un mismo emote cada 2 segundos:

```ts
const myAvatar = engine.addEntity()
AvatarShape.create(myAvatar, {
	id: '',
	emotes: [],
	wearables: [],
	expressionTriggerId: 'clap',
    expressionTriggerTimestamp: 0
})

Transform.create(myAvatar, {
	position: Vector3.create(4, 0.25, 5),
})

let clapTimer = 0
let emoteDuration = 2  // 2 segundos

// system
engine.addSystem((dt: number) => {
    clapTimer += dt
      
    if (clapTimer >= emoteDuration) {
        // Disparar el emote de aplauso
        AvatarShape.getMutable(wearable).expressionTriggerTimestamp =+ 1 
        
        clapTimer = 0 // Reiniciar el temporizador
    }
})
```

{% hint style="info" %}
**💡 Consejo**: Debes conocer la duración del emote, y hacer que esa sea la duración del sistema. Si creas un emote que deja al avatar quieto en la misma pose, es recomendable hacer la duración del emote más larga que la del sistema. De esa manera, puedes asegurarte de que no haya artefactos al finalizar y reiniciar la animación.
{% endhint %}

## Copiar wearables del jugador

El siguiente fragmento cambia los wearables y otras características de un avatar NPC para que coincidan con los que el jugador lleva puestos actualmente. Esto podría usarse en una escena como un maniquí, para mostrar un wearable o emote particular combinado con el atuendo actual del jugador.

```ts
import { getPlayer } from '@dcl/sdk/src/players'


export function swapAvatar(avatar: Entity) {

  let userData = getPlayer()
  console.log(userData)

  if (!userData || !userData.wearables) return

  const mutableAvatar = AvatarShape.getMutable(avatar)

  mutableAvatar.wearables = userData.wearables
  mutableAvatar.bodyShape = userData.avatar?.bodyShapeUrn
  mutableAvatar.eyeColor = userData.avatar?.eyesColor
  mutableAvatar.skinColor = userData.avatar?.skinColor
  mutableAvatar.hairColor = userData.avatar?.hairColor
  
}
```

## Mostrar solo wearables

Usa el `show_only_wearables` campo para mostrar solo los wearables listados de un avatar. El resto del cuerpo del avatar será invisible.

```ts
const myAvatar = engine.addEntity()
AvatarShape.create(myAvatar, {
	id: '',
	emotes: [],
	wearables: [
    'urn:decentraland:matic:collections-v2:0x90e5cb2d673699be8f28d339c818a0b60144c494:0'
  ],
	showOnlyWearables: true,
})

Transform.create(myAvatar, {
	position: Vector3.create(4, 0.25, 5),
})
```

Esto es útil para mostrar wearables, por ejemplo en una tienda.

{% hint style="info" %}
**💡 Consejo**: Si un wearable es bastante pequeño, intenta establecer la `scale` del `Transform` a un valor más grande.
{% endhint %}

## Adjuntar una entidad a un NPC

Puedes usar el `AvatarAttach` para fijar una entidad a uno de los huesos de un avatar NPC, por ejemplo para que el NPC sostenga un objeto en su mano. La entidad se moverá junto con el avatar cuando éste anime.

Para usar esta función, utiliza la `id` propiedad en el `AvatarShape` para asignar un id arbitrario a este avatar, y luego referencia ese id en el `AvatarAttach`. El id puede ser cualquier string que quieras.

```ts
// Crear NPC, con un ID
const myAvatar = engine.addEntity()
Transform.create(myAvatar, {
  position: Vector3.create(8, 0.25, 8),
})
AvatarShape.create(myAvatar, {
  id: "my-avatar-id", 
  wearables: [],
  emotes: []
})

// Crear objeto para adjuntar al NPC
const attachedEntity = engine.addEntity()
Transform.create(attachedEntity, {
    position: Vector3.create(4, 2, 4),
    scale: Vector3.create(0.15,0.15,0.15)
})
MeshRenderer.setBox(attachedEntity)
Material.setBasicMaterial(attachedEntity, { diffuseColor: Color4.Blue() })
AvatarAttach.create(attachedEntity, {
    avatarId: "my-avatar-id",
    anchorPointId: AvatarAnchorPointType.AAPT_LEFT_HAND
})
```

Aprende más sobre el `AvatarAttach` component [aquí](https://docs.decentraland.org/creator/content-creator-es/conceptos-esenciales-de-contenido-3d/entity-positioning#attach-an-entity-to-an-avatar).
