---
title: NPCを作成
slug: world-sdk-guide-ja/npc
docTags: 
createdAt: 2024-09-02T08:34:13.135Z
---

ZEPETOキャラクターからNPCを作成する方法を学びましょう。

各機能に提供されているサンプルスクリプトを適用して、あなたのワールドに選択したNPCを追加します。



ZEPETO IDを使用してNPCを作成します。

::Image[]{src="https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-6t3GXLriXPmQFtlwSRTpI-20240904-102416.png" size="64" width="2072" height="1702" position="center" showCaption="false"}



:::hint{type="danger"}
- NPCの外見と着用するアイテムは、入力されたZEPETO IDと同じになります。
- NPCを作成する前に、特定の外見を持つZEPETOキャラクターを設定することをお勧めします。
:::



### NPCが作成される場所オブジェクトの設定



- シーンにZEPETOキャラクター作成コードをデフォルトで実装します。

:::hint{type="info"}
**📘&#x20;**&#x6B21;のガイドを参照してください。\[[ZEPETOキャラクターを作成する](docId\:X3HPJvYg3lwW0PU1r8k1s)]
:::



- 階層を作成 > 空のオブジェクトを作成し、NPCに名前を変更します。
  - NPCが作成される場所を保存するオブジェクト。
  - 位置と回転を設定します。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-Q1f-ytfigV8Dq1mSrbw9H-20240904-102416.png)



### NPC作成スクリプトの作成



1\) プロジェクトを作成 > 作成 > ZEPETO > TypeScript とし、NPCCreatorに名前を変更します。

2\) 以下のようなサンプルスクリプトを書きます。

```typescript
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { SpawnInfo, ZepetoCharacter, ZepetoCharacterCreator } from 'ZEPETO.Character.Controller';
  
export default class NPCCreator extends ZepetoScriptBehaviour {
  
    // NPCのZEPETO ID
    public zepetoId: string;
    // NPCキャラクターオブジェクト
    private _npc: ZepetoCharacter;
  
    Start() {
        // SpawnInfoの新しいインスタンスを作成し、オブジェクトのトランスフォームに基づいてその位置と回転を設定します
        const spawnInfo = new SpawnInfo();
        spawnInfo.position = this.transform.position;
        spawnInfo.rotation = this.transform.rotation;
  
        // Zepeto IDを使用して新しいキャラクターを作成し、それを_npc変数に割り当てるためにZepetoCharacterCreatorを使用します
        ZepetoCharacterCreator.CreateByZepetoId(this.zepetoId, spawnInfo, (character: ZepetoCharacter) => {
            this._npc = character;
        })
    }
  
}
```



スクリプトの流れは次のとおりです：

- Start()
  - ZepetoCharacterCreator.CreateByZepetoId()関数を使用してNPCオブジェクトの位置にNPCを作成し、それを\_npcに保存します。



3\) スクリプトの記述が完了したら、NPCオブジェクトにスクリプトを追加します。

4\) インスペクターでZepeto IDを割り当てます。

- Zepeto ID : NPCのZEPETO ID。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-eddQgXlREGkYHgxSGffvE-20240904-102416.png "例のスクリプト設定画面")



5\) 実行するために再生ボタンを押すと、NPCが作成されます。

6\) 同様にNPCの位置オブジェクトを追加し、複数のNPCを簡単に作成するためのNPCスクリプトを追加します。

::Image[]{src="https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-n-EI7bbyvulqtYh2xM4Fi-20240904-102416.png" size="70" width="2162" height="1554" position="center" showCaption="false"}



# NPCのラベリング



プレイヤーと区別するために、名前タグでNPCにラベルを付けることができます。

::Image[]{src="https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-1wBC20gR8-tyjJfLNDdAz-20240904-102416.png" size="64" width="2240" height="1766" position="center" showCaption="false"}



### 名前タグキャンバスプレハブを作成する



1\) 階層 > UI > キャンバスを作成し、PrefNameTagCanvasに名前を変更します。

- レンダーモードをワールドスペースに設定します。

::Image[]{src="https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-V4rHI2xgMMHikJ1q6_HxT-20240904-102416.png" size="50" width="422" height="698" position="center" caption="キャンバス設定の例" showCaption="true"}



