あなたの世界を作りなさい
ジェスチャー
31 分
zepetoworldcontent apiを使用すると、希望するジェスチャー/ポーズカテゴリのサムネイルを設定し、サムネイルがクリックされたときに特定のジェスチャー/ポーズを有効にすることができます。 zepetoworldcontent apiを使用するには、次のようにインポート文を書く必要があります。 import { officialcontenttype, worldservice, zepetoworldcontent, content } from 'zepeto world'; ジェスチャー/ポーズ情報を含むcontentクラスのメンバ変数および関数情報は以下の通りです。 api 説明 public get id() string コンテンツユニークid public get title() string ジェスチャー、ポーズタイトルテキスト 言語はデバイスの言語に応じて自動的に翻訳されます public get thumbnail() unityengine texture2d 2dサムネイル public get animationclip() unityengine animationclip ジェスチャーアニメーションクリップ public get isdownloadedthumbnail() boolean このサムネイルを以前にダウンロードしたかどうかを判断するための関数 public get isdownloadedanimation() boolean このアニメーションクリップを以前にダウンロードしたかどうかを判断するための関数 public downloadanimation($complete system action)\ void アニメーションクリップをダウンロードする関数で、完了コールバックを受け取ります isdownloadedanimation()がfalseの場合、downloadanimation()を呼び出すように実装します。 public downloadthumbnail($complete system action)\ void サムネイルをダウンロードするための関数 isdownloadedthumbnail()がfalseの場合、downloadthumbnail()を呼び出すように実装します。 officialcontenttype enum コンテンツの種類(world 1 9 0以降) ジェスチャー = 2 ポーズ = 4 セルフィー = 8 ジェスチャー挨拶 = 16 ジェスチャーポーズ = 32 ジェスチャー肯定 = 64 ジェスチャーダンス = 128 ジェスチャー否定 = 256 ジェスチャーその他 = 512 すべて = 14 既存の関数を使用できますが、 public downloadthumbnail($character zepeto character controller zepetocharacter, $complete system action)\ void 、機能に関する問題はありません。ただし、zepetoキャラクターを引数として受け付けなくなったため、新しく修正された関数を使用してください。 public downloadthumbnail($complete system action)\ void 代わりに。 ステップ 1 uiを設定する ステップ 1 1 ジェスチャーボタンを作成する 1\) 階層 > ui > キャンバスを追加し、他のuiに隠れないようにソート順を2に設定します。 2\) 階層を追加 > ui > ボタン。 ステップ 1 2 ジェスチャーパネルを整理する 1\) 階層を追加 > 空のオブジェクトを作成し、panelparentと名前を変更します。 2\) 階層を追加 > ui > panelをpanelparentの子として追加します。 3\) 閉じるボタン ui > ボタンを追加した後、ジェスチャーパネルを無効にするonclickイベントを追加します。 4\) 開くボタン 上記で作成した開くボタンに、ジェスチャーパネルをアクティブにするonclickイベントを追加してください。 5\) タイトルエリアとして画像を追加します。 6\) ジェスチャーサムネイルを表示するためにスクロールビューを設定します。 階層を追加 > ui > スクロールビュー。 横方向をチェックし、スクロールバー画像を無効にします。縦方向のスクロールのみを使用し、横方向のスクロールは必要ありません。 スクロールビューのコンテンツにグリッドレイアウトを追加して、サムネイルをグリッドパターンで整列させます。 オブジェクトのサイズをコンテンツのサイズに適切にするために、コンテンツサイズフィッターを追加します。 スクリプトを実装する際は、スクロールビューのコンテンツをジェスチャーサムネイルの親として設定する必要があります(全体の領域が認識され、スクロールされるように)。 7\) ジェスチャータイプによってタブを設定します。 階層を追加 > パネルの子として空のオブジェクトを作成し、それをgesturetitleに名前変更します。 これはトグルボタンの親オブジェクトです。 タブを水平に整列させるために水平レイアウトを追加します。 トグルグループコンポーネントを追加します。 👍 タブをさらに構成するには、階層を追加 > ui > スクロールビューを追加し、スクロールビューオプションで水平をチェックします。 8\) トグルボタンとして使用するテキストをgesturetitleの子として追加し、それを「すべて」に置き換えます。 テキストの色を灰色に設定します。 チェックされたときに表示されるハイライトされたテキストをテキストの子として追加します。 フォントの内容、サイズ、太さを同じに設定し、色を黒に設定します。 トグルコンポーネントを追加します。 グループ内の親オブジェクトを指定します。 graphicの子として追加したハイライトされたテキストを追加します。 最初に表示されるすべてのトグルコンポーネントについてのみisonをチェックします。 gestureとposeのトグルボタンを同じ方法で作成します。 ステップ 1 3 サムネイルプレハブを作成する サムネイルボタンをプレハブとして作成し、スクリプト内でインスタンスとして生成する方法を使用します。 1\) scroll viewのcontentの子としてui > buttonを追加し、名前をprethumbに変更します。 2\) raw imageを追加した後、名前をthumbに変更してください。 この画像はサムネイルになります。サイズを適切に調整してください。 3\) テキストを追加します。 画像の下部を中央に配置します。 文字のサイズと太さを調整し、content size fitterを追加します。 横のフィット 推奨サイズ 縦のフィット 推奨サイズ 4\) 設定が完了したら、プレハブにしてresourcesフォルダに入れてください。 ステップ 1 4 ui設定ガイド動画 https //www youtube com/watch?v=v ias8t8wq0 https //www youtube com/watch?v=v ias8t8wq0 👍 動画に表示されているuiのサイズと位置の値は推奨ですが、希望する値に変更できます! ui設定が完了したら、スクリプティングに進んでください。 ステップ 2 スクリプトを書く このスクリプトはシングルプレイに基づいています。 ステップ 2 1 サムネイル プロジェクト > 作成 > zepeto > typescript としてサムネイルに名前を変更します。 以下のようなサンプルスクリプトを書きます。 これは、ジェスチャーコンテンツ情報(タイトル、画像)を ui に整理するスクリプトです。 サムネイル import { zepetoscriptbehaviour } from 'zepeto script'; import { content } from 'zepeto world'; import { rawimage, text } from 'unityengine ui'; import { texture2d } from 'unityengine'; export default class thumbnail extends zepetoscriptbehaviour { @hideininspector() public content content; start() { this getcomponentinchildren\<text>() text = this content title; this getcomponentinchildren\<rawimage>() texture = this content thumbnail as texture2d; } } スクリプトを作成した後、prethumb プレハブを開いてスクリプトを追加します。 ステップ 2 2 gestureloader 階層を作成 > 空のオブジェクトを作成し、gestureloaderに名前を変更します。 プロジェクトを作成 > 作成 > zepeto > typescriptを作成し、gestureloaderに名前を変更します。 以下のようなサンプルスクリプトを書きます。 gestureloader import { zepetoscriptbehaviour } from 'zepeto script'; import { localplayer, spawninfo, zepetocharacter, zepetoplayers } from 'zepeto character controller'; import { officialcontenttype, worldservice, zepetoworldcontent, content } from 'zepeto world'; import { rawimage, text, button } from 'unityengine ui'; import { gameobject, texture2d, transform, waituntil } from 'unityengine'; import thumbnail from ' /thumbnail'; export default class gestureloader extends zepetoscriptbehaviour { @hideininspector() public contents content\[] = \[]; @hideininspector() public thumbnails gameobject\[] = \[]; @serializefield() private count number = 50; @serializefield() private contentsparent transform; @serializefield() private prefthumb gameobject; private mycharacter zepetocharacter; start() { // キャラクターを作成 zepetoplayers instance createplayerwithuserid(worldservice userid, new spawninfo(), true); zepetoplayers instance onaddedlocalplayer addlistener(() => { this mycharacter = zepetoplayers instance localplayer zepetoplayer character; // 自分のキャラクターでサムネイルを取得するためには、キャラクターが作成された後にコンテンツをリクエストする必要があります。 this contentrequest(); }); } // 1 サーバーからコンテンツを受信 private contentrequest() { // すべてのタイプのリクエスト zepetoworldcontent requestofficialcontentlist(officialcontenttype all, contents => { this contents = contents; for (let i = 0; i < this count; i++) { if (!this contents\[i] isdownloadedthumbnail) { // 自分のキャラクターを使ってサムネイル写真を撮る this contents\[i] downloadthumbnail(() =>{ this createthumbnailobjcet(this contents\[i]); }); } else { this createthumbnailobjcet(this contents\[i]); } } }); } // 2 サムネイルオブジェクトの作成 private createthumbnailobjcet(content content) { const newthumb gameobject = gameobject instantiate(this prefthumb, this contentsparent) as gameobject; newthumb getcomponent\<thumbnail>() content = content; // 各サムネイルのボタンリスナー newthumb getcomponent\<button>() onclick addlistener(() => { this loadanimation(content); }); this thumbnails push(newthumb); } // 3 アニメーションの読み込み private loadanimation(content content) { // アニメーションの読み込みを確認 if (!content isdownloadedanimation) { // アニメーションがダウンロードされていない場合は、ダウンロードします。 content downloadanimation(() => { // アニメーションクリップを再生 this mycharacter setgesture(content animationclip); }); } else { this mycharacter setgesture(content animationclip); } } } カウントは、各タブでダウンロードする最大のジェスチャーの数です。100より大きい数に設定すると、サムネイルのダウンロードプロセス中にエラーが発生する可能性があるため、必要な分だけ設定してください。 スクリプトは次のように進行します: 1\) zepetoキャラクターを読み込んだ後、サムネイルを生成するためにcontentsrequest()カスタム関数を呼び出します。 contentsrequest()関数は、ジェスチャーとポーズをそれぞれ分けてコンテンツ情報を受け取ります。 既存のサムネイルがある場合はスキップされ、そうでない場合はサムネイルが取得されます。 取得したサムネイルデータは、それぞれのリストに保存されます。 ステップ 2 3 uicontroller 階層を作成 > 空のオブジェクトを作成し、uicontollerに名前を変更します。 プロジェクトを作成 > 作成 > zepeto > typescriptを作成し、uicontollerに名前を変更します。 以下のようなサンプルスクリプトを書きます。 uicontroller import { zepetoscriptbehaviour } from 'zepeto script'; import { button, rawimage, text, toggle } from 'unityengine ui'; import { localplayer, zepetocharacter, zepetoplayers, zepetoscreentouchpad } from 'zepeto character controller'; import { officialcontenttype, content } from 'zepeto world'; import { object, gameobject, transform } from 'unityengine'; import gestureloader from ' /gestureloader'; import thumbnail from ' /thumbnail'; export default class uicontroller extends zepetoscriptbehaviour { @serializefield() private closebutton button; @serializefield() private typetogglegroup toggle\[]; private gesturelodaer gestureloader; private mycharacter zepetocharacter; start() { this gesturelodaer = object findobjectoftype\<gestureloader>(); zepetoplayers instance onaddedlocalplayer addlistener(() => { this mycharacter = zepetoplayers instance localplayer zepetoplayer character; // if click the touchpad, cancel the gesture object findobjectoftype\<zepetoscreentouchpad>() onpointerdownevent addlistener(() => { this stopgesture(); }); // if click the close button, cancel the gesture this closebutton onclick addlistener(() => { this stopgesture(); }); }); // ui listener this typetogglegroup\[0] onvaluechanged addlistener(() => { this setcategoryui(officialcontenttype all); }); this typetogglegroup\[1] onvaluechanged addlistener(() => { this setcategoryui(officialcontenttype gesture); }); this typetogglegroup\[2] onvaluechanged addlistener(() => { this setcategoryui(officialcontenttype pose); }); } // category toggle ui set private setcategoryui(category officialcontenttype) { if (category == officialcontenttype all) { this gesturelodaer thumbnails foreach((obj) => { obj setactive(true); }); } else { for (let i = 0; i < this gesturelodaer thumbnails length; i++) { const content = this gesturelodaer thumbnails\[i] getcomponent\<thumbnail>() content; if (content keywords includes(category)) { this gesturelodaer thumbnails\[i] setactive(true); } else { this gesturelodaer thumbnails\[i] setactive(false); } } } } private stopgesture() { this mycharacter cancelgesture(); } } スクリプトの流れは次のとおりです: タッチパッドまたは閉じるボタンをタッチして、cancelgesture()関数を使用して再生をキャンセルします。 タブ(トグルボタン)をタップして、setcategoryui()カスタム関数を呼び出します。 setcategoryui()関数は、各サムネイルのジェスチャーコンテンツ情報を使用して、それぞれの対応するカテゴリに設定します。 適用可能なタイプであれば有効にし、そうでなければ無効にします。 スクリプトを完了したら、インスペクターに「close button」と「typetogglegroup」を割り当てます。 type toggle groupへのエントリーは、ジェスチャーパネル内のtoggle groupの子であるtoggleです。 ステップ 3 実行 ❗️ 注意 プレイする前に、panelparentを無効にして、プレイ中にオープンボタンだけが表示されるようにしてください。 ステップ 4 マルチプレイジェスチャーの同期 マルチプレイの場合、特定のプレイヤーが取得したジェスチャー情報値を受信し、ルームにアクセスするすべてのプレイヤーに適用する同期コードを追加する必要があります。 重要なのは、どのプレイヤーがどのジェスチャーを行ったかについて、サーバーとクライアント間でルームメッセージを送受信することです。 ステップ 4 1 クライアントコード サムネイル マルチプレイ シングルプレイのクライアントコードで実装されたのと同じスクリプトを書いてください。 サムネイル マルチプレイ import { zepetoscriptbehaviour } from 'zepeto script'; import { content } from 'zepeto world'; import { rawimage, text } from 'unityengine ui'; import { texture2d } from 'unityengine'; export default class thumbnail extends zepetoscriptbehaviour { @hideininspector() public content content; start() { this getcomponentinchildren\<text>() text = this content title; this getcomponentinchildren\<rawimage>() texture = this content thumbnail as texture2d; } } gestureloader マルチプレイ デフォルトでは、シングルプレイのクライアントコードで実装されたスクリプトは同じように書かれています。 さらに、クライアントはplayergestureinfoを含むインターフェースを宣言します。 サーバーに情報を送信する際:sendmygesture()カスタム関数を参照してください。 プレイヤーがサムネイルを押してジェスチャーを作成するとき、ジェスチャーidをサーバーに送信します room send() を使用します。 ジェスチャーをキャンセルするときは、キャンセルしたことを送信するために処理します。 サーバーから別のクライアントからジェスチャー情報を受信するとき:"onchangegesture"ルームメッセージがこの room addmessagehandler()内のstart()に送信されます。 同期は、"onchangegesture"メッセージにセッションidとジェスチャーidを持たせ、適切なプレイヤーがジェスチャーを実行することで達成されます。 import { zepetoscriptbehaviour } from 'zepeto script'; import { localplayer, spawninfo, zepetocharacter, zepetoplayers } from 'zepeto character controller'; import { officialcontenttype, worldservice, zepetoworldcontent, content, zepetoworldmultiplay } from 'zepeto world'; import { rawimage, text, button } from 'unityengine ui'; import { gameobject, texture2d, transform, waituntil } from 'unityengine'; import thumbnail from ' /thumbnail'; import { room, roomdata } from 'zepeto multiplay'; interface playergestureinfo { sessionid string, gestureid string } const cancelmotion = "" as const; export default class gestureloadermultiplay extends zepetoscriptbehaviour { public multiplay zepetoworldmultiplay; @hideininspector() public contents content\[] = \[]; @hideininspector() public thumbnails gameobject\[] = \[]; @serializefield() private count number = 50; @serializefield() private contentsparent transform; @serializefield() private prefthumb gameobject; private mycharacter zepetocharacter; private room room; private contentsmap map\<string, content> = new map\<string, content>(); start() { // キャラクターを作成 zepetoplayers instance onaddedlocalplayer addlistener(() => { this mycharacter = zepetoplayers instance localplayer zepetoplayer character; // キャラクターが作成された後にコンテンツをリクエストする必要があります。 this contentrequest(); }); // マルチプレイ用 this multiplay roomcreated += (room room) => { this room = room; // サーバーからユーザーのジェスチャー情報を受信 this room addmessagehandler("onchangegesture", (message playergestureinfo) => { let playergestureinfo playergestureinfo = { sessionid message sessionid, gestureid message gestureid }; this loadanimation(playergestureinfo); }); }; } // 1 サーバーからコンテンツを受信 private contentrequest(){ // すべてのタイプのリクエスト zepetoworldcontent requestofficialcontentlist(officialcontenttype all, contents => { this contents = contents; for (let i = 0; i < this count; i++) { if (!this contents\[i] isdownloadedthumbnail) { // 自分のキャラクターを使ってサムネイル写真を撮る this contents\[i] downloadthumbnail(() =>{ this createthumbnailobjcet(this contents\[i]); }); } else { this createthumbnailobjcet(this contents\[i]); } } }); } // 2 サムネイルオブジェクトの作成 private createthumbnailobjcet(content content) { const newthumb gameobject = gameobject instantiate(this prefthumb, this contentsparent) as gameobject; newthumb getcomponent\<thumbnail>() content = content; // コンテンツidでコンテンツを見つけるための辞書を作成 this contentsmap set(content id, content); // 各サムネイルのボタンリスナー newthumb getcomponent\<button>() onclick addlistener(() => { this sendmygesture(content id); }); // サムネイルリスト this thumbnails push(newthumb); } // マルチプレイ用 // クリックされたジェスチャー情報をサーバーに送信 public sendmygesture(gestureid) { const data = new roomdata(); data add("gestureid", gestureid); this room send("onchangegesture", data getobject()); } // 3 アニメーションの読み込み private loadanimation(playergestureinfo playergestureinfo){ if (!zepetoplayers instance hasplayer(playergestureinfo sessionid)) { console log("プレイヤーが存在しません"); return; } const zepetoplayer = zepetoplayers instance getplayer(playergestureinfo sessionid) character; if (playergestureinfo gestureid == cancelmotion) { zepetoplayer cancelgesture(); return; } else if(!this contentsmap has(playergestureinfo gestureid)) { console log("リソースがまだ読み込まれていません"); return; } const content = this contentsmap get(playergestureinfo gestureid); // アニメーションの読み込みを確認 if (!content isdownloadedanimation) { // アニメーションがダウンロードされていない場合、ダウンロードします。 content downloadanimation(() => { // アニメーションクリップを再生 zepetoplayer setgesture(content animationclip); }); } else { zepetoplayer setgesture(content animationclip); } } } スクリプトの作成が完了した後、インスペクターはzepeto world multiplayコンポーネントを使用してmultiplayに追加のオブジェクトを割り当てます。 uicontroller マルチプレイ デフォルトでは、シングルプレイクライアントコードで実装されたスクリプトは同じように書かれています。 シングルプレイクライアントコードとの違いは、stopgesture()カスタム関数です。 gestureloadermultiplay内でsendmygesture()カスタム関数を呼び出します。 ジェスチャーがキャンセルされたことを通知する情報を送信するプロセス。 import { zepetoscriptbehaviour } from 'zepeto script'; import { button, rawimage, text, toggle } from 'unityengine ui'; import { localplayer, zepetocharacter, zepetoplayers, zepetoscreentouchpad } from 'zepeto character controller'; import { officialcontenttype, content } from 'zepeto world'; import { object, gameobject, transform } from 'unityengine'; import gestureloadermultiplay from ' /gestureloadermultiplay'; import thumbnail from ' /thumbnail'; const cancelmotion = "" as const; export default class uicontroller extends zepetoscriptbehaviour { @serializefield() private closebutton button; @serializefield() private typetogglegroup toggle\[]; private gesturelodaer gestureloadermultiplay; private mycharacter zepetocharacter; start() { this gesturelodaer = object findobjectoftype\<gestureloadermultiplay>(); zepetoplayers instance onaddedlocalplayer addlistener(() => { this mycharacter = zepetoplayers instance localplayer zepetoplayer character; // タッチパッドをクリックした場合、ジェスチャーをキャンセル object findobjectoftype\<zepetoscreentouchpad>() onpointerdownevent addlistener(() => { this stopgesture(); }); // 閉じるボタンをクリックした場合、ジェスチャーをキャンセル this closebutton onclick addlistener(() => { this stopgesture(); }); }); // ui リスナー this typetogglegroup\[0] onvaluechanged addlistener(() => { this setcategoryui(officialcontenttype all); }); this typetogglegroup\[1] onvaluechanged addlistener(() => { this setcategoryui(officialcontenttype gesture); }); this typetogglegroup\[2] onvaluechanged addlistener(() => { this setcategoryui(officialcontenttype pose); }); } // カテゴリ トグル ui セット private setcategoryui(category officialcontenttype) { if (category == officialcontenttype all) { this gesturelodaer thumbnails foreach((obj) => { obj setactive(true); }); } else { for (let i = 0; i < this gesturelodaer thumbnails length; i++) { const content = this gesturelodaer thumbnails\[i] getcomponent\<thumbnail>() content; if (content keywords includes(category)) { this gesturelodaer thumbnails\[i] setactive(true); } else { this gesturelodaer thumbnails\[i] setactive(false); } } } } private stopgesture() { this gesturelodaer sendmygesture(cancelmotion); } } ステップ 4 2 サーバーコード サーバーコードは、playergestureinfoを含むインターフェースを同様に宣言します。 サーバーコードは、デフォルトでmultiplay sampleのサーバーコードに基づいています。 oncreate()内でジェスチャーが変更されると、他のクライアントにジェスチャー情報を送信するonmessage()コールバックを作成します。 import { sandbox, sandboxoptions, sandboxplayer } from 'zepeto multiplay'; import { player, transform, vector3 } from 'zepeto multiplay schema'; // プレイヤーのジェスチャー情報を表すインターフェース playergestureinfo を定義します。 interface playergestureinfo { sessionid string, gestureid string } export default class extends sandbox { // スクリプトで使用されるメッセージタイプを格納する定数オブジェクト `message type` を定義します。 message type = { onchangegesture "onchangegesture" } 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; player transform = transform; }); this onmessage("onchangedstate", (client, message) => { const player = this state players get(client sessionid); player state = message state; player substate = message substate; // キャラクターコントローラー v2 }); // ジェスチャーが変更されたとき、 this onmessage\<playergestureinfo>(this message type onchangegesture, (client, message) => { let gestureinfo\ playergestureinfo = { sessionid client sessionid, gestureid message gestureid }; // クライアントを除く他のプレイヤーにジェスチャーを送信します this broadcast(this message type onchangegesture, gestureinfo); }); } 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; } // クライアントオブジェクトの一意のキー値である sessionid を使用してプレイヤーオブジェクトを管理します。 // クライアントは、プレイヤーオブジェクトに追加された情報を players オブジェクトに add onadd イベントを追加することで確認できます。 this state players set(client sessionid, player); } onleave(client sandboxplayer, consented? boolean) { // allowreconnection を設定することで、回路の接続を維持できますが、基本ガイドではすぐにクリーンアップします。 // クライアントは、削除されたプレイヤーオブジェクトに関する情報を players オブジェクトに add onremove イベントを追加することで確認できます。 this state players delete(client sessionid); } }