Studio GuideWorld SDK Guide
Log In

Creating and controlling NPCs

Learn how to create NPCs from ZEPETO Characters.

Apply the sample scripts provided for each feature to add the NPC of your choice to your World.


Creating an NPC


Create an NPC using a ZEPETO ID.

2072

❗️

Caution

  • The NPC's appearance and items worn will be the same as the ZEPETO ID entered.
  • It is recommended that you set up a ZEPETO character with a specific appearance before creating an NPC.

Setting the location object where the NPC will be created


  • Implement the ZEPETO character creation code in your Scene by default.

📘

Please refer to the following guide. [Create a ZEPETO Character]


  • Create Hierarchy > Create Empty Object and rename it to NPC.
    • An object to store the location where the NPC will be created.
    • Set the Position, Rotation.
846

Example Object Setting


Writing an NPC creation script


  1. Create Project > Create > ZEPETO > TypeScript and rename it to NPCCreator.
  2. Write a sample script like below.
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { SpawnInfo, ZepetoCharacter, ZepetoCharacterCreator } from 'ZEPETO.Character.Controller';
  
export default class NPCCreator extends ZepetoScriptBehaviour {
  
    // ZEPETO ID of the NPC
    public zepetoId: string;
    // NPC character object
    private _npc: ZepetoCharacter;
  
    Start() {
        // Create a new instance of SpawnInfo and set its position and rotation based on the object's transform
        const spawnInfo = new SpawnInfo();
        spawnInfo.position = this.transform.position;
        spawnInfo.rotation = this.transform.rotation;
  
        // Use ZepetoCharacterCreator to create a new character by Zepeto ID and assign it to _npc variable
        ZepetoCharacterCreator.CreateByZepetoId(this.zepetoId, spawnInfo, (character: ZepetoCharacter) => {
            this._npc = character;
        })
    }
  
}

The flow of the script is as follows:

  • Start()
    • Create an NPC in the NPC object location using the ZepetoCharacterCreator.CreateByZepetoId() function and save it in _npc.

  1. After you have finished writing the script, add the script to the NPC object.
  2. Assign the Zepeto Id in the inspector.
    • Zepeto Id : The ZEPETO ID of the NPC.
549

Example Script Setting Screen


  1. Press the play button to execute and the NPC will be created.
  2. Add an NPC location object in the same way, and add an NPC script to create multiple NPCs easily.
2162

Labeling NPC


You can label your NPC with name tags to distinguish them from players.

2240

To create the Name Tag Canvas Prefab


  1. Create a Hierachy > UI > Canvas and rename it PrefNameTagCanvas.
    • Set the Render Mode to World Space.
422

Example of Canvas Settings


  1. Create Hierarchy> UI > Text as a child of PrefNameTagCanvas and rename it to NameTagText.
    • The text to represent the name.
    • Add a Content Size Fitter component to make the text the right size.
2880

Example of Text Settings


  1. Once you're done, drag it to the Project window to make it a Prefab, and then delete the PrefNameTagCanvas that's still in the highlighter.
3584

Example of Prefab Configuration


Creating NPC Name Tag Script


  1. Create a Project > Create > ZEPETO > TypeScript and rename it to NPCCreatorWithNameTag.
  2. Write a sample script as shown below.
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { KnowSockets, SpawnInfo, ZepetoCharacter, ZepetoCharacterCreator } from 'ZEPETO.Character.Controller';
import { Canvas, Camera, Vector3, Object, GameObject } from 'UnityEngine';
import { Text } from 'UnityEngine.UI';

export default class NPCCreatorWithNameTag extends ZepetoScriptBehaviour {

    // ZEPETO ID of the NPC
    public zepetoId: string;
    // Name to be displayed in the name tag 
    public nameTag: string;
    // Prefab of the name tag canvas game object
    public nameTagPrefab: GameObject;
    // Y-axis offset value of the name tag canvas game object
    public nameTagYOffset: number;

    // NPC character object
    private _npc: ZepetoCharacter;
    // Name tag canvas game object
    private _npcNameTagObject: GameObject;
    // Text inside the name tag canvas game object
    private _npcNameTagText: Text;
    // Name tag canvas
    private _canvas: Canvas;
    // World Camera
    private _cachedWorldCamera: Camera;

