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.
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.
Writing an NPC creation script
- Create Project > Create > ZEPETO > TypeScript and rename it to NPCCreator.
- 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.
- After you have finished writing the script, add the script to the NPC object.
- Assign the Zepeto Id in the inspector.
- Zepeto Id : The ZEPETO ID of the NPC.
- Press the play button to execute and the NPC will be created.
- Add an NPC location object in the same way, and add an NPC script to create multiple NPCs easily.
Labeling NPC
You can label your NPC with name tags to distinguish them from players.
To create the Name Tag Canvas Prefab
- Create a Hierachy > UI > Canvas and rename it PrefNameTagCanvas.
- Set the Render Mode to World Space.
- 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.
- 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.
Creating NPC Name Tag Script
- Create a Project > Create > ZEPETO > TypeScript and rename it to NPCCreatorWithNameTag.
- 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.
- After you have finished writing the script, add it to the NPC object.
- 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.
- press the play button to execute, and the NPC with the name tag will be created.
Controlling NPC Behavior
You can control the actions of NPC.
Jumping
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
- Go to Project > Create > ZEPETO > Create TypeScript and rename it to NPCJump.
- 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.
- After you have finished writing the script, add the script to the NPC object.
- Press the Play button and the NPC will jump.
Gesture
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
- Project > Create > Create Animator Controller and rename it to NPCAnimatorController.
- On the Animator tab, Create State > Empty.
- In the Inspector, rename it appropriately and assign the animation clip to Motion.
Creating an NPC Gesture Script
- Create a Project > Create > ZEPETO > TypeScript and rename it to NPCGesture.
- 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.
- After you finish writing the script, add it to the Location object where the NPC will be created.
- In the Inspector, assign the Zepeto Id, Npc Animator.
- Npc Animator: The NPC's animation controller.
- Press the play button to run it and you'll see the NPC make a gesture.
- 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.
Creating a Speech Bubble Canvas Prefab
- Create a Hierarchy> UI > Canvas and rename it to PrefSpeechBubbleCanvas.
- Set the Render Mode to World Space.
- 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.
- 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.
- 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.
Creating NPC Speech Bubble Script
- Create a Project > Create > ZEPETO > TypeScript and rename it to NPCSpeechBubble.
- 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.
- After you have finished writing the script, add it to the Location object where the NPC will be created.
- 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.
- 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.
Setting up the Collider
- Add a Collider component to your object to interact with the NPC and check isTrigger.
- Resize the Collider to the extent that the player can interact with the NPC.
Creating an NPC Interaction Script
- Create Project > Create > ZEPETO > TypeScript and rename it to NPCInteraction.
- 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.
- After you have finished writing the script, add it to the Location object where the NPC will be created.
- 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.
- 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.
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);
}
}