2\) PrefNameTagCanvasの子として階層 > UI > テキストを作成し、NameTagTextに名前を変更します。

- 名前を表すテキスト。
- テキストを適切なサイズにするために、コンテンツサイズフィッターコンポーネントを追加します。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-K-9H7mFnVL2HIgV3MAI8k-20240904-102416.png "テキスト設定の例")



3\) 完了したら、プロジェクトウィンドウにドラッグしてプレハブにし、ハイライターにまだ残っているPrefNameTagCanvasを削除します。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-3P9qMV8rV0RdM4ejqtS2A-20240904-102416.png "プレハブ設定の例")



### NPC名札スクリプトの作成



1\) プロジェクトを作成 > 作成 > ZEPETO > TypeScript とし、NPCCreatorWithNameTagに名前を変更します。

2\) 以下のようにサンプルスクリプトを書きます。

```typescript
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 {

    // NPCのZEPETO ID
    public zepetoId: string;
    // 名札に表示される名前 
    public nameTag: string;
    // 名札キャンバスゲームオブジェクトのプレハブ
    public nameTagPrefab: GameObject;
    // 名札キャンバスゲームオブジェクトのY軸オフセット値
    public nameTagYOffset: number;

    // NPCキャラクターオブジェクト
    private _npc: ZepetoCharacter;
    // 名札キャンバスゲームオブジェクト
    private _npcNameTagObject: GameObject;
    // 名札キャンバスゲームオブジェクト内のテキスト
    private _npcNameTagText: Text;
    // 名札キャンバス
    private _canvas: Canvas;
    // ワールドカメラ
    private _cachedWorldCamera: Camera;

    Start() {
        // SpawnInfoの新しいインスタンスを作成し、オブジェクトのトランスフォームに基づいて位置と回転を設定
        const spawnInfo = new SpawnInfo();
        spawnInfo.position = this.transform.position;
        spawnInfo.rotation = this.transform.rotation;

        // ZepetoCharacterCreatorを使用してZEPETO IDで新しいキャラクターを作成し、_npc変数に割り当て
        ZepetoCharacterCreator.CreateByZepetoId(this.zepetoId, spawnInfo, (character: ZepetoCharacter) => {
            this._npc = character;

            // 名札を設定
            this.SetNameTag();
        })
    }

    // 名札を設定
    SetNameTag() {
        // 名札キャンバスゲームオブジェクトを動的に作成
        this._npcNameTagObject = Object.Instantiate(this.nameTagPrefab) as GameObject;
        
        // 名札キャンバスゲームオブジェクトの親をNPCのトランスフォームに設定
        this._npcNameTagObject.transform.SetParent(this._npc.transform);
        
        // NPCの頭の上に名札キャンバスゲームオブジェクトの位置を設定
        this._npcNameTagObject.transform.position = Vector3.op_Addition(this._npc.GetSocket(KnowSockets.HEAD_UPPER).position, new Vector3(0, this.nameTagYOffset,0));

        // 名札内のテキストを設定
        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();
        }
    }

    // 名札キャンバスの回転をカメラに向けて更新
    private UpdateCanvasRotation() {
        this._canvas.transform.LookAt(this._cachedWorldCamera.transform);
        this._canvas.transform.Rotate(0, 180, 0);
    }

}
```



スクリプトの流れは次のとおりです：

- 開始する()
  - SetNameTag() カスタム関数を呼び出します。
- SetNameTag()
  - NPCのために動的に名前タグを生成し、生成された名前タグをNPCの頭上に調整します。
  - 名前タグの中のテキストを設定します。
- 更新する()
  - UpdateCanvasRotation() カスタム関数を呼び出して、カメラに合わせてキャンバスを回転させます。



3\) スクリプトの記述が完了したら、NPCオブジェクトに追加します。

4\) インスペクターで、Zepeto Id、名前タグ、名前タグプレハブ、および名前タグYオフセットを割り当てます。

