---
title: 音声チャット機能の使用
slug: world-sdk-guide-ja/txySJN-NC5yszqn09uba_
docTags: 
createdAt: 2024-09-02T08:34:13.134Z
---

Zepeto.Voice.Chat プレビュー版パッケージは、ワールド内でのボイスチャットを可能にします。



## ZEPETO.Voice.Chatをインストールしてモードを設定する

1\) ウィンドウをインストール → パッケージマネージャー → ZEPETO.Voice.Chat。

:::hint{type="danger"}
- この機能は、マルチプレイヤー要素が実装されたワールドで利用可能です。
- テストはモバイルテストでのみ利用可能で、エディターテストでは利用できません。
- iOSポリシーにより、ボイスチャットが有効なワールドでマイクがオンのとき、デバイスの音量はゼロにはなりません。
  マイクがオフのとき、デバイスの音量はゼロになります。
:::



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

2\) 開発中のUnityプロジェクト画面の中央メニューにある\[▼]ボタンをクリックします。
表示されるポップアップメニューで\[ワールド設定を開く]ボタンをクリックします。

::Image[]{src="https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-FKLyhsT_NpGSs69hIudps-20240904-102425.png" size="72" width="362" height="224" position="center" showCaption="false"}



3\) ZEPETO.Voice.Chatパッケージが正しくインストールされている場合、ボイスチャットモードオプションが追加されます。

::Image[]{src="https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-mT_dx8P_ZKL9pl4pcE7-X-20240904-102425.png" size="62" width="416" height="453" position="center" showCaption="false"}



4\) ボイスチャットモードでは、希望するモードを設定してください。

- 基本: デフォルトで提供されるボイスチャット機能を使用します。
- スクリプト: ボイスチャットAPIを実装してボイスチャット機能を使用します。
  - ランタイムでボイスチャットのルームアクセスの入退室を処理できます。
  - 異なるチームのためにボイスチャットを実装します（例: 赤チームのボイスチャットと青チームのボイスチャット）
  - 現在話しているユーザーを検出する



## 基本モード：ボイスチャット機能の使用

基本モードのボイスチャットがある世界はこのようになります。

ボイスモジュレーション機能を使用して、より楽しいボイスチャットを作成することもできます。

ボイスチャット機能を持つワールドに入ると、ボイスチャットが自動的に有効になります。

:::hint{type="success"}
**👍&#x20;**&#x5A;EPETOでボイスチャット機能を初めて使用する際、マイクのアクセスに関するポップアップが表示されます。
ボイスチャット機能を使用するには、アクセスを許可する必要があります。
:::

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-1uuwxj2Ex-naVmnnoFpi2-20240904-102426.png "ボイスチャット機能を有効にすると、UIにボタンが自動的に表示されます")

![ボイスチャットボタンをタッチすることで使用できます](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-vVNrp9SxpJYzvoAy8gXAg-20240904-102425.png "ボイスチャットボタンをタッチすることで使用できます")



:::hint{type="danger"}
- ZEPETOアプリ3.26.000以上では、ボイスチャットスピーカーアイコンが表示されません。
- スピーチアイコンを表示させたい場合は、スクリプトモードに切り替え、自分のコードを書くためのガイドに従ってください。
:::



## スクリプトモード : VoiceChat APIの使用

スクリプトモードは、チームによって分けられたチャンネルでのボイスチャットを有効にします。

機能の説明と以下の例を参照して、機能を実装してください。

| **API**                                 | **説明**                                                                                                        |
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------- |
| OnInitializedEvent                      | 音声チャットAPIは、初期化イベントでTrueイベントが発生した後に利用可能です。<br />このイベントがTrueの場合、音声チャットが利用可能であり、Falseの場合は音声チャットが利用できません。         |
| EnterRoom(RoomProperty roomProperty)    | 音声チャットルームに入るための関数<br />- 音声チャットルームに正常に入った後、音声チャットボタンが表示されます。                                                  |
| ExitRoom()                              | 音声チャットルームを離れるための関数                                                                                            |
| OnRoomConnectedEvent                    | 音声チャットルームに入る状態を確認するためのイベント。<br />このイベントがtrueの場合、ユーザーは音声チャットルームに入っています。falseの場合、ユーザーは音声チャットルームを離れています。         |
| OnSpeechDetectedEvent\<string, boolean> | 音声チャットで現在話しているユーザーを検出するためのイベント。<br />- stringは話しているユーザーのuserId<br />- booleanは発話が始まるとtrue、発話が終了するとfalseになります。 |
| ChangeTeamID(number teamid)             | 音声チャットルームで使用するTeamIdを変更するための関数<br />- 1以上の整数値にのみ設定できます。                                                       |

