CREATE YOUR WORLD
Economy
ZEPETO 마네킹
27분
zepeto 마네킹은 옷을 입어보거나 판매할 수 있는 기능을 지원하는 마네킹 api 패키지입니다 당신이 만든 의류 아이템을 월드에서 판매할 수 있습니다 zepeto 캐릭터 npc의 지정된 의상을 입은 마네킹을 만들 수 있습니다 마네킹이나 물체와 상호작용하여 의류 아이템을 구매할 수 있습니다 https //www youtube com/watch?v=sag4h7b5om4 https //www youtube com/watch?v=sag4h7b5om4 1단계 설치 창 → 패키지 관리자 → zepeto world 패키지 1 21 15 이상을 먼저 설치하세요 그 후, zepeto module 1 0 8 패키지를 설치하세요 ❗️ 주의 성능 개선의 일환으로, 독립형 패키지가 zepeto module 1 0 8 및 이후 버전 패키지에 통합되었습니다 이전에 설치된 zepeto mannequin 패키지를 삭제하세요 기존 패키지를 제거한 후, zepeto module 패키지 버전 1 0 8 이상을 설치하세요 2단계 마네킹에 설정할 아이템 id 확인 👍 아이템 id 확인 방법 zepeto studio에서 아이템 제품을 클릭할 때 나타나는 url을 확인할 수 있습니다 아이템 id를 임의의 숫자 형태로 복사하여 unity editor에 붙여넣고, 앞에 'cr '를 붙입니다 📘 아이템을 처음 만드는 경우, 다음 가이드를 참조하세요 \[ 템플릿 편집기를 사용하여 쉽게 아이템 만들기 (2d) docid\ cqp0hzxkf0ddpqfy6eey8 ] 3단계 마네킹 설정하기 마네킹 객체는 총 세 가지 방법으로 제작할 수 있습니다 당신이 만든 아이템만 zepeto 마네킹으로 설정하고 판매할 수 있습니다 검토에서 거부된 아이템은 판매할 수 없습니다 따라서 이 기능을 사용하려면 unity에 로그인해야 합니다 마네킹 기능이 포함된 패키지를 게시할 때는 편집자로 로그인해야 합니다 zepeto 템플릿과 zepeto 모델 유형 마네킹을 사용할 때 소비되는 자원은 들어오는 zepeto 캐릭터 수에 해당하며, 이는 최적화에 영향을 미칠 수 있습니다 월드 내에 많은 zepeto 캐릭터 모양의 마네킹을 배치해야 하는 경우, 간단한 유형의 마네킹을 선택한 후, zepeto basemodel https //studio zepeto me/console/download/652892d3a80a9f5505ed888f 을 객체로 활용하는 것이 좋습니다 3단계 1 간단한 유형 가장 기본적인 것입니다 특정 객체는 마네킹 자식으로 추가하여 외관을 설정할 수 있습니다 1\) 상호작용할 객체를 추가합니다 2\) 객체와 상호작용하기 위해서는 충돌체를 추가해야 합니다 istrigger를 체크해야 합니다 체크하지 않으면 자동으로 트리거로 인식되도록 처리됩니다 충돌체를 추가하지 않고 마네킹 컴포넌트를 추가하려고 하면 아래와 같은 경고 창이 나타납니다 3\) 물체에 마네킹 구성 요소를 추가하십시오 4\) 검사기에서 다음을 설정하십시오 아이콘 기본적으로 행거 아이콘이 표시됩니다 사용자 정의 아이콘으로 변경할 수 있습니다 아이콘 위치 없으면 기본적으로 마네킹 구성 요소와 함께 물체 위치에 아이콘이 나타납니다 원하는 위치에 나타나도록 위치 객체를 추가한 후 값을 입력하십시오 ids 판매하고자 하는 의류 항목의 아이템 id를 입력하십시오 5\) 빈 객체를 추가하고 객체 이름을 mannequinscript로 작성하십시오 6\) zepeto 추가 > typescript를 선택하고 스크립트 이름을 mannequinscript로 작성하세요 7\) 아래와 같이 작성하세요 import { zepetoscriptbehaviour } from 'zepeto script'; import { zepetoplayers, spawninfo } from 'zepeto character controller'; import { worldservice } from 'zepeto world'; import { itemcontentsrequest, mannequin, mannequincomponent, mannequininteractable, mannequinpreviewer } from 'zepeto mannequin'; import { object } from 'unityengine'; export default class mannequinscript extends zepetoscriptbehaviour { private previewer mannequinpreviewer; start() { // 로그인한 id를 기반으로 zepeto 캐릭터를 생성하는 코드 // zepetoplayers instance createplayerwithuserid(worldservice userid, spawninfo default, true); zepetoplayers instance onaddedlocalplayer addlistener(() => { const character = zepetoplayers instance localplayer zepetoplayer character; // mannequin interactable component 추가 character gameobject addcomponent\<mannequininteractable>(); }); // 모든 mannequin 컴포넌트 찾기 const mannequins = object findobjectsoftype\<mannequincomponent>(); mannequins foreach(m => { // collider에 들어가기 m onactive addlistener(contents => { mannequin openui(contents); const zepetocontext = zepetoplayers instance localplayer zepetoplayer character context; this previewer = new mannequinpreviewer(zepetocontext, contents); this previewer previewcontents(); }); // collider에서 나가기 m oncancel addlistener(() => { mannequin closeui(); this previewer? resetcontents(); }); }); } } 8\) 객체에 스크립트를 추가한 후 \[▶︎(재생)] 버튼을 눌러 실행하세요 step 3 2 zepeto 모델 유형 zepeto 캐릭터 npc에 아이템 id를 추가하여 마네킹의 외관을 설정할 수 있습니다 1\) 빈 오브젝트를 생성하고 이름을 마네킹으로 지정합니다 2\) 오브젝트와 상호작용하기 위해서는 콜라이더를 추가해야 합니다 istrigger를 체크해야 합니다 체크하지 않으면 자동으로 트리거로 인식됩니다 3\) 오브젝트에 마네킹 구성 요소를 추가합니다 4\) 인스펙터에서 다음을 설정해 주세요 아이콘 기본적으로 행거 아이콘이 표시됩니다 사용자 정의 아이콘으로 변경할 수 있습니다 아이콘 위치 없으면 기본적으로 마네킹 구성 요소와 함께 오브젝트 위치에 아이콘이 나타납니다 원하는 위치에 나타나도록 위치 오브젝트를 추가한 후 값을 입력합니다 ids 판매하고자 하는 의류 아이템의 id를 입력해 주세요 포즈 포즈를 선택하고 설정할 수 있습니다 앞으로 원하는 포즈를 포즈 id 형태로 제공할 예정입니다 👍 장면에 이미 마네킹 스크립트가 있는 경우, 이후 단계를 건너뛸 수 있습니다 5\) 빈 오브젝트를 추가하고 오브젝트 이름을 mannequinscript로 작성합니다 6\) zepeto > typescript를 추가하고 스크립트 이름을 mannequinscript로 작성합니다 7\) 아래와 같이 작성합니다 import { zepetoscriptbehaviour } from 'zepeto script'; import { zepetoplayers, spawninfo } from 'zepeto character controller'; import { worldservice } from 'zepeto world'; import { itemcontentsrequest, mannequin, mannequincomponent, mannequininteractable, mannequinpreviewer } from 'zepeto mannequin'; import { object } from 'unityengine'; export default class mannequinscript extends zepetoscriptbehaviour { private previewer mannequinpreviewer; start() { // 로그인한 id를 기반으로 zepeto 캐릭터를 생성하는 코드 // zepetoplayers instance createplayerwithuserid(worldservice userid, spawninfo default, true); zepetoplayers instance onaddedlocalplayer addlistener(() => { const character = zepetoplayers instance localplayer zepetoplayer character; // 마네킹 상호작용 컴포넌트 추가 character gameobject addcomponent\<mannequininteractable>(); }); // 모든 마네킹 컴포넌트 찾기 const mannequins = object findobjectsoftype\<mannequincomponent>(); mannequins foreach(m => { // 충돌체에 들어가기 m onactive addlistener(contents => { mannequin openui(contents); const zepetocontext = zepetoplayers instance localplayer zepetoplayer character context; this previewer = new mannequinpreviewer(zepetocontext, contents); this previewer previewcontents(); }); // 충돌체에서 나가기 m oncancel addlistener(() => { mannequin closeui(); this previewer? resetcontents(); }); }); } } 8\) 객체에 스크립트를 추가한 후 \[▶︎(재생)] 버튼을 눌러 실행합니다 3단계 3 zepeto 템플릿 유형 zepeto id를 입력하면 해당 사람이 입고 있는 옷이 마네킹으로 나타납니다 그러나 당신이 만든 옷이 아니라면 옷이 표시되지 않습니다 1\) 빈 객체를 만들고 이름을 마네킹으로 지정합니다 2\) collider는 객체와 상호작용하기 위해 추가되어야 합니다 istrigger를 체크해야 합니다 체크하지 않으면 자동으로 트리거로 인식됩니다 3\) 객체에 마네킹 구성 요소를 추가하세요 4\) 인스펙터에서 다음을 설정해 주세요 아이콘 기본적으로 행거 아이콘이 표시됩니다 사용자 정의 아이콘으로 변경할 수 있습니다 아이콘 위치 없으면 기본적으로 마네킹 구성 요소와 함께 객체 위치에 아이콘이 나타납니다 원하는 위치에 나타나도록 위치 객체를 추가한 후 값을 입력하세요 zepeto id zepeto id를 입력해 주세요 포즈 포즈를 선택하고 설정할 수 있습니다 앞으로 원하는 포즈를 포즈 id 형태로 제공할 예정입니다 👍 이미 장면에 마네킹 스크립트가 있는 경우, 이후 단계를 건너뛸 수 있습니다 5\) 빈 객체를 추가하고 객체 이름을 mannequinscript로 작성하세요 6\) zepeto를 추가하고 스크립트 이름을 mannequinscript로 작성하세요 7\) 아래와 같이 작성하세요 import { zepetoscriptbehaviour } from 'zepeto script'; import { zepetoplayers, spawninfo } from 'zepeto character controller'; import { worldservice } from 'zepeto world'; import { itemcontentsrequest, mannequin, mannequincomponent, mannequininteractable, mannequinpreviewer } from 'zepeto mannequin'; import { object } from 'unityengine'; export default class mannequinscript extends zepetoscriptbehaviour { private previewer mannequinpreviewer; start() { // 로그인한 id를 기반으로 zepeto 캐릭터를 생성하는 코드 // zepetoplayers instance createplayerwithuserid(worldservice userid, spawninfo default, true); zepetoplayers instance onaddedlocalplayer addlistener(() => { const character = zepetoplayers instance localplayer zepetoplayer character; // mannequin interactable component 추가 character gameobject addcomponent\<mannequininteractable>(); }); // 모든 mannequin 컴포넌트 찾기 const mannequins = object findobjectsoftype\<mannequincomponent>(); mannequins foreach(m => { // collider에 들어가기 m onactive addlistener(contents => { mannequin openui(contents); const zepetocontext = zepetoplayers instance localplayer zepetoplayer character context; this previewer = new mannequinpreviewer(zepetocontext, contents); this previewer previewcontents(); }); // collider에서 나가기 m oncancel addlistener(() => { mannequin closeui(); this previewer? resetcontents(); }); }); } } 8\) 객체에 스크립트를 추가한 후 \[▶︎(재생)] 버튼을 눌러 실행하세요 4단계 마네킹 구매 사용하기 마네킹 설정을 올바르게 완료하면, 마네킹 객체의 collider 영역에 들어갈 때 상호작용 아이콘이 나타납니다 아이콘을 클릭하면 설정한 아이템과 함께 구매 창이 나타납니다 아이템을 클릭하면 착용해 볼 수 있습니다 이미 소유하고 있는 아이템은 가격 대신 체크 표시로 표시됩니다 맨니킨 객체의 콜라이더 영역을 벗어나면 착용이 취소되고 원래의 의상으로 돌아갑니다 다음은 테스트 시나리오에 따른 구매 프로세스 작동 방식입니다 step 5 맨니킨 멀티플레이어 동기화 멀티플레이어는 마네킹 기능을 사용하여 다른 플레이어가 착용한 의상을 동기화해야 합니다 👍 기본 멀티플레이어 설정은 아래 내용을 작업하기 전에 완료되어야 합니다 1\) 클라이언트 스크립트를 추가합니다 zepeto > typescript를 추가하고 스크립트 이름을 mannequincontroller로 작성합니다 2\) 아래와 같이 작성합니다 import { zepetoscriptbehaviour } from 'zepeto script'; import { room } from 'zepeto multiplay'; import { clothespreviewer, itemcontent, itemcontentsrequest, mannequin, mannequincomponent, mannequininteractable, mannequinpreviewer } from 'zepeto mannequin'; import { zepetocontext } from 'zepeto'; import { zepetoplayer, zepetoplayers } from 'zepeto character controller'; import { gameobject, object, canvas, waitforsecondsrealtime, layermask } from 'unityengine'; import { player } from 'zepeto multiplay schema'; import { zepetoworldmultiplay } from 'zepeto world'; class characteritem { property string; id string; } class changeditem { sessionid string; characteritems characteritem\[]; } export default class mannequincontroller extends zepetoscriptbehaviour { private message type = { onchangeditem "onchangeditem", syncchangeditem "syncchangeditem", checkchangeditem "checkchangeditem" } private multiplay zepetoworldmultiplay; private room room; private previewer mannequinpreviewer private context zepetocontext private userzepetocontexts map\<string, zepetocontext> = new map\<string, zepetocontext>(); private currentmannequincomponent mannequincomponent = null; private selectmannequincomponent mannequincomponent = null; private isopenmannequinui boolean = false; private basicclothstring = "basiccloth" as const; start() { this multiplay = object findobjectoftype\<zepetoworldmultiplay>(); mannequin onopenedshopui addlistener((item) => { // 상점 버튼을 클릭했을 때 this openedshopui(item) }); mannequin onclosedshopui addlistener(() => { // 닫기 버튼을 클릭했을 때 this closedshopui() }); mannequin onselecteditem addlistener((itemcontent itemcontent, select boolean) => { // 아이템이 선택되었을 때의 동작 }); zepetoplayers instance onaddedlocalplayer addlistener(() => { const myplayer = zepetoplayers instance localplayer zepetoplayer; // 마네킹 const character = myplayer character; character gameobject addcomponent\<mannequininteractable>(); console log("로컬 context 설정됨"); this context = character context; const mannequins = object findobjectsoftype\<mannequincomponent>() mannequins foreach(mannequin => { // 마네킹 충돌체에 들어갔을 때 mannequin onactive addlistener(contents => { if (this currentmannequincomponent != null && this currentmannequincomponent == mannequin) { return; } if (contents == null || contents length == 0) { console log("마네킹 데이터 없음"); return; } if (this isopenmannequinui) { this breakmannequin(); } this selectmannequincomponent = mannequin; mannequin openui(contents); console log("onactive"); }); // \[옵션] 마네킹 충돌체에서 나갔을 때 mannequin oncancel addlistener( () => { if (this currentmannequincomponent == null || this currentmannequincomponent != mannequin) { return; } this breakmannequin(); console log("oncancel"); }); let iconcanvas = mannequin gameobject getcomponentinchildren\<canvas>(true); if (iconcanvas != null) { iconcanvas gameobject layer = layermask nametolayer("ui"); } }); }); zepetoplayers instance onaddedplayer addlistener((sessionid string) => { if (zepetoplayers instance getplayer(sessionid) islocalplayer) { return; } const usercontext = zepetoplayers instance getplayer(sessionid) character context; this userzepetocontexts set(sessionid, usercontext); this room send(this message type checkchangeditem, sessionid); }); this multiplay roomjoined += (room room) => { this room = room; this addmessagehandler(); }; } private addmessagehandler() { // \[옵션] 각 플레이어의 옷을 동기화 this room addmessagehandler\<changeditem>(this message type syncchangeditem, message => { console log("syncchangeditem"); if (message == null) { return; } if (false == this userzepetocontexts has(message sessionid)) { return; } let itemcontents itemcontent\[] = \[]; for (const characteritem of message characteritems) { let itemcontent itemcontent = new itemcontent(); itemcontent id = characteritem id; itemcontent property = parseint(characteritem property); if (itemcontent id == this basicclothstring) { itemcontent id = ""; } itemcontents push(itemcontent); } let clothespreviewer\ clothespreviewer = new clothespreviewer(this userzepetocontexts get(message sessionid),itemcontents); clothespreviewer previewcontents(); }); } private closedshopui() { this currentmannequincomponent = null; this isopenmannequinui = false; } private openedshopui(items itemcontent\[]) { this isopenmannequinui = true; this currentmannequincomponent = this selectmannequincomponent; this previewer = new mannequinpreviewer(this context, items); this previewer onchanged addlistener((changevalues) => { let characteritems characteritem\[] = \[]; for (const changevalue of changevalues) { let characteritem characteritem = new characteritem(); characteritem id = changevalue id; characteritem property = changevalue property tostring(); if (characteritem id == "") { characteritem id = this basicclothstring; } characteritems push(characteritem); } this room send(this message type onchangeditem, characteritems); }); this previewer previewcontents(); } public breakmannequin() { mannequin closeui(); if (this previewer) { this previewer resetcontents(); this previewer = null; } this currentmannequincomponent = null; this isopenmannequinui = false; } } 3\) 계층 구조 만들기 > 빈 객체를 만들고 이름을 마네킹 컨트롤러로 지정합니다 4\) 방금 작성한 스크립트를 마네킹 컨트롤러에 추가하세요 5\) 다음으로, world multiplay > index ts의 내용을 참조하여 서버 코드를 작성하세요 import { sandbox, sandboxoptions, sandboxplayer } from 'zepeto multiplay'; import { player, transform, vector3 } from 'zepeto multiplay schema'; class characteritem { property string; id string; } class changeditem { sessionid string; characteritems characteritem\[]; } enum cloth { top = "19", bottom = "20" , dress = "22" } export default class extends sandbox { private message type = { onchangeditem "onchangeditem", syncchangeditem "syncchangeditem", checkchangeditem "checkchangeditem" } // map\<sessionid, map\<characteritem property, characteritem id>> private changeditems map\<string, map\<string, string>>; 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 changeditems = new map\<string, map\<string, string>>(); this onmessage\<characteritem\[]>(this message type onchangeditem, (client, message) => { // 옷을 덮어쓰고 새로운 부품을 설정합니다 if (this changeditems has(client userid)) { const changeditemmap = this changeditems get(client userid); for (const characteritem of message) { if (characteritem property == cloth dress) { // 드레스(22)의 경우, 상의(19)와 하의(20)를 제거합니다 if (changeditemmap has(cloth top)) { changeditemmap delete(cloth top); } if (changeditemmap has(cloth bottom)) { changeditemmap delete(cloth bottom); } } else if (characteritem property == cloth top || characteritem property == cloth bottom) { // 상의(19) 또는 하의(20)인 경우 드레스를 제거합니다 if (changeditemmap has(cloth dress)) { changeditemmap delete(cloth dress); } } changeditemmap set(characteritem property,characteritem id); console log(`onchangeditem old ${client userid} ${characteritem property} // ${characteritem id}`); } } else { // 초기 등록 let changeditemmap map\<string,string> = new map\<string, string>(); for (const characteritem of message) { changeditemmap set(characteritem property,characteritem id); } this changeditems set(client sessionid,changeditemmap); } let changeditem changeditem = new changeditem(); changeditem sessionid = client sessionid; changeditem characteritems = message; console log(`onchangeditem ${changeditem sessionid}`); for (const characteritem of changeditem characteritems) { console log(` ${characteritem property} ${characteritem id} `); } this broadcast(this message type syncchangeditem, changeditem, {except client}); }); this onmessage\<string>(this message type checkchangeditem,(client, message) => { if (false == this changeditems has(message)) { return; } let changeditem changeditem = new changeditem(); changeditem sessionid = client sessionid; changeditem characteritems = \[]; for (const property of this changeditems get(message) keys()) { let characteritem characteritem = new characteritem(); characteritem property = property; characteritem id = this changeditems get(message) get(property); changeditem characteritems push(characteritem); } client send\<changeditem>(this message type syncchangeditem, changeditem ); }); } 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 userid) { player zepetouserid = client userid; } // 클라이언트 객체의 고유 키 값인 sessionid를 사용하여 플레이어 객체를 관리합니다 // 클라이언트는 players 객체에 add onadd 이벤트를 추가하여 추가된 플레이어 객체에 대한 정보를 확인할 수 있습니다 this state players set(client sessionid, player); } async onleave(client sandboxplayer, consented? boolean) { // allowreconnection을 설정하면 회로에 대한 연결을 유지할 수 있지만 기본 가이드에서는 즉시 정리합니다 // 클라이언트는 players 객체에 add onremove 이벤트를 추가하여 삭제된 플레이어 객체에 대한 정보를 확인할 수 있습니다 this state players delete(client sessionid); if (this changeditems has(client sessionid)) { this changeditems delete(client sessionid); } } } 6\) 멀티플레이어 서버를 켜고 테스트하세요 이벤트 기능 이벤트 기능은 zepeto mannequin 1 1 0부터 사용할 수 있습니다 zepeto mannequin mannequin 기능 설명 public static onselecteditem unityengine events unityevent$2\<itemcontent, boolean>; 마네킹 의상 구매 창에서 특정 항목이 선택될 때 호출되며, 선택된 항목 정보와 항목 선택이 boolean 값으로 전달됩니다 public static onsucceededpurchaseitems unityengine events unityevent$1\<itemcontent\[]>; 의상 구매가 완료되었을 때 호출되며, 구매한 항목 정보의 itemcontent 목록이 전달됩니다 public static onfailedpurchaseitems unityengine events unityevent$1\<itemcontent\[]>; 의상 구매가 실패했을 때 호출되며, 실패한 항목의 itemcontent 목록이 전달됩니다 public static onapplieditems unityengine events unityevent$1\<itemcontent\[]>; 의상 구매가 성공적으로 완료된 후 구매한 항목을 착용하기로 선택했을 때 호출되며, 착용한 항목 정보의 itemcontent 목록이 전달됩니다 public static onopenedshopui unityengine events unityevent$1\<itemcontent\[]>; 마네킹 의상 구매 창이 열릴 때 호출되며, 구매 창의 항목 정보의 itemcontent 목록이 전달됩니다 public static onclosedshopui unityengine events unityevent; 마네킹 의상 구매 창이 닫힐 때 호출됩니다 zepeto mannequin basepreviewer 기능 설명 public onchanged unityengine events unityevent$1\<zepeto mannequin basepreviewer changedvalue\[]>; 장비된 아이템 정보가 마네킹을 눌러 변경될 때 항상 호출되며, onchagedvalue 목록이 전달됩니다 onchagedvalue 클래스의 멤버 변수 정보는 다음과 같습니다 public property zepetopropertyflag 의류 부위 정보 public id string 아이템 id mannequin worldcamera 마네킹 월드카메라가 설정되지 않은 경우, 마네킹 상호작용 아이콘의 카메라는 낮은 깊이의 카메라로 설정됩니다 특정 카메라를 설정하려면 마네킹 월드카메라를 사용하여 지정할 수 있습니다 변수 설명 마네킹 월드카메라 마네킹 상호작용 아이콘의 카메라를 수동으로 설정할 수 있는 변수입니다 아래는 기존 mannequinscript에서 mannequin worldcamera의 설정 예시입니다 import { zepetoscriptbehaviour } from 'zepeto script'; import { zepetoplayers, spawninfo } from 'zepeto character controller'; import { worldservice } from 'zepeto world'; import { itemcontentsrequest, mannequin, mannequincomponent, mannequininteractable, mannequinpreviewer } from 'zepeto mannequin'; import { object } from 'unityengine'; export default class mannequinscript extends zepetoscriptbehaviour { private previewer mannequinpreviewer; start() { // 로그인한 id를 기반으로 zepeto 캐릭터를 생성하는 코드 // zepetoplayers instance createplayerwithuserid(worldservice userid, spawninfo default, true); zepetoplayers instance onaddedlocalplayer addlistener(() => { const character = zepetoplayers instance localplayer zepetoplayer character; // mannequin interactable component 추가 character gameobject addcomponent\<mannequininteractable>(); // mannequin icon world canvas camera를 zepeto camera로 설정하는 코드 mannequin worldcamera = zepetoplayers instance localplayer zepetocamera camera; }); // 모든 mannequin 컴포넌트 찾기 const mannequins = object findobjectsoftype\<mannequincomponent>(); mannequins foreach(m => { // collider에 들어가기 m onactive addlistener(contents => { mannequin openui(contents); const zepetocontext = zepetoplayers instance localplayer zepetoplayer character context; this previewer = new mannequinpreviewer(zepetocontext, contents); this previewer previewcontents(); }); // collider에서 나가기 m oncancel addlistener(() => { mannequin closeui(); this previewer? resetcontents(); }); }); } } oncontentsloaded api mannequin api를 사용하여 의류 아이템을 장착할 때 모든 의류 아이템이 완전히 로드되면 트리거되는 콜백이 추가되었습니다 api public oncontentsloaded unityengine events unityevent$1\<zepeto mannequin basepreviewer changedvalue\[]>; 기존 mannequinscript에서 oncontentsloaded를 설정하는 예는 다음과 같습니다 mannequinscript import { zepetoscriptbehaviour } from 'zepeto script'; import { zepetoplayers, spawninfo } from 'zepeto character controller'; import { worldservice } from 'zepeto world'; import { itemcontentsrequest, mannequin, mannequincomponent, mannequininteractable, mannequinpreviewer } from 'zepeto mannequin'; import { object } from 'unityengine'; export default class mannequinscript extends zepetoscriptbehaviour { private previewer mannequinpreviewer; start() { // 로그인한 id를 기반으로 zepeto 캐릭터를 생성하는 코드 // zepetoplayers instance createplayerwithuserid(worldservice userid, spawninfo default, true); zepetoplayers instance onaddedlocalplayer addlistener(() => { const character = zepetoplayers instance localplayer zepetoplayer character; // mannequin interactable component 추가 character gameobject addcomponent\<mannequininteractable>(); }); // 모든 mannequin 컴포넌트 찾기 const mannequins = object findobjectsoftype\<mannequincomponent>(); mannequins foreach(m => { // collider에 들어가기 m onactive addlistener(contents => { mannequin openui(contents); const zepetocontext = zepetoplayers instance localplayer zepetoplayer character context; this previewer = new mannequinpreviewer(zepetocontext, contents); // oncontentsloaded 이벤트에 리스너 추가 this previewer oncontentsloaded addlistener((changedvalues)=>{ console log('contents loaded ', changedvalues); }); this previewer previewcontents(); }); // collider에서 나가기 m oncancel addlistener(() => { mannequin closeui(); this previewer? resetcontents(); }); }); } }