- 名前タグ: NPCの名前タグに表示される名前。
- 名前タグプレハブ: 名前タグキャンバスのプレハブ。
- 名前タグYオフセット: 名前タグキャンバスオブジェクトのy軸オフセット値を格納する変数。キャラクターの頭上に名前タグを配置する際に、キャラクターと名前タグの間の距離を調整できます。

::Image[]{src="https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-1gmj-fFGOz1PvkIsEgzr1-20240904-102416.png" size="86" width="498" height="342" position="center" caption="スクリプト設定画面の例" showCaption="true"}



5\) 再生ボタンを押して実行すると、名前タグを持つNPCが作成されます。

::Image[]{src="https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-oTdyZ4V5rP2aOM-FG7gDz-20240904-102416.png" size="60" width="2058" height="1572" position="center" showCaption="false"}



# NPCの行動を制御する



NPCの行動を制御できます。



## ジャンプ



::Image[]{src="https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-kQCSmRiBt_OP-OkBovT_P-20240904-102417.gif" size="68" width="800" height="639" position="center" showCaption="false"}



ZEPETOキャラクターAPIを使用してNPCをジャンプさせます。

ZEPETOキャラクターAPIを使用して、より広範な動作を実装できます。

:::hint{type="info"}
**📘&#x20;**&#x4EE5;下のガイドを参照してください。\[[ZEPETOキャラクター](docId\:lMI7uxueCfHlfSvgCsRlO)]
:::



### NPCジャンプスクリプトの作成

1\) プロジェクト > 作成 > ZEPETO > TypeScriptを作成し、NPCJumpに名前を変更します。

2\) 以下のようにサンプルスクリプトを書きます。

```typescript
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { SpawnInfo, ZepetoCharacter, ZepetoCharacterCreator } from 'ZEPETO.Character.Controller';
import { WaitForSeconds } from 'UnityEngine';

export default class NPCJump extends ZepetoScriptBehaviour {

    // NPCのZEPETO ID
    public zepetoId: string;
    // NPCキャラクターオブジェクト
    private _npc: ZepetoCharacter;

    Start() {
        // SpawnInfoの新しいインスタンスを作成し、オブジェクトのトランスフォームに基づいて位置と回転を設定します
        const spawnInfo = new SpawnInfo();
        spawnInfo.position = this.transform.position;
        spawnInfo.rotation = this.transform.rotation;

        // ZepetoCharacterCreatorを使用してZEPETO IDで新しいキャラクターを作成し、_npc変数に割り当てます
        ZepetoCharacterCreator.CreateByZepetoId(this.zepetoId, spawnInfo, (character: ZepetoCharacter) => {
            this._npc = character;
            
            this.StartCoroutine(this.JumpCoroutine());
        });
    }

    *JumpCoroutine() {
        // 無限ループで継続的に
        while (true) {
            // ZepetoCharacterのJump()メソッドを呼び出してジャンプさせます
            this._npc.Jump();

            // 5秒待機
            yield new WaitForSeconds(5);
        }
    }
}
```

スクリプトの流れは次のとおりです：

- 開始()
  - JumpCoroutine()コルーチンを呼び出します。
- JumpCoroutine()
  - NPCキャラクターが5秒ごとにジャンプするようにJump()メソッドを呼び出します。



3\) スクリプトの記述が完了したら、スクリプトをNPCオブジェクトに追加します。

4\) 再生ボタンを押すと、NPCがジャンプします。



## ジェスチャー



::Image[]{src="https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-IxShgv_lsEN9qbJbGhkqH-20240904-102419.gif" size="68" width="800" height="639" position="center" showCaption="false"}



NPCのためにジェスチャーを実装するには、アニメーターコントローラーを使用します。

アニメーターコントローラーを使用すると、より多様な動作を実装できます。

:::hint{type="info"}
**📘 Unityアニメーターコントローラー**
[https://docs.unity3d.com/Manual/class-AnimatorController.html](https://docs.unity3d.com/Manual/class-AnimatorController.html)
:::



### アニメーションクリップの準備



- 以下のガイドを使用して、NPCが実行するためのジェスチャーアニメーションクリップを準備します。

:::hint{type="info"}
**📘&#x20;**&#x4EE5;下のガイドを参照してください。

- \[[ZEPETOキャラクターアニメーションの使用](docId\:FQjPvaRYpgvo1Jx0lKo4X)]
- \[[カスタムアニメーションを適用する方法](docId\:hTBui3CjUgc8jeiah7uVX)]
:::



### アニメーターの作成



1\) プロジェクト > 作成 > アニメーターコントローラーを作成し、NPCAnimatorControllerに名前を変更します。