### ルームプロパティクラス

| **API**      | **説明**                                                                                                                                                                                                                                                           |
| ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| SetAudioMode | ボイスチャットで使用するオーディオモード<br />- **AudioMode.Omnidirectional:** 距離に基づく音声減衰のないボイスチャットモード<br />(このモードはZEPETOキャラクターがあってもなくても使用できます)<br /><br /><br />- **AudioMode.Directional:** 距離に基づく音声減衰のあるボイスチャットモード<br />(ZEPETOキャラクターの位置に基づいて動作するため、シーンにZEPETOキャラクターが存在する必要があります) |
| SetTeamID    | ボイスチャットで同じTeamIdを持つユーザー間のボイスチャットを有効にするために使用されるTeamId。<br />- 整数値1以上に設定することができます                                                                                                                                                                                  |

### チーム特有のボイスチャット実装の例

ここにVoice Chat APIを試すためのサンプルコードがあります。

1\) ボタンを追加し、以下の画像のようにテキストをキャンバスにログとして表示して、ボイスチャットチームチャンネルに入ります。ステータスログを表示します。

- ボタン
  - Button\_blueTeam : 青チームボイスチャット入場ボタン
  - Button\_redTeam : 赤チームボイスチャット入場ボタン
  - Button\_exit : ボイスチャット退出ボタン
- テキスト
  - Text\_log : チャットログを表示するテキスト
  - Text\_team : 同じボイスチャットチームチャンネルのメンバーリストを表示するテキスト
  - Text\_currentSpeaking : 現在ボイスチャットで話しているユーザーIDを表示するテキスト。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-euodAMUXM6E3-jg4tSzzL-20240904-102425.png)



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

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

:::CodeblockTabs
VoiceChatTest

