チュートリアル
マルチプレイを作る
13 分
サンプルプロジェクト 📘 マルチプレイサンプル https //github com/naverz/zepeto multiplay example 概要 true 330,331left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type パート1 マルチプレイのインストール マルチプレイサーバーからクライアントを作成し、マルチプレイワールドを開発するために必要な環境を設定します。 https //www youtube com/watch?v=s68b1tma a8 第2部 世界ロジックの記述 サーバーとクライアント間の通信に必要なスキーマについて学び、スキーマタイプとルームステートを定義します。 https //www youtube com/watch?v=tfky rabov0 ビデオで使用されているサーバースクリプトは、hashcodeに関連するコンテンツを含んでおり、もはやサポートされていないことに注意してください。 したがって、記述時には以下のコードを除外してください。 if (client hashcode) { 	player zepetohash = client hashcode; } 第3部 世界ロジックの記述2 プレイヤーの位置からプレイヤーの出口に同期するために必要な世界ロジックを記述します。 https //www youtube com/watch?v=h92gd2g9dhm パート4 サーバーの実行とマルチプレイへの接続 サーバーを実行し、マルチプレイに接続します。 https //www youtube com/watch?v=fmk6jnlsjja パート5 スクリプト schemas json schemas json { "state" {"players" {"map" "プレイヤー"}}, "player" {"sessionid" "文字列","zepetouserid" "文字列","transform" "変換","state" "数値","substate" "数値"}, "transform" {"position" "ベクトル3","rotation" "ベクトル3"}, "vector3" {"x" "数値","y" "数値","z" "数値"} } サーバーコード 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>(); constructor() { super(); } oncreate(options sandboxoptions) { // ルームオブジェクトが作成されたときに呼び出されます。 // ルームオブジェクトの状態またはデータの初期化を処理します。 this onmessage("onchangedtransform", (client, message) => { 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; // キャラクターコントローラー v2 } }); } async onjoin(client sandboxplayer) { // schemas jsonで定義されたプレイヤーオブジェクトを作成し、初期値を設定します。 console log(`\[onjoin] sessionid ${client sessionid}, userid ${client userid}`) const player = new player(); player sessionid = client sessionid; if (client userid) { player zepetouserid = client userid; } // \[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を使用してプレイヤーオブジェクトを管理します。これはクライアントオブジェクトの一意のキー値です。 // クライアントは、プレイヤーオブジェクトに追加された情報を確認できます。 this state players set(client sessionid, player); } ontick(deltatime number) void { // サーバーの各設定時間で繰り返し呼び出され、特定の間隔イベントをdeltatimeを使用して管理できます。 } async onleave(client sandboxplayer, consented? boolean) { 	 // allowreconnectionを設定することで、回路の接続を維持できますが、基本ガイドではすぐにクリーンアップします。 // クライアントは、削除されたプレイヤーオブジェクトに関する情報を確認できます。 this state players delete(client sessionid); } } クライアントコード clientstarter ts import {zepetoscriptbehaviour} from 'zepeto script' import {zepetoworldmultiplay} from 'zepeto world' import {room, roomdata} from 'zepeto multiplay' import {player, state, vector3} from 'zepeto multiplay schema' import {characterstate, spawninfo, zepetoplayers, zepetoplayer, characterjumpstate} from 'zepeto character controller' import as unityengine from "unityengine"; export default class clientstarterv2 extends zepetoscriptbehaviour { public multiplay zepetoworldmultiplay; private room room; private currentplayers map\<string, player> = new map\<string, player>(); private zepetoplayer zepetoplayer; private start() { this multiplay roomcreated += (room room) => { this room = room; }; this multiplay roomjoined += (room room) => { room onstatechange += this onstatechange; }; this startcoroutine(this sendmessageloop(0 04)); } // send the local character transform to the server at the scheduled interval time private sendmessageloop(tick number) { while (true) { yield new unityengine waitforseconds(tick); if (this room != null && this room isconnected) { const hasplayer = zepetoplayers instance hasplayer(this room sessionid); if (hasplayer) { const character = zepetoplayers instance getplayer(this room sessionid) character; this sendtransform(character transform); this sendstate(character currentstate); } } } } private onstatechange(state state, isfirst boolean) { // when the first onstatechange event is received, a full state snapshot is recorded if (isfirst) { // \[charactercontroller] (local) called when the player instance is fully loaded in scene zepetoplayers instance onaddedlocalplayer addlistener(() => { const myplayer = zepetoplayers instance localplayer zepetoplayer; this zepetoplayer = myplayer; }); // \[charactercontroller] (local) called when the player instance is fully loaded in scene zepetoplayers instance onaddedplayer addlistener((sessionid string) => { const islocal = this room sessionid === sessionid; if (!islocal) { const player player = this currentplayers get(sessionid); // \[roomstate] called whenever the state of the player instance is updated player onchange += (changevalues) => this onupdateplayer(sessionid, player); } }); } let join = new map\<string, player>(); let leave = new map\<string, player>(this currentplayers); state players foreach((sessionid string, player player) => { if (!this currentplayers has(sessionid)) { join set(sessionid, player); } leave delete(sessionid); }); // \[roomstate] create a player instance for players that enter the room join foreach((player player, sessionid string) => this onjoinplayer(sessionid, player)); // \[roomstate] remove the player instance for players that exit the room leave foreach((player player, sessionid string) => this onleaveplayer(sessionid, player)); } private onjoinplayer(sessionid string, player player) { console log(`\[onjoinplayer] players sessionid ${sessionid}`); this currentplayers set(sessionid, player); const spawninfo = new spawninfo(); const position = this parsevector3(player transform position); const rotation = this parsevector3(player transform rotation); spawninfo position = position; spawninfo rotation = unityengine quaternion euler(rotation); const islocal = this room sessionid === player sessionid; zepetoplayers instance createplayerwithuserid(sessionid, player zepetouserid, spawninfo, islocal); } private onleaveplayer(sessionid string, player player) { console log(`\[onremove] players sessionid ${sessionid}`); this currentplayers delete(sessionid); zepetoplayers instance removeplayer(sessionid); } private onupdateplayer(sessionid string, player player) { const position = this parsevector3(player transform position); const zepetoplayer = zepetoplayers instance getplayer(sessionid); var movedir = unityengine vector3 op subtraction(position, zepetoplayer character transform position); movedir = new unityengine vector3(movedir x, 0, movedir z); if (movedir magnitude < 0 05) { if (player state === characterstate moveturn) return; zepetoplayer character stopmoving(); } else { zepetoplayer character movecontinuously(movedir); } if (player state === characterstate jump) { if (zepetoplayer character currentstate !== characterstate jump) { zepetoplayer character jump(); } if (player substate === characterjumpstate jumpdouble) { zepetoplayer character doublejump(); } } } private sendtransform(transform unityengine transform) { const data = new roomdata(); const pos = new roomdata(); pos add("x", transform localposition x); pos add("y", transform localposition y); pos add("z", transform localposition z); data add("position", pos getobject()); const rot = new roomdata(); rot add("x", transform localeulerangles x); rot add("y", transform localeulerangles y); rot add("z", transform localeulerangles z); data add("rotation", rot getobject()); this room send("onchangedtransform", data getobject()); } private sendstate(state characterstate) { const data = new roomdata(); data add("state", state); if(state === characterstate jump) { data add("substate", this zepetoplayer character motionv2 currentjumpstate); } this room send("onchangedstate", data getobject()); } private parsevector3(vector3 vector3) unityengine vector3 { return new unityengine vector3 ( vector3 x, vector3 y, vector3 z ); } }