::Image[]{src="https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-yRqBb0vmcd1uU09TWYxTZ-20240904-102416.png" size="68" width="612" height="773" position="center" showCaption="false"}



2\) アニメータータブで、状態を作成 > 空の状態。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-DimxMvgUSMikvwjWAXS49-20240904-102416.png)



3\) インスペクターで適切に名前を変更し、アニメーションクリップをモーションに割り当てます。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-M6b-vT5cSD0ZssJRPRq1w-20240904-102416.png)



### NPCジェスチャースクリプトの作成



1\) プロジェクトを作成 > 作成 > ZEPETO > TypeScript として名前を NPCGesture に変更します。

2\) 以下のようにサンプルスクリプトを書きます。

```typescript
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { SpawnInfo, ZepetoCharacter, ZepetoCharacterCreator } from 'ZEPETO.Character.Controller';
import { Animator, RuntimeAnimatorController } from 'UnityEngine';

export default class NPCGesture extends ZepetoScriptBehaviour {

    // NPCのZEPETO ID
    public zepetoId: string;
    // NPCのAnimator Controller
    public npcAnimator: RuntimeAnimatorController;

    // NPCキャラクターオブジェクト
    private _npc: ZepetoCharacter;

    Start() {

        // SpawnInfoの新しいインスタンスを作成し、オブジェクトのトランスフォームに基づいて位置と回転を設定します
        const spawnInfo = new SpawnInfo();
        spawnInfo.position = this.transform.position;
        spawnInfo.rotation = this.transform.rotation;

        // ZepetoCharacterCreatorを使用してZEPETO IDによって新しいキャラクターを作成し、_npc変数に割り当てます
        ZepetoCharacterCreator.CreateByZepetoId(this.zepetoId, spawnInfo, (character: ZepetoCharacter) => {
            this._npc = character;

            // NPCキャラクターからAnimatorコンポーネントを取得し、そのruntimeAnimatorControllerをnpcAnimatorに設定します
            this._npc.GetComponentInChildren<Animator>().runtimeAnimatorController = this.npcAnimator;
        });
    }
}
```



スクリプトの流れは次のとおりです：

- Start()
  - NPCオブジェクトのAnimatorコンポーネントを取得し、npcAnimator変数で指定されたAnimator Controllerに設定します。



3\) スクリプトの記述が終わったら、NPCが作成されるLocationオブジェクトに追加します。

4\) インスペクターで、Zepeto Id、Npc Animatorを割り当てます。

- Npc Animator: NPCのアニメーションコントローラー。

::Image[]{src="https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-CgJYDlgaLNgzETWd9RfCB-20240904-102416.png" size="60" width="499" height="299" position="center" showCaption="false"}



5\) 再生ボタンを押して実行すると、NPCがジェスチャーをするのが見えます。

6\) ジェスチャーやジャンプ以外のアクションを行うNPCを作成するためにこれを適用できます。



# NPCの上の吹き出し



NPCの頭の上にキャンバスを作成し、画像やテキストを表示してバブルにすることができます。

::Image[]{src="https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-y1YkAff-EjrFNU79j-DES-20240904-102416.png" size="72" width="2344" height="1746" position="center" showCaption="false"}



### 吹き出しキャンバスプレハブの作成

1\) 階層 > UI > キャンバスを作成し、名前をPrefSpeechBubbleCanvasに変更します。

- レンダーモードをワールドスペースに設定します。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-uk0mM_BrabzsikogLJFqs-20240904-102416.png)



2\) PrefSpeechBubbleCanvasの子として階層 > UI > 画像を作成し、名前をSpeechBubbleImageに変更します。

- これはスピーチバブルの背景となる画像です。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-u8wdp_2mKNd2U3MIGpE7i-20240904-102416.png "画像設定の例")