    Start() {
        // Create a new instance of SpawnInfo and set its position and rotation based on the object's transform
        const spawnInfo = new SpawnInfo();
        spawnInfo.position = this.transform.position;
        spawnInfo.rotation = this.transform.rotation;

        // Use ZepetoCharacterCreator to create a new character by ZEPETO ID and assign it to _npc variable
        ZepetoCharacterCreator.CreateByZepetoId(this.zepetoId, spawnInfo, (character: ZepetoCharacter) => {
            this._npc = character;

            // Set the name tag
            this.SetNameTag();
        })
    }

    // Set the name tag
    SetNameTag() {
        // Dynamically create the name tag canvas game object
        this._npcNameTagObject = Object.Instantiate(this.nameTagPrefab) as GameObject;
        
        // Set the parent of the name tag canvas game object transform to be the NPC transform.
        this._npcNameTagObject.transform.SetParent(this._npc.transform);
        
        // Set the position of the name tag canvas game object above the NPC's head
        this._npcNameTagObject.transform.position = Vector3.op_Addition(this._npc.GetSocket(KnowSockets.HEAD_UPPER).position, new Vector3(0, this.nameTagYOffset,0));

        // Set the text inside the name tag
        this._npcNameTagText = this._npcNameTagObject.GetComponentInChildren<Text>();
        this._npcNameTagText.text = this.nameTag;

        this._canvas = this._npcNameTagObject.GetComponent<Canvas>();
        this._cachedWorldCamera = Object.FindObjectOfType<Camera>();
        this._canvas.worldCamera = this._cachedWorldCamera;
    }

    private Update() {
        if (this._canvas != null) {
            this.UpdateCanvasRotation();
        }
    }

    // Update the rotation of the name tag canvas to face the camera
    private UpdateCanvasRotation() {
        this._canvas.transform.LookAt(this._cachedWorldCamera.transform);
        this._canvas.transform.Rotate(0, 180, 0);
    }

}

The flow of the script is as follows:

  • Start()
    • Call the SetNameTag() custom function.
  • SetNameTag()
    • Dynamically generates a name tag for the NPC and adjusts the position of the generated name tag above the NPC's head
    • Set the text inside the name tag.
  • Update()
    • Call the UpdateCanvasRotation() custom function to rotate the canvas to match the camera.

  1. After you have finished writing the script, add it to the NPC object.
  2. In the Inspector, assign the Zepeto Id, Name Tag, Name Tag Prefab, and Name Tag Y Offset.
    • Name Tag: The name that will appear on the NPC's name tag.
    • Name Tag Prefab: The name tag canvas prefab.
    • Name Tag Y Offset: A variable that stores the y-axis offset value for the Name Tag Canvas object. When you place the name tag above the character's head, you can adjust the distance between the character and the name tag.
498

Example Script Setting Screen


  1. press the play button to execute, and the NPC with the name tag will be created.
2058

Controlling NPC Behavior


You can control the actions of NPC.


Jumping


800

Use the ZEPETO Character API to make the NPC jump.

You can use the ZEPETO Character API to implement a wider range of behaviors.

📘

Please refer to the following guide. [ZEPETOCharacter]


Creating an NPC Jump script

  1. Go to Project > Create > ZEPETO > Create TypeScript and rename it to NPCJump.
  2. Write a sample script as shown below.
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { SpawnInfo, ZepetoCharacter, ZepetoCharacterCreator } from 'ZEPETO.Character.Controller';
import { WaitForSeconds } from 'UnityEngine';

export default class NPCJump extends ZepetoScriptBehaviour {

    // ZEPETO ID of the NPC
    public zepetoId: string;
    // NPC character object
    private _npc: ZepetoCharacter;

    Start() {
        // Create a new instance of SpawnInfo and set its position and rotation based on the object's transform
        const spawnInfo = new SpawnInfo();
        spawnInfo.position = this.transform.position;
        spawnInfo.rotation = this.transform.rotation;

        // Use ZepetoCharacterCreator to create a new character by ZEPETO ID and assign it to _npc variable
        ZepetoCharacterCreator.CreateByZepetoId(this.zepetoId, spawnInfo, (character: ZepetoCharacter) => {
            this._npc = character;
            
            this.StartCoroutine(this.JumpCoroutine());
        });
    }