```typescript
import { Button, InputField, Text } from 'UnityEngine.UI';
import { ZepetoScriptBehaviour } from 'ZEPETO.Script'
import { AudioMode, RoomProperty, VoiceChatController } from 'ZEPETO.Voice.Chat'
 
export default class VoiceChatTest extends ZepetoScriptBehaviour {
 
    // Declare UI components as public members
    public BlueTeamButton: Button;
    public RedTeamButton: Button;
    public exitRoomButton: Button;
    public logText: Text;
    public currentTeamIDText: Text;
    public currentSpeakingUserIDsText: Text;
     
    // Declare private members to store speaking user IDs and team ID input field
    private currentSpeakingUserIDs: string[];   
    private teamIDInputField: InputField;
 
    Start() {
        this.currentSpeakingUserIDs = new Array();
         
        // Add event listeners for button clicks
        this.BlueTeamButton.onClick.AddListener(()=>{
            this.EnterBlueTeam();
        });
        this.RedTeamButton.onClick.AddListener(()=>{
            this.EnterRedTeam();
        });
        this.exitRoomButton.onClick.AddListener(()=>{
            this.ExitVoiceChatRoom();
        });
 
        // Add event listeners for Voice Chat Controller
        VoiceChatController.OnInitializedEvent.AddListener(init => this.OnInitialized(init));
        VoiceChatController.OnRoomConnectedEvent.AddListener(connected => this.OnRoomConnected(connected));
        VoiceChatController.OnSpeechDetectedEvent.AddListener((userId, speechDetected) => this.OnSpeechDetected(userId, speechDetected));
         
        this.logText.text = "[VoiceChat] VoiceChatTest Start";
    }
 
    // OnDestroy method called when the script is destroyed
    OnDestroy() {
        VoiceChatController.OnInitializedEvent.RemoveAllListeners();
        VoiceChatController.OnRoomConnectedEvent.RemoveAllListeners();
        VoiceChatController.OnSpeechDetectedEvent.RemoveAllListeners();
    }
 
    // Method called when the Voice Chat system is initialized
    private OnInitialized(initialized: boolean) {
        this.logText.text = "[VoiceChat] OnInitialized: " + initialized;
    }
 
     // Method called when the Voice Chat room is connected
    private OnRoomConnected(connected: boolean) {
        this.logText.text = "[VoiceChat] OnRoomConnected: " + connected;
    }
 
    // Method called when a user's speech is detected or not detected
    private OnSpeechDetected(userId: string, speechDetected: boolean) {
        this.logText.text = "[VoiceChat] OnSpeechDetected: " + userId + ", " + speechDetected;
 
        if (speechDetected) {
            this.currentSpeakingUserIDs.push(userId);
        }
        else {
            let index = this.currentSpeakingUserIDs.indexOf(userId);
            this.currentSpeakingUserIDs.splice(index, 1);
        }
 
        let userIds = "[CurrentSpeakingUserIDs]\n";
        for (let i = 0; i < this.currentSpeakingUserIDs.length; i++) {
            userIds += this.currentSpeakingUserIDs[i];
            userIds += "\n";
        }
 
        this.currentSpeakingUserIDsText.text = userIds;
    }
 
    // Method to enter the blue team's Voice Chat room
    public EnterBlueTeam(){
        this.EnterVoiceChatRoom(2);
    }
 
    // Method to enter the red team's Voice Chat room
    public EnterRedTeam(){
        this.EnterVoiceChatRoom(3);
    }
 
    // Method to enter a Voice Chat room based on the given team index
    private EnterVoiceChatRoom(teamIndex: number) {
        console.log("[VoiceChat] EnterVoiceChatRoom");
 
        // Create a new RoomProperty object and set its properties
        let roomProperty = new RoomProperty();
        roomProperty.SetAudioMode(AudioMode.Omnidirectional);
        roomProperty.SetTeamID(teamIndex);
        VoiceChatController.EnterRoom(roomProperty);
        this.currentTeamIDText.text = "TeamID: " + roomProperty.TeamId.toString();
    }
 
    // Method to exit the Voice Chat room
    public ExitVoiceChatRoom() {
        this.logText.text = "[VoiceChat] ExitVoiceChatRoom";
        VoiceChatController.ExitRoom();
    }
 
    // Method to change the team ID for the current user
    public ChangeTeamID() {
        // Get the new team ID from the input field and parse it as an integer
        let teamID = parseInt(this.teamIDInputField.text);
        this.logText.text = "[VoiceChat] ChangeTeamID: " + teamID;
        this.currentTeamIDText.text = "TeamID: " + teamID.toString();
        // Change the team ID in the Voice Chat system
        VoiceChatController.ChangeTeamID(teamID);
    }
 
}
```
:::



- コードの説明
  - スクリプトが実行されると、Start()関数内の各ボタンにイベントが登録され、VoiceChatControllerにOnInitialized、OnRoomConnected、OnSpeechDetectedイベントが登録されます。
  - 青チームボタンまたは赤チームボタンがクリックされると、EnterVoiceChatRoom()関数が実行され、ユーザーは指定されたRoomPropertyを入力することでボイスチャットルームに入ります。例のルームプロパティは以下の通りです。
    - **roomProperty.SetAudioMode :** AudioMode.Omnidirectional。オムニディレクショナルオーディオモードは、プレイヤーの位置に関係なく音量が同じになるモードです。対照的に、ディレクショナルモードは3Dサウンドモードであり、キャラクターの位置によって音量が異なるため、キャラクターが遠くなるほど音量が小さくなります。
    - **roomProperty.SetTeamID :** 青チームはチャンネル2、赤チームはチャンネル3。SetTeamIDはボイスチャットのチャンネルのように機能します。チャンネル2に入ったチームはチャンネル2のプレイヤーとしかボイスチャットできず、チャンネル3に入ったチームはチャンネル3のプレイヤーとしかボイスチャットできません。
  - ExitVoiceChatRoom()は現在のボイスチャットチームチャンネルから退出します。
  - OnSpeechDetected()は、現在ボイスチャットを使用しているプレイヤーIDをチームチャンネルのログテキストに出力します。



4\) スクリプトを完成させた後、インスペクターでステップ1で作成したボタンとテキストを割り当てます。

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