3\) 階層を作成 > UI > SpeeachBubbleImageの子としてテキストを作成し、名前をSpeeachBubbleTextに変更します。

- これはスピーチバブルの中のテキストです。
- テキストのサイズを適切にするために、Content Size Fitterコンポーネントを追加します。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-KCY849QEh54QbG-8DA_7t-20240904-102416.png "テキスト設定の例")



4\) 完了したら、プロジェクトウィンドウにドラッグしてPrefabにし、ハイライトにまだ残っているPrefSpeechBubbleCanvasを削除します。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-PpAK7gLrLZb7h0kGbzRWo-20240904-102416.png "Prefab設定の例")



### NPCスピーチバブルスクリプトの作成



1\) プロジェクトを作成 > 作成 > ZEPETO > TypeScriptを選択し、名前をNPCSpeechBubbleに変更します。

2\) 以下のようにサンプルスクリプトを書いてください。

```typescript
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 {

    // NPCのZEPETO ID
    public zepetoId: string;
    // スピーチバブルに表示されるダイアログ内容
    public speechBubbleText: string;
    // スピーチバブルキャンバスゲームオブジェクトのプレハブ
    public speechBubblePrefab: GameObject;
    // スピーチバブルキャンバスゲームオブジェクトのY軸オフセット値
    public speechBubbleYOffset: number;

    // NPCキャラクターオブジェクト
    private _npc: ZepetoCharacter;
    // スピーチバブルキャンバスゲームオブジェクト
    private _speechBubbleObject: GameObject;
    // スピーチバブルキャンバスゲームオブジェクト内のテキスト
    private _speechBubbleText: Text;
    // スピーチバブルキャンバス
    private _canvas: Canvas;
    // ワールドカメラ
    private _cachedWorldCamera: Camera;
    
    Start() {
        // SpawnInfoの新しいインスタンスを作成し、オブジェクトのトランスフォームに基づいてその位置と回転を設定
        const spawnInfo = new SpawnInfo();
        spawnInfo.position = this.transform.position;
        spawnInfo.rotation = this.transform.rotation;

        // ZepetoCharacterCreatorを使用してZEPETO IDによって新しいキャラクターを作成し、_npc変数に割り当て
        ZepetoCharacterCreator.CreateByZepetoId(this.zepetoId, spawnInfo, (character: ZepetoCharacter) => {
            this._npc = character;
            
            // スピーチバブルを設定
            this.SetBubble();
        })
    }

    // スピーチバブルを設定
    SetBubble() {
        // スピーチバブルキャンバスゲームオブジェクトを動的に作成
        this._speechBubbleObject = Object.Instantiate(this.speechBubblePrefab) as GameObject;

        // スピーチバブルキャンバスゲームオブジェクトの親をNPCのトランスフォームに設定
        this._speechBubbleObject.transform.SetParent(this._npc.transform);
        
        // NPCの頭の上にスピーチバブルキャンバスゲームオブジェクトの位置を設定
        this._speechBubbleObject.transform.position = Vector3.op_Addition(this._npc.GetSocket(KnowSockets.HEAD_UPPER).position, new Vector3(0, this.speechBubbleYOffset,0));

        // スピーチバブル内のテキストを設定
        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;
    }

    // スピーチバブルキャンバスを開き、テキストを設定
    SetBubbleText(bubbleText: string) {
        this._speechBubbleObject.SetActive(true);
        this._speechBubbleText.text = bubbleText;
    }

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

    // スピーチバブルキャンバスの回転をカメラに向けて更新
    private UpdateCanvasRotation() {
        this._canvas.transform.LookAt(this._cachedWorldCamera.transform);
        this._canvas.transform.Rotate(0, 180, 0);
    }

}
```



スクリプトの流れは次のとおりです：

- 開始()
  - SetBubble() カスタム関数を呼び出します。
- SetBubble()
  - スピーチバブルキャンバス (speechBubblePrefab) を作成し、作成したスピーチバブルをNPCの頭の上に配置します。
  - SetBubbleText() カスタム関数を呼び出して、スピーチバブル内のテキストを設定します。