    *JumpCoroutine() {
        // Infinite loop to continuously
        while (true) {
            // Call the Jump() method of the ZepetoCharacter to make it jump
            this._npc.Jump();

            // Wait for 5 seconds 
            yield new WaitForSeconds(5);
        }
    }
}

The flow of the script is as follows:

  • Start()
    • Call the JumpCoroutine() coroutine.
  • JumpCoroutine()
    • Call the Jump() method to make the NPC character jump every 5 seconds.

  1. After you have finished writing the script, add the script to the NPC object.
  2. Press the Play button and the NPC will jump.

Gesture


800

Use the Animator Controller to implement gestures for NPC.

You can use the Animator Controller to implement a wider variety of behaviors.

📘

Unity Animator Controller

https://docs.unity3d.com/Manual/class-AnimatorController.html


Preparing your animation clip


  • Use the following guide to prepare the gesture animation clip for your NPC to perform.

📘

Please refer to the following guide.


Creating an Animator


  1. Project > Create > Create Animator Controller and rename it to NPCAnimatorController.
612
  1. On the Animator tab, Create State > Empty.


  1. In the Inspector, rename it appropriately and assign the animation clip to Motion.


Creating an NPC Gesture Script


  1. Create a Project > Create > ZEPETO > TypeScript and rename it to NPCGesture.
  2. Write a sample script as shown below.
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { SpawnInfo, ZepetoCharacter, ZepetoCharacterCreator } from 'ZEPETO.Character.Controller';
import { Animator, RuntimeAnimatorController } from 'UnityEngine';

export default class NPCGesture extends ZepetoScriptBehaviour {

    // The ZEPETO ID of the NPC
    public zepetoId: string;
    // The Animator Controller of the NPC
    public npcAnimator: RuntimeAnimatorController;

    // NPC character object
    private _npc: ZepetoCharacter;

    Start() {

        // Create a new instance of SpawnInfo and set its position and rotation based on the object's transform
        const spawnInfo = new SpawnInfo();
        spawnInfo.position = this.transform.position;
        spawnInfo.rotation = this.transform.rotation;

        // Use ZepetoCharacterCreator to create a new character by ZEPETO ID and assign it to _npc variable
        ZepetoCharacterCreator.CreateByZepetoId(this.zepetoId, spawnInfo, (character: ZepetoCharacter) => {
            this._npc = character;

            // Get the Animator component from the NPC character and set its runtimeAnimatorController to npcAnimator
            this._npc.GetComponentInChildren<Animator>().runtimeAnimatorController = this.npcAnimator;
        });
    }
}

The flow of the script is as follows:

  • Start()
    • Get the Animator component of the NPC object and set it to the Animator Controller specified by the npcAnimator variable.

  1. After you finish writing the script, add it to the Location object where the NPC will be created.
  2. In the Inspector, assign the Zepeto Id, Npc Animator.
    • Npc Animator: The NPC's animation controller.
499

Example Script Setting Screen


  1. Press the play button to run it and you'll see the NPC make a gesture.
  2. You can apply this to create NPCs that do more actions besides gestures and jumps.

Speech bubbles over NPC


You can create a Canvas above an NPC's head, display an image or text, and make it bubble.

2344

Creating a Speech Bubble Canvas Prefab

  1. Create a Hierarchy> UI > Canvas and rename it to PrefSpeechBubbleCanvas.
    • Set the Render Mode to World Space.
1440

Example of Canvas Settings


  1. Create a Hierarchy> UI > Image as a child of PrefSpeechBubbleCanvas and rename it to SpeechBubbleImage.
    • This is the image that will be the background of the speech bubble.
1925

Example of Image Settings


  1. Create Hierarchy> UI > Text as a child of SpeeachBubbleImage and rename it to SpeeachBubbleText.
    • This is the text inside the speech bubble.
    • Add a Content Size Fitter component to make the text the right size.
1921

Example of Text Settings


  1. Once you're done, drag it to the Project window to make it a Prefab, and then delete the PrefSpeechBubbleCanvas that is still in the Highlight.