5\) QRコードまたはテストリンクを介してモバイルでテストを実行すると、チームに参加ボタンが押されたときにボイスチャットのアクティベーションボタンが作成され、プレイヤーが話すたびにログにどのプレイヤーがボイスチャットにいるかが表示されます。以下の画面に示されています。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-eqa8jcnJifdqPWRi_gfiS-20240904-102426.gif)



### ボイスチャットのスピーチバブル画像の表示例

ZEPETOアプリ3.26.000以降のバージョンでは、ボイスチャットの発話アイコンは表示されません。
発話アイコンを表示させたい場合は、ガイドに従って自分のコードを書く必要があります。

1\) プレイヤーがボイスチャットにいるときにキャラクターの頭上にスピーチバブルを表示するには、スピーチバブル画像を使用するプレハブを作成する必要があります。以下のように使用したいスピーチバブルPNG画像をインポートし、そのテクスチャタイプをスプライトに変更します。

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



2\) プロジェクト > 作成 > プレハブとし、名前をChatBubbleに変更します。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-FAeAB-SKLLJO2mSUsRMYI-20240904-102425.png)



3\) ChatBubbleプレハブをダブルクリックしてプレハブ編集モードに入ります。ChatBubbleプレハブを選択し、Transform > Position > Y値を0.35に変更します。

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



4\) プレハブオブジェクト内にキャンバスを作成します。

- ChatBubbleプレハブをダブルクリックしてプレハブ編集モードに入り、Hierarchy > UI > Canvasを追加します。
- キャンバスのRectTransformコンポーネントの値を以下のように変更します。
  - PosX: 0 , posY: 0
  - 幅: 100, 高さ: 100
  - ScaleX: 0.005, ScaleY: 0.005, ScaleZ: 0.005
- キャンバスコンポーネントのRenderMoveをワールドスペースに変更します。

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



5\) キャンバス内にスピーチバブル画像を作成します。

- Hierarchy > UI > Imageをキャンバスの子として追加し、ChatBubbleImageに名前を変更します。
- ChatBubbleImageのRectTransformコンポーネントの値を以下のように変更します。
  - 幅 42, 高さ:42
- ステップ1でインポートした画像スプライトを、イメージコンポーネントのソース画像として登録します。

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



:::hint{type="success"}
👍 **ヒント**

- スピーチバブルの画像スプライトをアニメーション化することもできます。
- 異なるチームのために別々のバブル画像を使用することもできます。
:::



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

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

:::CodeblockTabs
VoiceChatBubbleController