- SetBubbleText()
  - NPCのスピーチバブルキャンバス (\_speechBubbleObject) をアクティブにします。
  - スピーチバブル内にパラメータとして与えられた文字列 (bubbleText) を表示します。
- 更新()
  - UpdateCanvasRotation() カスタム関数を呼び出して、キャンバスをカメラに合わせて回転させます。



3\) スクリプトの記述が完了したら、NPCが作成される場所のオブジェクトに追加します。

4\) インスペクターで、Zepeto Id、スピーチバブルテキスト、スピーチバブルプレハブ、スピーチバブルYオフセットを割り当てます。

- スピーチバブルテキスト: この変数は、NPCキャラクターがスピーチバブルで言うダイアログを保存します。私たちの例では、次のダイアログを保存します: "こんにちは世界"。
- スピーチバブルプレハブ: この変数は、スピーチバブルキャンバスゲームオブジェクトのプレハブを保存します。
- スピーチバブルYオフセット: この変数は、スピーチバブルキャンバスゲームオブジェクトのY軸オフセット値を保存します。これにより、キャラクターの頭上にスピーチバブルを配置する際に、キャラクターとスピーチバブルの間の距離を調整できます。

::Image[]{src="https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-gIn4E4c0m0HetSALlRzLb-20240904-102416.png" size="76" width="499" height="342" position="center" caption="例のスクリプト設定画面" showCaption="true"}

5\) 再生ボタンを押して実行すると、NPCの頭上にスピーチバブルが浮かんでいるのが見えます。



# NPCとのインタラクション



NPCと対話することで、たくさんの楽しいコンテンツを実装できます。

このガイドでは、NPCに近づくと変化する吹き出しを実装する例を使用します。

::Image[]{src="https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-rlzfSSbfFzCHSTypmkC5v-20240904-102419.gif" size="42" width="800" height="639" position="center" showCaption="false"}



### コライダーの設定



1\) NPCと対話するためにオブジェクトにコライダーコンポーネントを追加し、isTriggerを確認します。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-fLpIWDpR24sxEAh5j_GSL-20240904-102416.png)



2\) プレイヤーがNPCと対話できる範囲にコライダーをリサイズします。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-l5kXKnIsuXNjgVTvjUdSx-20240904-102416.png)



### NPCインタラクションスクリプトの作成



1\) プロジェクトを作成 > 作成 > ZEPETO > TypeScript として名前を NPCInteraction に変更します。

2\) 以下のようにサンプルスクリプトを書きます。

```typescript
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 {

    // NPCのZEPETO ID
    public zepetoId: string;
    // スピーチバブルに表示されるダイアログ内容
    public speechBubbleText: string;

    public changedSpeechBubbleText: string;
    // スピーチバブルキャンバスゲームオブジェクトのプレハブ
    public speechBubblePrefab: GameObject;
    // スピーチバブルキャンバスゲームオブジェクトのy軸オフセット値
    public speechBubbleYOffset: number;

    // ローカルキャラクターオブジェクト
    private _zepetoCharacter: ZepetoCharacter;
    // NPCキャラクターオブジェクト
    private _npc: ZepetoCharacter;
    // スピーチバブルキャンバスゲームオブジェクト
    private _speechBubbleObject: GameObject;
    // スピーチバブルキャンバスゲームオブジェクト内のテキスト
    private _speechBubbleText: Text;
    // スピーチバブルキャンバス
    private _canvas: Canvas;
    // ワールドカメラ
    private _cachedWorldCamera: Camera;
    
    Start() {
        // SpawnInfoの新しいインスタンスを作成し、オブジェクトのトランスフォームに基づいて位置と回転を設定
        const spawnInfo = new SpawnInfo();
        spawnInfo.position = this.transform.position;
        spawnInfo.rotation = this.transform.rotation;

        // ZepetoCharacterCreatorを使用してZEPETO IDによって新しいキャラクターを作成し、_npc変数に割り当て
        ZepetoCharacterCreator.CreateByZepetoId(this.zepetoId, spawnInfo, (character: ZepetoCharacter) => {
            this._npc = character;
            
            // スピーチバブルを設定
            this.SetBubble();
        })

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

    // プレイヤーキャラクターがコライダーに入ったか確認
    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);
    }


    // スピーチバブルを設定
    SetBubble() {
        // スピーチバブルキャンバスゲームオブジェクトを動的に作成
        this._speechBubbleObject = Object.Instantiate(this.speechBubblePrefab) as GameObject;

        // スピーチバブルキャンバスゲームオブジェクトの親をNPCのトランスフォームに設定
        this._speechBubbleObject.transform.SetParent(this._npc.transform);
        
        // NPCの頭の上にスピーチバブルキャンバスゲームオブジェクトの位置を設定
        this._speechBubbleObject.transform.position = Vector3.op_Addition(this._npc.GetSocket(KnowSockets.HEAD_UPPER).position, new Vector3(0, this.speechBubbleYOffset,0));

        // スピーチバブル内のテキストを設定
        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;
    }

    // スピーチバブルキャンバスを開き、テキストを設定
    SetBubbleText(bubbleText: string) {
        this._speechBubbleObject.SetActive(true);
        this._speechBubbleText.text = bubbleText;
    }

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

    // スピーチバブルキャンバスの回転をカメラに向けて更新
    private UpdateCanvasRotation() {
        this._canvas.transform.LookAt(this._cachedWorldCamera.transform);
        this._canvas.transform.Rotate(0, 180, 0);
    }
    
}
```