1919

Example of Prefab Configuration


Creating NPC Speech Bubble Script


  1. Create a Project > Create > ZEPETO > TypeScript and rename it to NPCSpeechBubble.
  2. Write a sample script as shown below.
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { KnowSockets, SpawnInfo, ZepetoCharacter, ZepetoCharacterCreator } from 'ZEPETO.Character.Controller';
import { Canvas, Camera, Vector3, Object, GameObject } from 'UnityEngine';
import { Text } from 'UnityEngine.UI';

export default class NPCSpeechBubble extends ZepetoScriptBehaviour {

    // ZEPETO ID of the NPC
    public zepetoId: string;
    // Dialogue content to be displayed in the speech bubble
    public speechBubbleText: string;
    // Prefab of the speech bubble canvas game object
    public speechBubblePrefab: GameObject;
    // Y-axis offset value of the speech bubble canvas game object
    public speechBubbleYOffset: number;

    // NPC character object
    private _npc: ZepetoCharacter;
    // Speech bubble canvas game object
    private _speechBubbleObject: GameObject;
    // Text inside the speech bubble canvas game object
    private _speechBubbleText: Text;
    // Speech bubble canvas
    private _canvas: Canvas;
    // World Camera
    private _cachedWorldCamera: Camera;
    
    Start() {
        // Create a new instance of SpawnInfo and set its position and rotation based on the object's transform
        const spawnInfo = new SpawnInfo();
        spawnInfo.position = this.transform.position;
        spawnInfo.rotation = this.transform.rotation;

        // Use ZepetoCharacterCreator to create a new character by ZEPETO ID and assign it to _npc variable
        ZepetoCharacterCreator.CreateByZepetoId(this.zepetoId, spawnInfo, (character: ZepetoCharacter) => {
            this._npc = character;
            
            // Set the speech bubble
            this.SetBubble();
        })
    }

    // Set the speech bubble
    SetBubble() {
        // Dynamically create the speech bubble canvas game object
        this._speechBubbleObject = Object.Instantiate(this.speechBubblePrefab) as GameObject;

        // Set the parent of the  speech bubble canvas game object transform to be the NPC transform.
        this._speechBubbleObject.transform.SetParent(this._npc.transform);
        
        // Set the position of the speech bubble canvas game object above the NPC's head
        this._speechBubbleObject.transform.position = Vector3.op_Addition(this._npc.GetSocket(KnowSockets.HEAD_UPPER).position, new Vector3(0, this.speechBubbleYOffset,0));

        // Set the text inside the speech bubble
        this._speechBubbleText = this._speechBubbleObject.GetComponentInChildren<Text>();
        this.SetBubbleText(this.speechBubbleText);

        this._canvas = this._speechBubbleObject.GetComponent<Canvas>();
        this._cachedWorldCamera = Object.FindObjectOfType<Camera>();
        this._canvas.worldCamera = this._cachedWorldCamera;
    }

    // Open the speech bubble canvas and set the text
    SetBubbleText(bubbleText: string) {
        this._speechBubbleObject.SetActive(true);
        this._speechBubbleText.text = bubbleText;
    }

    private Update() {
        if (this._canvas != null) {
            this.UpdateCanvasRotation();
        }
    }

    // Update the rotation of the speech bubble canvas to face the camera
    private UpdateCanvasRotation() {
        this._canvas.transform.LookAt(this._cachedWorldCamera.transform);
        this._canvas.transform.Rotate(0, 180, 0);
    }

}

The flow of the script is as follows:

  • Start()
    • Call the SetBubble() custom function.
  • SetBubble()
    • Create a speech bubble canvas (speechBubblePrefab) and position the created speech bubble above the NPC's head
    • Call the SetBubbleText() custom function to set the text inside the speech bubble.
  • SetBubbleText()
    • Activates the NPC's speech bubble canvas (_speechBubbleObject).
    • Displays the string given as a parameter (bubbleText) inside the speech bubble.
  • Update()
    • Call the UpdateCanvasRotation() custom function to rotate the canvas to match the camera.

  1. After you have finished writing the script, add it to the Location object where the NPC will be created.
  2. In the Inspector, assign the Zepeto Id, Speech Bubble Text, Speech Bubble Prefab, and Speech Bubble Y Offset.
    • Speech Bubble Text: This variable stores the dialog that the NPC character will say in the speech bubble. In our example, we store the following dialog: "Hello World".
    • Speech Bubble Prefab: This variable stores the prefab for the Speech Bubble Canvas GameObject.
    • Speech Bubble Y Offset: This variable stores the y-axis offset value for the Speech Bubble Canvas GameObject. This allows you to adjust the distance between the character and the speech bubble when you place the speech bubble above the character's head.