```typescript
import { GameObject, Object } from 'UnityEngine';
import { KnowSockets, ZepetoPlayers } from 'ZEPETO.Character.Controller'
import { ZepetoScriptBehaviour } from 'ZEPETO.Script'
import { AudioMode, RoomProperty, VoiceChatController } from 'ZEPETO.Voice.Chat';
 
export default class VoiceChatBubbleController extends ZepetoScriptBehaviour {
 
    // ボイスチャットバブルプレハブを格納するためのパブリックGameObject変数
    public voiceChatPrefab: GameObject;
 
    // ユーザーIDに関連付けられたGameObjectを格納するためのプライベートマップ
    private _voiceBubbleMap: Map<string, GameObject> = new Map<string, GameObject>();
 
    Start() {
        // ボイスチャットコントローラーのイベントリスナーを追加
        VoiceChatController.OnInitializedEvent.AddListener(init => this.OnInitialized(init));
        VoiceChatController.OnRoomConnectedEvent.AddListener(connected => this.OnRoomConnected(connected));
        VoiceChatController.OnSpeechDetectedEvent.AddListener((userId, speechDetected) => this.OnSpeechDetected(userId, speechDetected));
    }
 
    // ボイスチャットシステムが初期化されたときに呼ばれるメソッド
    private OnInitialized(initialized: boolean) {
        console.log("[VoiceChat] OnInitialized: ");
        this.EnterVoiceChatRoom(1);
    }
 
    // ボイスチャットルームが接続されたときに呼ばれるメソッド
    private OnRoomConnected(connected: boolean) {
        console.log("[VoiceChat] OnRoomConnected: ");
    }
 
    // 指定されたチームインデックスに基づいてボイスチャットルームに入るメソッド
    private EnterVoiceChatRoom(teamIndex: number) {
        console.log("[VoiceChat] EnterVoiceChatRoom");
 
        // 新しいRoomPropertyオブジェクトを作成し、そのプロパティを設定
        let roomProperty = new RoomProperty();
        roomProperty.SetAudioMode(AudioMode.Omnidirectional);
        VoiceChatController.EnterRoom(roomProperty);
    }
 
    // ユーザーのスピーチが検出されたときまたは検出されなかったときに呼ばれるメソッド
    private OnSpeechDetected(userId: string, speechDetected: boolean) {
        console.log("[VoiceChat] OnSpeechDetected: " + userId + ", " + speechDetected);
 
        // ユーザーIDがボイスバブルマップにない場合、ボイスバブルを作成
        if (!this._voiceBubbleMap.has(userId)) {
            this.CreateVoiceBubble(userId);
        }
 
        this.SetVoiceBubble(userId, speechDetected);
    }
 
    // 指定されたユーザーIDのボイスバブルのアクティブ状態を設定するメソッド
    private SetVoiceBubble(userId: string, speechDetected: boolean) {
        const chatBubble = this._voiceBubbleMap.get(userId);
        chatBubble.SetActive(speechDetected);
    }
 
    // 指定されたユーザーIDのためのボイスバブルを作成するメソッド
    private CreateVoiceBubble(userId: string) {
 
        // ユーザーキャラクターの頭のソケットを取得
        const headSocket = ZepetoPlayers.instance.GetPlayerWithUserId(userId).character.GetSocket(KnowSockets.HEAD_UPPER);
 
        // 頭のソケット位置にボイスチャットバブルプレハブをインスタンス化
        const instanceBubble = Object.Instantiate(this.voiceChatPrefab, headSocket) as GameObject;
 
        // インスタンス化されたバブルをボイスバブルマップに追加
        this._voiceBubbleMap.set(userId, instanceBubble);
        instanceBubble.SetActive(false);
    }
 
    LateUpdate() {

        // ボイスバブルマップが空かどうかを確認し、空であれば戻る
        if (this._voiceBubbleMap.size === 0) {
            return;
        }

        // ボイスバブルマップを反復処理し、各バブルGameObjectの回転を更新
        this._voiceBubbleMap.forEach((bubbleObject: GameObject) => {
            // バブルオブジェクトの回転をカメラの親トランスフォームの回転に合わせる
            bubbleObject.transform.rotation = ZepetoPlayers.instance.ZepetoCamera.cameraParent.transform.rotation;
        });

    }
 
}
```
:::



- コードの説明
  - スクリプトが実行されると、Start()関数内の各ボタンにイベントが登録され、VoiceChatControllerのOnInitialized、OnRoomConnected、OnSpeechDetectedイベントが登録されます。
  - OnInitialized()の後、プレイヤーがワールドに入るとVoice Chatボタンが画面に表示され、ボタンを押すとEnterVoiceChatRoom()が実行されてVoice Chatルームに入ります。
  - プレイヤーがVoiceChatをアクティブにして話すたびに、OnSpeechDetected()が実行され、speechDetectedがtrueの場合はBubbleChatオブジェクトが有効になり、falseの場合は無効になります。
  - OnSpeechDetected()関数が初めてアクティブになると、CreateVoiceBubble()がvoiceChatPrefab GameObjectをプレイヤーの頭上に浮かせるためにインスタンス化し、\_voiceBubbleMapにマップデータとして登録します。
  - LateUpdate()を使用して、ZEPETOワールドのCameraParentに合わせて毎フレーム音声チャットバブルの回転を更新します。これにより、スピーチバブルの画像が常にカメラを向くようになります。最初に\_voiceBubbleMapが空かどうかを確認し、そうでなければスピーチバブル画像のプレハブの回転を更新します。



8\) スクリプトの記述が完了したら、インスペクタでVoiceChatPrefabエントリをSTEP 1で作成したスピーチバブルプレハブとして割り当てます。

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



9\) QRコードまたはテストリンクを介してモバイルで実行すると、プレイヤーが音声チャットを使用するたびにキャラクターの頭上にスピーチバブル画像が表示されるはずです。



## 音声変調

ボイスチャットバージョン0.2.1-previewから、スクリプトモードでボイスチャットの声を変調できます。

