あなたの世界を作りなさい
オブジェクトとの相互作用
オブジェクトとの相互作用
15分
zepetoキャラクターがオブジェクトに近づくと表示されるインタラクションボタンを実装します。 ステップ 1 環境設定 インタラクションサンプルで使用されるアニメーションとボタンリソースは、以下のリンクからダウンロードできます。 📘 zepetoインタラクションサンプル zepetoインタラクションモジュール https //github com/naverz/zepeto multiplay example/tree/main/assets/zepeto%20interaction%20module zepetoキャラクター作成コードをシーンにデフォルトとして実装します。 📘 以下のガイドを参照してください。 \[ zepetoプレーヤー docid 2xtlbty9qgzwgthyv8nxs ] ステップ 2 オブジェクトの設定 zepetoキャラクターと対話するオブジェクトを設定します。 1\) zepetoキャラクターが対話するオブジェクトを配置します。 2\) 階層を作成 > 空のオブジェクトを作成し、dockpointに名前を変更します。 これはzepetoキャラクターが対話するポイントです。オブジェクトの位置を調整してください。 unityエディタの上部にあるトランスフォームギズモのトグルボタンがローカルになっていることを確認し、z軸(青い矢印)をオブジェクトの外側に回転させます。 コライダーコンポーネントを追加した後、istriggerを確認します。 プレイヤーがオブジェクトとインタラクトできる範囲に合わせてコライダーのサイズを調整します。 3\) ヒエラルキー > dockpointの子として空のオブジェクトを作成し、iconposに名前を変更します。 ステップ 3 uiの設定 1\) 階層を作成 > ui > canvas を zepeto キャラクターが対話するオブジェクトの子として作成し、preficoncanvas に名前を変更します。 レンダーモードをワールドスペースに設定します。 幅と高さをそれぞれ1に設定します。 graphic raycaster コンポーネントの「ignore reversed graphics」オプションのチェックを外します。 2\) 階層を作成 > ui > button を preficoncanvas の子として作成します。 3\) 設定が完了したら、prefabにして、階層内の残りのpreficoncanvasを削除します。 ステップ 4 スクリプトを書く ステップ 4 1 interactionicon 1\) プロジェクトを作成 > 作成 > zepeto > typescript として、interactionicon に名前を変更します。 2\) 以下のようなサンプルスクリプトを書きます。 import { zepetoscriptbehaviour } from 'zepeto script'; import { camera, canvas, collider, gameobject, transform, object } from 'unityengine'; import { button } from 'unityengine ui'; import { unityevent } from 'unityengine events'; import { zepetoplayers } from 'zepeto character controller'; export default class interactionicon extends zepetoscriptbehaviour { // アイコン @header("\[アイコン]") @serializefield() private preficoncanvas gameobject; @serializefield() private iconposition transform; // unity イベント @header("\[unity イベント]") public onclickevent unityevent; public ontriggerenterevent unityevent; public ontriggerexitevent unityevent; private button button; private canvas canvas; private cachedworldcamera camera; private isiconactive boolean = false; private isdonefirsttrig boolean = false; private update() { if (this isdonefirsttrig && this canvas? gameobject activeself) { this updateiconrotation(); } } private ontriggerenter(coll collider) { if (coll != zepetoplayers instance localplayer? zepetoplayer? character getcomponent\<collider>()) { return; } this showicon(); this ontriggerenterevent? invoke(); } private ontriggerexit(coll collider) { if (coll != zepetoplayers instance localplayer? zepetoplayer? character getcomponent\<collider>()) { return; } this hideicon(); this ontriggerexitevent? invoke(); } public showicon(){ if (!this isdonefirsttrig) { this createicon(); this isdonefirsttrig = true; } else { this canvas gameobject setactive(true); } this isiconactive = true; } public hideicon() { this canvas? gameobject setactive(false); this isiconactive = false; } private createicon() { if (this canvas === undefined) { const canvas = gameobject instantiate(this preficoncanvas, this iconposition) as gameobject; this canvas = canvas getcomponent\<canvas>(); this button = canvas getcomponentinchildren\<button>(); this canvas transform position = this iconposition position; } this cachedworldcamera = object findobjectoftype\<camera>(); this canvas worldcamera = this cachedworldcamera; this button onclick addlistener(() => { this onclickicon(); }); } private updateiconrotation() { this canvas transform lookat(this cachedworldcamera transform); } private onclickicon() { this onclickevent? invoke(); } } スクリプトの流れは次のとおりです: update() アイコンのキャンバスをカメラの回転に合わせて回転させるために、updateiconrotation()カスタム関数を呼び出します。 ontriggerenter(), ontriggerexit() コライダーエリアに入ってトリガーを検出したときは、showicon()カスタム関数を呼び出してアイコンをアクティブにします。 コライダーエリアから出たときは、hideicon()カスタム関数を呼び出してアイコンを無効にします。 3\) スクリプト作成が完了したら、スクリプトをdockpointオブジェクトに追加します。 4\) インスペクターからpref icon canvas、icon positionを割り当てます。 ステップ 4 2 ジェスチャーインタラクション 1\) プロジェクトを作成 > 作成 > zepeto > typescript として名前を変更し、gestureinteractionにします。 2\) 以下のようなサンプルスクリプトを書いてください。 import { animationclip, animator, humanbodybones, physics, transform, vector3, waitforendofframe} from 'unityengine'; import { zepetoscriptbehaviour } from 'zepeto script'; import { zepetoplayers, zepetocharacter } from "zepeto character controller"; import interactionicon from ' /interactionicon'; export default class gestureinteraction extends zepetoscriptbehaviour { @serializefield() private animationclip animationclip; @serializefield() private issnapbone boolean = true; @serializefield() private bodybone humanbodybones; @serializefield() private allowoverlap boolean = false; private interactionicon interactionicon; private isfirst boolean = true; private localcharacter zepetocharacter; private outposition vector3; private playergestureposition vector3; private start() { this interactionicon = this transform getcomponent\<interactionicon>(); zepetoplayers instance onaddedlocalplayer addlistener(() => { this localcharacter = zepetoplayers instance localplayer zepetoplayer character; }); this interactionicon onclickevent addlistener(()=> { // when onclick interaction icon this interactionicon hideicon(); this dointeraction(); }); } private dointeraction() { this outposition = this transform position; if (this issnapbone) { // is place empty if (this allowoverlap || this findotherplayernum() < 1) { this localcharacter setgesture(this animationclip); this startcoroutine(this snapbone()); this startcoroutine(this waitforexit()); } else { // the seats are full this interactionicon showicon(); } } else { this localcharacter setgesture(this animationclip); this startcoroutine(this waitforexit()); } } private snapbone() { const animator animator = this localcharacter zepetoanimator; const bone transform = animator getbonetransform(this bodybone); let idx = 0; while(true) { const distance = vector3 op subtraction(bone position, this localcharacter transform position); const newpos vector3 = vector3 op subtraction(this transform position, distance); this playergestureposition = newpos; this localcharacter transform position = this playergestureposition; this localcharacter transform rotation = this transform rotation; yield new waitforendofframe(); idx++; // calibrate position during 5 frames of animation if (idx > 5) { return; } } } // the exact method must go through the server code, // but it is calculated by the local client for server optimization private findotherplayernum() { const hitinfos = physics overlapsphere(this transform position, 0 1); let playernum = 0; if (hitinfos length > 0) { hitinfos foreach((hitinfo) => { if (hitinfo transform getcomponent\<zepetocharacter>()) { playernum ++; } }); } return playernum; } private waitforexit() { if (this localcharacter) { while (true) { if (this localcharacter tryjump || this localcharacter trymove) { this localcharacter cancelgesture(); this transform position = this outposition; this interactionicon showicon(); break; } else if(this issnapbone && this playergestureposition != this localcharacter transform position){ this interactionicon showicon(); break; } yield; } } } } スクリプトの流れは次のとおりです: アイコンがクリックされると、無効になり、dointeraction()カスタム関数を呼び出します。 dointeraction() issnapboneがチェックされている場合、 座席が空いている場合(allowoverlapがチェックされているか、findotherplayernum()カスタム関数の戻り値が1未満) アニメーションクリップに割り当てられたジェスチャーを取ります。 snapbone()コルーチンを開始し、zepetoキャラクターのbodyboneをtargettransformにアタッチします。 waitforexit()コルーチンを開始します。 zepetoキャラクターがジャンプしたり移動したり、コライダーエリアから出たりした場合、ジェスチャーをキャンセルし、アイコンをアクティブにします。 座席の定員が満杯のときにアイコンをアクティブにします。 issnapboneがチェックされていない場合、 アニメーションクリップに割り当てられたジェスチャーを取ります。 waitforexit()コルーチンを開始します。 3\) スクリプト作成が完了したら、スクリプトをdockpointオブジェクトに追加します。 4\) インスペクターでアニメーションクリップ、スナップボーン、ボディボーン、オーバーラップを許可します。 アニメーションクリップを割り当てます。これらはインタラクションに伴うジェスチャーです。 スナップボーンを確認します。ボディボーンに割り当てられた部分がドックポイントとして位置していることを確認してください。 ボディボーンをヒップに設定します。ヒップがドックポイントに位置していることを確認してください。これは座るジェスチャーになります。 オーバーラップを許可すると、複数の人が1つの席に座ることができるかどうかを決定できます。 ステップ 5 プレイ zepetoキャラクターがオブジェクトに近づくとボタンが表示され、離れると消えます。 設定したジェスチャーがボタンに近づいて相互作用すると再生されれば成功です。 ジェスチャーに加えて、相互作用後に発生するさまざまなイベントを実装できます。 以下は、相互作用後にアイテムを作成するイベントを実装する例です。 https //www youtube com/watch?v=ooazdb4 lgo https //www youtube com/watch?v=ooazdb4 lgo 📘 zepeto world サンプル 第3章 インタラクションサンプル https //github com/naverz/zepeto world sample/tree/main/assets/chapter3 https //github com/naverz/zepeto world sample/tree/main/assets/chapter3