あなたの世界を作りなさい
プレイヤーとキャラクター: 上級
ボットプレイヤー作成ガイド
15 分
ボットプレイヤーは、マルチプレイヤーの世界を開始するのに十分な人数がいないときや、プレイヤーが世界から離脱したときに補填するために使用されます。 ボットプレイヤーの動作は、各コンテンツに対して実装する必要があります。 このガイドは、ボットプレイヤーを作成する一般的な方法を説明しています。 📘 ボットプレイヤー作成ガイドは、マルチプレイヤーガイドに基づいています。\[ マルチプレイを作る docid\ zp83r5fc6n0bi1i84p4k3 ] ステップ 1 ボットプレイヤーを作成する 1 1 マルチプレイヤースキーマに「 isbot 」というブール値を追加します。 1 2 サーバースクリプト index ts にボットプレイヤーを作成するための以下の関数を定義し、必要なポイントで呼び出します。 index ts // `createbot()` メソッドは、指定された `userid` を持つボットプレイヤーを作成するために使用されます。 createbot(userid string) { // 提供された `userid` を使用してボットプレイヤーのセッションidを生成します。 const sessionid = "bot " + userid; // 同じセッションidを持つボットプレイヤーがすでに存在するか確認します。存在する場合は、重複を作成せずに戻ります。 if (this state players has(sessionid)) { return; } // ボットプレイヤーのための新しい `player` オブジェクトを作成します。 const player player = new player(); player sessionid = sessionid; if (userid) { player zepetouserid = userid; } player isbot = true; // セッションidをキーとして使用して、ボットプレイヤーを状態のプレイヤーマップに追加します。 this state players set(player sessionid, player); this botmap set(sessionid, player); } 👍 ヒント 特定のユーザーの userid は、ボットプレイヤーキャラクターを作成するために事前に保存されています。 サーバーの onjoin に接続しているクライアントの userid を確認することで、特定のユーザーの userid を確認できます。以下のスクリプトをサーバースクリプトに書いた後、関連するワールドから接続してください。 index ts onjoin(client sandboxplayer) { 	console log(client userid); } ステップ 2 クライアントでボットプレイヤーを作成する 2 1 サーバーがボットプレイヤーを作成する場合、クライアントはそれを onjoinplayer() で新しいプレイヤーとして認識します。 プロジェクトを作成 > 作成 > zepeto > typescript として作成し、botplayermanager に名前を変更します。 onaddedplayer() にロジックを追加して各プレイヤーを作成し、ボットプレイヤーを区別してその zepeto キャラクターを作成するロジックを追加します。 botplayermanager ts import { zepetocharacter, zepetoplayers } from 'zepeto character controller'; import { room } from 'zepeto multiplay'; import { zepetoscriptbehaviour } from 'zepeto script' import { zepetoworldmultiplay } from 'zepeto world'; export default class botplayermanager extends zepetoscriptbehaviour { public zepetoworldmultiplay zepetoworldmultiplay; // 現在の部屋とボットプレイヤーデータを保存するためのプライベート変数。 private room room; private botmapdata map\<string, zepetocharacter> = new map\<string, zepetocharacter>(); start() { 		 	 // `zepetoworldmultiplay` コンポーネントからの `roomjoined` イベントをリッスンします。 this zepetoworldmultiplay roomjoined += (room room) => { this room = room; } 	 // `zepetoplayers instance` からの `onaddedplayer` イベントをリッスンして、新しく追加されたプレイヤーを処理します。 zepetoplayers instance onaddedplayer addlistener((userid string) => { 	 // `userid` を使用して部屋の状態から現在のプレイヤーデータを取得します。 const currentplayer = this room state players get item(userid); 	 // プレイヤーがボットかどうかを確認し、ボットプレイヤーとして設定します。 if (currentplayer isbot) { this setbotplayer(currentplayer sessionid); } }); } } 2 2 setbotplayer関数を作成して、ボットプレイヤーにタグと同期コンポーネントを追加し、それらを制御するスクリプトを作成します。 ボットプレイヤーのデータを管理するために、map形式で botmapdataに保存します。 botplayermanager ts // `setbotplayer()`メソッドは、プレイヤーをボットとして設定するために使用されます。 setbotplayer(userid string) { // `userid`を使用してボットプレイヤーに関連付けられたzepetoキャラクターを取得します。 const bot = zepetoplayers instance getplayer(userid) character; // 識別のためにキャラクターの名前を`userid`に設定します。 bot gameobject name = userid; // ボットプレイヤーのデータを`userid`をキーとして botmapdataマップに保存します。 	 this botmapdata set(userid, bot); } 👍 ヒント ボットプレイヤーの動作を制御するために、setbotplayer()に追加のスクリプトや設定を追加できます。 ステップ 3 クライアントにボットプレイヤーボタンを作成する 開始するために特定の数のプレイヤーが必要なワールドでは、時々プレイヤーが不足していて、ワールドが開始するまで長い間待たなければなりません。 この場合、botプレイヤーを追加することで世界を開始できます。 3 1 index tsでサーバーがクライアントからメッセージを受信したときにcreatebot()を実行する関数を登録します。 async oncreate() { 	 // 与えられたuseridでボットプレイヤーを作成する"createbot"メッセージを処理します。 this onmessage("createbot", (client, message) => { this createbot(message); }); } 3 2 クライアントスクリプトbotplayermanager tsで、サーバーに"createbot"メッセージを送信する関数を書きます。 関数を実行する方法は、ボタンを押してメッセージを送信することです。 作成されるbotプレイヤーのユーザーidを文字列としてメッセージを通じて送信します。 botplayermanager ts public buttoncreatebot button; public botplayerid string; start() {	 	 // ボットプレイヤーを作成するメッセージを送信するために"create bot"ボタンにクリックリスナーを追加します。 	 this buttoncreatebot onclick addlistener(() => { this room send("createbot", this botplayerid); }); } 3 3 さて、サーバーとランタイムを実行すると、ボットプレイヤーがボタンを押すと作成されるのがわかります。 ステップ 4 ボットプレイヤーを追加して世界を開始する プレイヤーが不足している場合、ボットプレイヤーを追加して世界を開始できます。 4 1 サーバースクリプトで、onjoin中に以下のコードを追加して、プレイヤーの数を確認し、4人以上のプレイヤーがいるときにワールドを開始します。 createbot()内でプレイヤーの数を確認する関数を追加します。 startworld()関数内でプレイの数をカウントする機能を追加します。 index ts async onjoin(client sandboxplayer) { // プレイヤーが参加した後、部屋のプレイヤー数を確認します。 	this checkplayernumber(); } // `checkplayernumber()`メソッドは、部屋のプレイヤー数を確認し、4人以上のプレイヤーがいる場合にワールドを開始します。 checkplayernumber() { 	// 現在のプレイヤー数をコンソールに出力します。 	console log(`プレイヤー数, ${this state players size}`); 	// 部屋に4人以上のプレイヤーがいる場合、ワールドを開始します。 	if (this state players size >= 4) { this startworld(); 	} } // `createbot()`メソッドは、指定された`userid`を持つボットプレイヤーを作成するために使用されます。 createbot(userid string) { 	// 提供された`userid`を使用してボットプレイヤーのセッションidを生成します。 	const sessionid = "bot " + userid; 	// 同じセッションidを持つボットプレイヤーがすでに存在するか確認します。存在する場合は、重複を作成せずに戻ります。 if (this state players has(sessionid)) { 	return; 	} 	// ボットプレイヤーのために新しい`player`オブジェクトを作成します。 	const player player = new player(); player sessionid = sessionid; 	if (userid) { 	 player zepetouserid = userid; 	} 	player isbot = true; 	// セッションidをキーとして、状態のプレイヤーマップにボットプレイヤーを追加します。 	this state players set(player sessionid, player); 	this botmap set(sessionid, player); 	// ボットプレイヤーを追加した後、部屋のプレイヤー数を確認します。 	this checkplayernumber(); } private playtime number = 0; // `startworld()`メソッドは、プレイ時間を増加させ、すべてのクライアントに"startworld"メッセージをブロードキャストします。 startworld() { 	 this playtime += 1; // ワールドの開始と現在のプレイ時間を示すメッセージを出力します。 console log("ワールドを開始します!"); this broadcast("startworld", this playtime); } サーバーでは、実際のプレイヤーが部屋に参加するときに onjoin が実行されます。したがって、createbot を介して bot プレイヤーが作成され、onjoin を介してプレイヤーが入るとき、checkplayernumber() は人数を追加します。 4 2 クライアントスクリプト botplayermanager ts で、サーバーから startworld メッセージを受信したときに実行される startworld() を記述します。 botplayermanager ts start() { 	// `zepetoworldmultiplay` コンポーネントからの `roomjoined` イベントをリッスンします。 	this zepetoworldmultiplay roomjoined += (room room) => { // "startworld" メッセージタイプのメッセージハンドラーを追加します。 	this room addmessagehandler("startworld", (playtime number) => { this startworld(playtime); }); } // `startworld()` メソッドは、提供された `playtime` でワールドが開始されるときに呼び出されます。 startworld(playtime number) { 	// `playtime` とともにワールド開始メッセージを表示します。 console log(`start world ${playtime}`); } 4 3 実行時に、bot プレイヤーを含む 4 人以上のプレイヤーがいる場合、サーバーコンソールとクライアントのコンソールに「world start」というログが表示されます。 ステップ 5 bot プレイヤーの位置を同期する 以下は、追加されたボットプレイヤーをローカルプレイヤーの位置に移動させ、移動位置を同期させるサンプルコードです。 5 1 まず、サーバーのindex tsでクライアントから受信したメッセージのときにボットプレイヤーを移動させるコードを書きます。 movebot が受信されると、 async oncreate() { // "movebot"メッセージを処理し、ボットプレイヤーを指定された位置に移動させます。 	this onmessage("movebot", (client, message) => { this movebot(client, message); }); } // `movebot()`メソッドは、受信したメッセージに基づいてボットプレイヤーを指定された位置に移動させます。 movebot(client sandboxplayer, message string) { // クライアントから受信したjsonメッセージを解析して位置情報を抽出します。 const position = json parse(message); // ユーザーのセッションidと解析された位置データを持つ新しいメッセージオブジェクトを作成します。 const newmessage = { user client sessionid, positionx position x, positiony position y, positionz position z } // 新しいメッセージデータをjson文字列としてすべてのクライアントに"movebottoposition"メッセージをブロードキャストします。 this broadcast("movebottoposition", json stringify(newmessage)); } 5 2 クライアントスクリプトのbotplayermanager tsで、buttoncallbotが押されたときにローカルプレイヤーの位置をサーバーに送信するsendbotposition()を書きます。 メッセージ movebottoposition がサーバーから受信されたときに、すべてのボットプレイヤーをメッセージに含まれる位置情報に移動させるコードを書いてください。 botplayermanager ts public buttoncallbot button; start(){ 	// `zepetoworldmultiplay` コンポーネントからの `roomjoined` イベントをリッスンします。 this zepetoworldmultiplay roomjoined += (room room) => { this room = room; // "startworld" メッセージタイプのメッセージハンドラーを追加します。 this room addmessagehandler("startworld", (playtime number) => { this startworld(playtime); }); 	// ボタン "call bot" にクリックリスナーを追加して、ボットプレイヤーの位置を送信するメッセージを送ります。 	this buttoncallbot onclick addlistener(() => { 	 this sendbotposition(); 	}); } // このメソッドは、ボットの動きの同期のためにローカルプレイヤーのキャラクターの位置をサーバーに送信します。 sendbotposition() { // ローカルプレイヤーのキャラクターの位置を取得します。 const localplayerposition = zepetoplayers instance localplayer zepetoplayer character transform position; // ローカルプレイヤーのキャラクターの x, y, z 座標を含む位置オブジェクトを作成します。 const position = { x localplayerposition x, y localplayerposition y, z localplayerposition z } // 位置オブジェクトを json 文字列に変換し、"movebot" メッセージタイプでサーバーに送信します。 this room send("movebot", json stringify(position)); } movebottoposition(message) { // クライアントから受信した json メッセージを解析して位置情報を抽出します。 const jsonmessage = json parse(message); const position = new vector3(jsonmessage positionx, jsonmessage positiony, jsonmessage positionz); // ` botmapdata` マップ内の各ボットキャラクターを指定された位置に移動させ、x および z 軸に小さなランダムオフセットを加えます。 this botmapdata foreach((character zepetocharacter) => { // `movetoposition()` メソッドを使用してキャラクターを指定された位置に移動させます。 // ここでは、ボットの自然な動きを作成するために、ターゲット位置に小さなランダムオフセットを追加します。 character movetoposition(position + new vector3(random range(0 5, 1), 0, random range(0 5, 1))); }); } 5 3 さて、ランタイムでボットプレイヤーを作成し、buttoncallbot ボタンを押すと、作成されたボットプレイヤーがローカルプレイヤーのキャラクターの位置に移動するのが見えるはずです。 botplayermanager tsの全コード botplayermanager ts import { random, vector3 } from 'unityengine'; import { button } from 'unityengine ui'; import { zepetocharacter, zepetoplayers } from 'zepeto character controller'; import { room } from 'zepeto multiplay'; import { zepetoscriptbehaviour } from 'zepeto script' import { zepetoworldmultiplay } from 'zepeto world'; export default class botplayermanager extends zepetoscriptbehaviour { // inspectorから必要なコンポーネントと設定を参照するための公開プロパティ。 public zepetoworldmultiplay zepetoworldmultiplay; public buttoncreatebot button; public buttoncallbot button; public botplayerid string; // 現在の部屋とボットプレイヤーデータを保存するためのプライベート変数。 private room room; private botmapdata map\<string, zepetocharacter> = new map\<string, zepetocharacter>(); start() { // `zepetoworldmultiplay`コンポーネントからの`roomjoined`イベントをリッスンします。 this zepetoworldmultiplay roomjoined += (room room) => { this room = room; // "startworld"メッセージタイプのメッセージハンドラーを追加します。 this room addmessagehandler("startworld", (playtime number) => { this startworld(playtime); }); } // 新しく追加されたプレイヤーを処理するために`zepetoplayers instance`からの`onaddedplayer`イベントをリッスンします。 zepetoplayers instance onaddedplayer addlistener((userid string) => { // `userid`を使用して部屋の状態から現在のプレイヤーデータを取得します。 const currentplayer = this room state players get item(userid); // プレイヤーがボットかどうかを確認し、そうであればボットプレイヤーとして設定します。 if (currentplayer isbot) { this setbotplayer(currentplayer sessionid); } }); // ボットプレイヤーを作成するためのメッセージを送信するために"create bot"ボタンにクリックリスナーを追加します。 this buttoncreatebot onclick addlistener(() => { this room send("createbot", this botplayerid); }); this zepetoworldmultiplay roomjoined += (room room) => { this room = room; this room addmessagehandler("movebottoposition", (message string) => { this movebottoposition(message); }); } // ボットプレイヤーの位置を送信するためのメッセージを送信するために"call bot"ボタンにクリックリスナーを追加します。 this buttoncallbot onclick addlistener(() => { this sendbotposition(); }); } // `setbotplayer()`メソッドはプレイヤーをボットとして設定するために使用されます。 setbotplayer(userid string) { // ボットプレイヤーに関連付けられたzepetoキャラクターを`userid`を使用して取得します。 const bot = zepetoplayers instance getplayer(userid) character; // 識別のためにキャラクターの名前を`userid`に設定します。 bot gameobject name = userid; // ボットプレイヤーのデータを`userid`をキーとして` botmapdata`マップに保存します。 this botmapdata set(userid, bot); } // `startworld()`メソッドは、指定された`playtime`で世界が開始されると呼び出されます。 startworld(playtime number) { // `playtime`と共に世界開始メッセージを出力します。 console log(`start world ${playtime}`); } // このメソッドは、ボットの動きの同期のためにローカルプレイヤーのキャラクターの位置をサーバーに送信します。 sendbotposition() { // ローカルプレイヤーのキャラクターの位置を取得します。 const localplayerposition = zepetoplayers instance localplayer zepetoplayer character transform position; // ローカルプレイヤーのキャラクターのx、y、z座標を含む位置オブジェクトを作成します。 const position = { x localplayerposition x, y localplayerposition y, z localplayerposition z } // 位置オブジェクトをjson文字列に変換し、"movebot"メッセージタイプでサーバーに送信します。 this room send("movebot", json stringify(position)); } // このメソッドは、サーバーがクライアントから"movebot"メッセージを受信したときに呼び出され、ボットキャラクターを指定された位置に移動させます。 movebottoposition(message) { // クライアントから受信したjsonメッセージを解析して位置情報を抽出します。 const jsonmessage = json parse(message); const position = new vector3(jsonmessage positionx, jsonmessage positiony, jsonmessage positionz); // ` botmapdata`マップ内の各ボットキャラクターを指定された位置に小さなランダムオフセットを加えて移動させます。 this botmapdata foreach((character zepetocharacter) => { // `movetoposition()`メソッドは、キャラクターを指定された位置に移動させるために使用されます。 // ここでは、ボットの自然な動きを作成するために、ターゲット位置に小さなランダムオフセットが追加されます。 character movetoposition(position + new vector3(random range(0 5, 1), 0, random range(0 5, 1))); }); } } index ts サーバーの完全なコード import { sandbox, sandboxoptions, sandboxplayer } from "zepeto multiplay"; import { datastorage } from "zepeto multiplay datastorage"; import { player, transform, vector3 } from "zepeto multiplay schema"; export default class extends sandbox { storagemap map\<string, datastorage> = new map\<string, datastorage>(); // ボットプレイヤーのマップデータを botmap として保存 private botmap map\<string, player> = new map\<string, player>(); private playtime number = 0; constructor() { super(); } oncreate(options sandboxoptions) { // room オブジェクトが作成されたときに呼び出されます。 // room オブジェクトの状態またはデータの初期化を処理します。 this onmessage("onchangedtransform", (client, message) => { this state players get(client sessionid); const player = this state players get(client sessionid); const transform = new transform(); transform position = new vector3(); transform position x = message position x; transform position y = message position y; transform position z = message position z; transform rotation = new vector3(); transform rotation x = message rotation x; transform rotation y = message rotation y; transform rotation z = message rotation z; if (player) { player transform = transform; } }); this onmessage("onchangedstate", (client, message) => { const player = this state players get(client sessionid); if (player) { player state = message state; player substate = message substate; } }); // 指定された userid でボットプレイヤーを作成する "createbot" メッセージを処理します。 this onmessage("createbot", (client, message) => { this createbot(message); }); // 指定された位置にボットプレイヤーを移動する "movebot" メッセージを処理します。 this onmessage("movebot", (client, message) => { this movebot(client, message); }); } // `createbot()` メソッドは、指定された `userid` でボットプレイヤーを作成するために使用されます。 createbot(userid string) { // 提供された `userid` を使用してボットプレイヤーのセッション id を生成します。 const sessionid = "bot " + userid; // 同じセッション id のボットプレイヤーがすでに存在するか確認します。存在する場合は、重複を作成せずに戻ります。 if (this state players has(sessionid)) { return; } // ボットプレイヤーのための新しい `player` オブジェクトを作成します。 const player player = new player(); player sessionid = sessionid; if (userid) { player zepetouserid = userid; } player isbot = true; // セッション id をキーとして、状態のプレイヤーマップにボットプレイヤーを追加します。 this state players set(player sessionid, player); this botmap set(sessionid, player); // ボットプレイヤーを追加した後、部屋のプレイヤー数を確認します。 this checkplayernumber(); } // `checkplayernumber()` メソッドは、部屋のプレイヤー数を確認し、4人以上のプレイヤーがいる場合にワールドを開始します。 checkplayernumber() { // 現在の部屋のプレイヤー数をコンソールに出力します。 console log(`プレイヤー数, ${this state players size}`); // 部屋に4人以上のプレイヤーがいる場合、ワールドを開始します。 if (this state players size >= 4) { this startworld(); } } // `startworld()` メソッドは、プレイ時間を増加させ、すべてのクライアントに "startworld" メッセージをブロードキャストします。 startworld() { this playtime += 1; // ワールドの開始と現在のプレイ時間を示すメッセージを出力します。 console log("ワールドを開始!"); this broadcast("startworld", this playtime); } // `movebot()` メソッドは、受信したメッセージに基づいてボットプレイヤーを指定された位置に移動します。 movebot(client sandboxplayer, message string) { // クライアントから受信した json メッセージを解析して位置情報を抽出します。 const position = json parse(message); // ユーザーのセッション id と解析された位置データを持つ新しいメッセージオブジェクトを作成します。 const newmessage = { user client sessionid, positionx position x, positiony position y, positionz position z } // 新しいメッセージデータを json 文字列としてすべてのクライアントに "movebottoposition" メッセージをブロードキャストします。 this broadcast("movebottoposition", json stringify(newmessage)); } async onjoin(client sandboxplayer) { // schemas json で定義されたプレイヤーオブジェクトを作成し、初期値を設定します。 console log(`\[onjoin] sessionid ${client sessionid}, hashcode ${client hashcode}, userid ${client userid}`) const player = new player(); player sessionid = client sessionid; if (client hashcode) { player zepetohash = client hashcode; } if (client userid) { player zepetouserid = client userid; } // \[datastorage] 入力されたプレイヤーの datastorage をロードします const storage datastorage = client loaddatastorage(); this storagemap set(client sessionid, storage); let visit cnt = await storage get("visitcount") as number; if (visit cnt == null) visit cnt = 0; console log(`\[onjoin] ${client sessionid} の訪問回数 ${visit cnt}`) // \[datastorage] プレイヤーの訪問回数を更新し、その後ストレージを保存します await storage set("visitcount", ++visit cnt); // セッション id を使用してプレイヤーオブジェクトを管理します。これはクライアントオブジェクトの一意のキー値です。 // クライアントは、プレイヤーオブジェクトに追加された情報を players オブジェクトに add onadd イベントを追加することで確認できます。 this state players set(client sessionid, player); // プレイヤーが参加した後、部屋のプレイヤー数を確認します。 this checkplayernumber(); } ontick(deltatime number) void { // サーバーで設定された各時間に繰り返し呼び出され、特定の間隔イベントを deltatime を使用して管理できます。 } async onleave(client sandboxplayer, consented? boolean) { // allowreconnection を設定することで、回路の接続を維持できますが、基本的なガイドではすぐにクリーンアップします。 // クライアントは、プレイヤーオブジェクトが削除された情報を players オブジェクトに add onremove イベントを追加することで確認できます。 this state players delete(client sessionid); } }