499

Example Script Setting Screen

  1. press the play button to execute, and you will see a speech bubble floating above the NPC's head.

Interacting with NPC


You can implement a lot of fun content by interacting with NPCs.

In this guide, we will use an example to implement a speech bubble that changes when an NPC is approached.

800

Setting up the Collider


  1. Add a Collider component to your object to interact with the NPC and check isTrigger.


  1. Resize the Collider to the extent that the player can interact with the NPC.


Creating an NPC Interaction Script


  1. Create Project > Create > ZEPETO > TypeScript and rename it to NPCInteraction.
  2. Write a sample script as shown below.
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { KnowSockets, SpawnInfo, ZepetoCharacter, ZepetoCharacterCreator, ZepetoPlayers } from 'ZEPETO.Character.Controller';
import { Canvas, Camera, Vector3, Object, GameObject, Collider } from 'UnityEngine';
import { Text } from 'UnityEngine.UI';

export default class NPCInteraction extends ZepetoScriptBehaviour {

    // ZEPETO ID of the NPC
    public zepetoId: string;
    // Dialogue content to be displayed in the speech bubble
    public speechBubbleText: string;

    public changedSpeechBubbleText: string;
    // Prefab of the speech bubble canvas game object
    public speechBubblePrefab: GameObject;
    // y-axis offset value of the speech bubble canvas game object
    public speechBubbleYOffset: number;

    // Local character object
    private _zepetoCharacter: ZepetoCharacter;
    // NPC character object
    private _npc: ZepetoCharacter;
    // Speech bubble canvas game object
    private _speechBubbleObject: GameObject;
    // Text inside the speech bubble canvas game object
    private _speechBubbleText: Text;
    // Speech bubble canvas
    private _canvas: Canvas;
    // World Camera
    private _cachedWorldCamera: Camera;
    
    Start() {
        // Create a new instance of SpawnInfo and set its position and rotation based on the object's transform
        const spawnInfo = new SpawnInfo();
        spawnInfo.position = this.transform.position;
        spawnInfo.rotation = this.transform.rotation;

        // Use ZepetoCharacterCreator to create a new character by ZEPETO ID and assign it to _npc variable
        ZepetoCharacterCreator.CreateByZepetoId(this.zepetoId, spawnInfo, (character: ZepetoCharacter) => {
            this._npc = character;
            
            // Set the speech bubble
            this.SetBubble();
        })

        ZepetoPlayers.instance.OnAddedLocalPlayer.AddListener(() => {
            this._zepetoCharacter = ZepetoPlayers.instance.LocalPlayer.zepetoPlayer.character;
        });
    }

    // Check if Player character enter collider
    OnTriggerEnter(collider: Collider) {
        if (this._zepetoCharacter == null || collider.gameObject != this._zepetoCharacter.gameObject) {
            return;
        }
        this.SetBubbleText(this.changedSpeechBubbleText);
    }

    OnTriggerExit(collider: Collider) {
        if (this._zepetoCharacter == null || collider.gameObject != this._zepetoCharacter.gameObject) {
            return;
        }
        this.SetBubbleText(this.speechBubbleText);
    }