スクリプトの流れは次のとおりです：

- OnTriggerEnter(), OnTriggerExit()
  - トリガーがコライダーエリアに入ると検出されたとき、SetBubbleText()カスタム関数を呼び出して、スピーチバブル内のテキストをchangedSpeechBubbleTextに設定します。
  - コライダーエリアを離れると、SetBubbleText()カスタム関数を呼び出して、スピーチバブル内のテキストをspeechBubbleTextに設定します。



3\) スクリプトの記述が完了したら、NPCが作成されるLocationオブジェクトに追加します。

4\) インスペクターで、Zepeto Id、スピーチバブルテキスト、スピーチバブルプレハブ、スピーチバブルYオフセット、および変更されたスピーチバブルを割り当てます。

- スピーチバブルテキスト: この変数は、NPCキャラクターがスピーチバブルで言うダイアログを格納します。私たちの例では、次のダイアログを格納します: "こんにちは世界"。
- スピーチバブルプレハブ: この変数は、スピーチバブルキャンバスGameObjectのプレハブを格納します。
- スピーチバブルYオフセット: この変数は、スピーチバブルキャンバスGameObjectのy軸オフセット値を格納します。これにより、キャラクターの頭上にスピーチバブルを配置する際に、キャラクターとスピーチバブルの間の距離を調整できます。
- 変更されたスピーチバブル: プレイヤーがNPCのコライダーに入ると、NPCのスピーチバブルに表示されるダイアログを格納します。

::Image[]{src="https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-WtOJ3nQKqkxWUSPkqN65j-20240904-102416.png" size="82" width="502" height="189" position="center" caption="スクリプト設定画面の例" showCaption="true"}



5\) プレイを押して実行し、プレイヤーがNPCに近づくと、吹き出しのテキストが変わります。



### NPCインタラクションの適用



ダイアログ形式を作成するには、パネルを使用してUIを作成します。

以下は、パネルとボタンで構成されたシンプルなダイアログの例です。

::Image[]{src="https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-qQe1Xx8mTUbOapkLXU_-Z-20240904-102416.png" size="78" width="1452" height="910" position="center" showCaption="false"}



これは、NPCとインタラクションするときにダイアログを開き、各ボタンが押されたときにそれを処理する例のスクリプトです。

これを適用して、面白いコンテンツを実装します。

```typescript
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;
        });
        
        // ダイアログ - はいを選択
        this.yesButton.onClick.AddListener(() => {
            console.log("はい")
            this.npcDialogCanvas.SetActive(false);
        });

        // ダイアログ - いいえを選択
        this.noButton.onClick.AddListener(() => {
            console.log("いいえ")
            this.npcDialogCanvas.SetActive(false);
        });

    }

    // プレイヤーキャラクターがコライダーに入ったか確認
    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);
    }

}
```