::embed[[https://www.youtube.com/watch?v=yXfPuQyPbqk](https://www.youtube.com/watch?v=yXfPuQyPbqk)]{url="https://www.youtube.com/watch?v=yXfPuQyPbqk"}



APIガイドとサンプルコードを使用して音声変調を試してみてください。

| **音声タイプ (enum)** | **値** | **説明** |
| ---------------- | ----- | ------ |
| タイプ00            | 0     | オリジナル  |
| タイプ01            | 1     | チップマンク |
| タイプ02            | 2     | おじ     |
| タイプ03            | 3     | エコー    |
| タイプ04            | 4     | 深い声    |
| タイプ05            | 5     | ロボット   |
| タイプ06            | 6     | 方言     |
| タイプ07            | 7     | メガホン   |
| タイプ08            | 8     | 獣      |
| タイプ09            | 9     | 機械     |
| タイプ10            | 10    | 強い流れ   |
| タイプ11            | 11    | 子供     |
| タイプ12            | 12    | ハリネズミ  |



ここに声の変調のサンプルスクリプトがあります。

```javascript
import { Button } from 'UnityEngine.UI';
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { RoomProperty, VoiceChatController, VoiceType } from 'ZEPETO.Voice.Chat';

export default class VoiceModulationManager extends ZepetoScriptBehaviour {
 
    // 異なる音声タイプを設定するためのボタン
    public buttons: Button[];
 
    Start() {
        const voiceTypes = [
            VoiceType.Type00,
            VoiceType.Type01,
            VoiceType.Type05,
            VoiceType.Type03,
        ];
 
        for (const [index, button] of this.buttons.entries()) {
            button.onClick.AddListener(() => {
                // クリックされたボタンのインデックスに対応する音声タイプを設定
                VoiceChatController.SetVoiceType(voiceTypes[index]);
            });
        };
 
        // ボイスチャットシステムが初期化されたときに呼ばれるメソッド
        VoiceChatController.OnInitializedEvent.AddListener(
            init => {
                VoiceChatController.EnterRoom(new RoomProperty());;
            }
        );
 
        // ボイスチャットルームに接続されたときに呼ばれるメソッド
        VoiceChatController.OnRoomConnectedEvent.AddListener(
            connected => {
                // 初期音声タイプを設定し、ループバックを有効にする
                VoiceChatController.SetVoiceType(voiceTypes[0]);
                VoiceChatController.EnableLoopback(true);
            }
        );
    }
 
    // ボイスチャットルームを退出するためのメソッド
    OnDestroy() {
        VoiceChatController.OnInitializedEvent.RemoveAllListeners();
        VoiceChatController.OnRoomConnectedEvent.RemoveAllListeners();
    }
}
```

- コードの説明：
  - 各ボタンに異なる音声変調タイプを設定するためのonClickリスナーを追加します。
    - 同じインデックスの要素が`ボタン`配列と`音声タイプ`配列が一致します。
  - ワールドに入ると、`VoiceChatController`が初期化され、ルーム接続が自動的に確立されます。
  - 初期の音声変調タイプは`Type00`に設定され、ループバックが有効になり、自分の声を聞くことができます。
    - 呼び出しのために注意してください、`SetVoiceType`と`EnableLoopback`には、ルーム接続が必要です。したがって、初期設定は`OnRoomConnectedEvent`のリスナー内で処理されます。



![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-gDF6X-7KgtHpythXUaKcU-20240904-102426.png)



## ローカルプレイヤーの音声再生位置を変更する



ローカルプレイヤーのボイスチャット位置を変更するには、`VoiceChatController.SetLocalPlayerTransform()`を使用します。

これを使用すると、ボイスチャットで話すときに特定の空間やオブジェクトの位置に設定することで、さまざまなシナリオを作成できます。



:::hint{type="info"}
**📘 ヒント**
ボイスチャットのトランスフォームは、ローカルプレイヤーのZEPETOキャラクターのトランスフォームにリンクしています。

したがって、ローカルプレイヤーのZEPETOキャラクターがワールド内に作成されていない場合、あなたの声は伝達されない可能性があります。

この場合、現在のシーン内で音声再生位置を設定することでボイスチャットを使用できます。`SetLocalPlayerTransform()`.
:::



| **API**                                                                         | **説明**                     |
| ------------------------------------------------------------------------------- | -------------------------- |
| `public static SetLocalPlayerTransform($transform: UnityEngine.Transform):void` | ローカルプレイヤーの音声再生位置を変更するための関数 |



:::hint{type="danger"}
**❗️ 注意**
`SetLocalPlayerTransform()` は、ボイスチャットが初期化された後に、`VoiceChatController.OnInitializedEvent(true)` を呼び出す必要があります。
:::



1\) 以下は、音声位置変更機能のサンプルスクリプトです。

:::CodeblockTabs
VoiceTransformSample

```typescript
import { GameObject, Transform, Vector3 } from 'UnityEngine';
import { Button } from 'UnityEngine.UI';
import { ZepetoScriptBehaviour } from 'ZEPETO.Script';
import { AudioMode, RoomProperty, VoiceChatController } from 'ZEPETO.Voice.Chat';

export default class VoiceTransformSample extends ZepetoScriptBehaviour {

    // 音声変換を近くに設定するボタン
    public buttonCloserTransform: Button;

    // 音声変換を遠くに設定するボタン
    public buttonFartherTransform: Button;

    // 音声位置の変換
    private voiceTransform: Transform;

    Start() {

        // 新しいGameObjectを作成し、音声変換オブジェクトを格納するための変換を割り当てる
        const voiceTransformObject = new GameObject;  
        this.voiceTransform = voiceTransformObject.transform;

        // 音声チャットシステムが初期化されたときに呼び出されるメソッド
        VoiceChatController.OnInitializedEvent.AddListener(
            init => {
                let roomProperty = new RoomProperty();

                // 音声モードを方向性3D空間音声に設定
                roomProperty.SetAudioMode(AudioMode.Directional);
                VoiceChatController.EnterRoom(roomProperty);  

                // ローカルプレイヤーの音声のための音声チャット変換を設定
                VoiceChatController.SetLocalPlayerTransform(this.voiceTransform);
            }
        );
        
        // 'buttonCloseTransform'がクリックされたときに音声変換位置を(0,0,0)に設定
        this.buttonCloserTransform.onClick.AddListener(()=>{
            this.voiceTransform.position = Vector3.zero;
        })
        
        // 'buttonFarTransform'がクリックされたときに音声変換位置を遠くの点に設定
        this.buttonFartherTransform.onClick.AddListener(()=>{
            this.voiceTransform.position = new Vector3(0,0,-10);
        })

    }

    // 音声チャットルームを退出するためのメソッド
    OnDestroy() {
        VoiceChatController.OnInitializedEvent.RemoveAllListeners();
        VoiceChatController.OnRoomConnectedEvent.RemoveAllListeners();
    }

}
```
:::

コードの説明

- シーンが始まるとき、`Start()`関数内にvoiceTransformObjectというゲームオブジェクトを作成し、voiceTransformにTransformを登録します。
- ボイスチャットが`OnInitialized`リスナーが呼び出されるとき、次の設定を適用してください：
- ボイスチャットを3D空間オーディオモードに設定します。`SetAudioMode(AudioMode.Directional)`.
- ローカルプレイヤーのボイスチャット位置をvoiceTransformに設定します。`VoiceChatController.SetLocalPlayerTransform()`.
- buttonCloserTransformは、ボタンがクリックされたときにvoiceTransformの位置を原点(0, 0, 0)に設定します。
- buttonFartherTransformは、ボタンがクリックされたときにvoiceTransformの位置を(10, 0, 0)に設定します。



2\) シーン内のCanvasにボタンを登録し、VoiceTransformSampleコンポーネントのbuttonCloserTransformとbuttonFartherTransformに接続します。

![](https://api.archbee.com/api/optimize/fCt3n1oCa8rgNJ8fw9I2N-cr-0SWeexanSXeb-6NHj5-20240904-102426.png)



3\) QRコードまたはテストリンクを使用してモバイルフォンで実行すると、次のことを確認できます。

- クローザーボタンを押すと、あなたの声は他の人に近く聞こえます。
- ファーザーボタンを押すと、あなたの声は他の人から遠く聞こえます。



::embed[[https://www.youtube.com/watch?v=Y_pj4RCshts](https://www.youtube.com/watch?v=Y_pj4RCshts)]{url="https://www.youtube.com/watch?v=Y_pj4RCshts"}