    // Set the speech bubble
    SetBubble() {
        // Dynamically create the speech bubble canvas game object
        this._speechBubbleObject = Object.Instantiate(this.speechBubblePrefab) as GameObject;

        // Set the parent of the  speech bubble canvas game object transform to be the NPC transform.
        this._speechBubbleObject.transform.SetParent(this._npc.transform);
        
        // Set the position of the speech bubble canvas game object above the NPC's head
        this._speechBubbleObject.transform.position = Vector3.op_Addition(this._npc.GetSocket(KnowSockets.HEAD_UPPER).position, new Vector3(0, this.speechBubbleYOffset,0));

        // Set the text inside the speech bubble
        this._speechBubbleText = this._speechBubbleObject.GetComponentInChildren<Text>();
        this.SetBubbleText(this.speechBubbleText);
        
        this._canvas = this._speechBubbleObject.GetComponent<Canvas>();
        this._cachedWorldCamera = Object.FindObjectOfType<Camera>();
        this._canvas.worldCamera = this._cachedWorldCamera;
    }

    // Open the speech bubble canvas and set the text
    SetBubbleText(bubbleText: string) {
        this._speechBubbleObject.SetActive(true);
        this._speechBubbleText.text = bubbleText;
    }

    private Update() {
        if (this._canvas != null) {
            this.UpdateCanvasRotation();
        }
    }

    // Update the rotation of the speech bubble canvas to face the camera
    private UpdateCanvasRotation() {
        this._canvas.transform.LookAt(this._cachedWorldCamera.transform);
        this._canvas.transform.Rotate(0, 180, 0);
    }
    
}

The flow of the script is as follows:

  • OnTriggerEnter(), OnTriggerExit()
    • When the trigger is detected by entering the collider area, call the SetBubbleText() custom function to set the text inside the speech bubble to changedSpeechBubbleText.
    • When it leaves the collider area, call the SetBubbleText() custom function to set the text inside the speech bubble to speechBubbleText.

  1. After you have finished writing the script, add it to the Location object where the NPC will be created.
  2. In the Inspector, assign the Zepeto Id, Speech Bubble Text, Speech Bubble Prefab, Speech Bubble Y Offset, and Changed Speech Bubble.
    • Speech Bubble Text: This variable stores the dialog that the NPC character will say in the speech bubble. In our example, we store the following dialog: "Hello World".
    • Speech Bubble Prefab: This variable stores the prefab for the Speech Bubble Canvas GameObject.
    • Speech Bubble Y Offset: This variable stores the y-axis offset value for the Speech Bubble Canvas GameObject. This allows you to adjust the distance between the character and the speech bubble when placing the speech bubble above the character's head.
    • Changed Speech Bubble: Stores the dialog that will be displayed in the NPC's speech bubble when the player enters the NPC's collider.
502

Example Script Setting Screen


  1. press play to execute, and when the player approaches the NPC, the text in the speech bubble will change.

Apply NPC interaction


To create a dialog format, create a UI using a panel.

The following is an example of a simple dialog composed of panels and buttons.

1452

This is an example script that opens dialogs when interacting with NPCs and processes them when each button is pressed.

Apply this to implement interesting content.

import { GameObject, HumanBodyBones, Object, Collider } from 'UnityEngine';
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { Button } from 'UnityEngine.UI';
import { ZepetoCharacter, ZepetoPlayers } from "ZEPETO.Character.Controller";

export default class NPCDialogInteraction extends ZepetoScriptBehaviour {

    public npcDialogCanvas: GameObject;
    public yesButton: Button;
    public noButton: Button;

    private _zepetoCharacter: ZepetoCharacter;

    Start() {

        ZepetoPlayers.instance.OnAddedLocalPlayer.AddListener(()=>{
            this._zepetoCharacter = ZepetoPlayers.instance.LocalPlayer.zepetoPlayer.character;
        });
        
        // Dialog - Select Yes
        this.yesButton.onClick.AddListener(() => {
            console.log("yes")
            this.npcDialogCanvas.SetActive(false);
        });

        // Dialog - Select No
        this.noButton.onClick.AddListener(() => {
            console.log("no")
            this.npcDialogCanvas.SetActive(false);
        });

    }

    // Check if Player character enter collider
    OnTriggerEnter(collider: Collider) {
        if (this._zepetoCharacter == null || collider.gameObject != this._zepetoCharacter.gameObject) {
            return;
        }
        this.npcDialogCanvas.SetActive(true);
    }

    OnTriggerExit(collider: Collider) {
        if (this._zepetoCharacter == null || collider.gameObject != this._zepetoCharacter.gameObject) {
            return;
        }
        this.npcDialogCanvas.SetActive(false);
    }

}