创造你的世界
经济
ZEPETO 模型
25 分
zepeto 人体模型是一个支持试穿/销售服装的模型 api 包。 您将能够在世界中销售您制作的服装。 您可以创建一个穿着指定服装的 zepeto 角色 npc 的模型。 您可以通过与模型或物体互动来购买服装。 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 编辑器中,并在前面粘贴 'cr '。 📘 如果您是第一次制作物品,请参考以下指南。 \[ docid\ cqp0hzxkf0ddpqfy6eey8 ] 步骤 3 设置人形模型 人形模型可以通过三种方式制作。 只有您制作并发布的物品才能在 zepeto 人形模型中设置和出售。 在审核中被拒绝的物品无法出售。 因此,您必须登录 unity 才能使用此功能。 当您发布带有人形功能的包时,您还必须以编辑身份登录。 使用 zepeto 模板和 zepeto 模型类型的人形模型时,消耗的资源等同于进入的 zepeto 角色数量,这可能会影响优化。 如果您需要在世界中放置许多 zepeto 角色形状的人形模型,建议选择简单类型的人形模型,然后使用 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 可交互组件 character gameobject addcomponent\<mannequininteractable>(); }); // 查找所有 mannequin 组件 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 2 zepeto 模型类型 您可以通过将物品 id 添加到 zepeto 角色 npc 来设置人形的外观。 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\) 必须添加碰撞体以与对象进行交互。 必须勾选 istrigger。如果未勾选,则会自动处理为识别为触发器。 3\) 将人形组件添加到对象中。 4\) 请在检查器中设置以下内容。 图标:默认显示衣架图标。您可以将其更改为自定义图标。 图标位置:如果不存在,图标默认出现在带有人形组件的对象位置。 输入值后添加位置对象,以使其出现在所需位置。 zepeto id:请输入 zepeto 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; // 添加 mannequin 可交互组件 character gameobject addcomponent\<mannequininteractable>(); }); // 查找所有 mannequin 组件 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\) 将脚本添加到对象后,按 \[▶︎(播放)] 按钮运行它。 步骤 4 使用 mannequin 购买 如果您正确完成了人形设置,当您进入人形对象的碰撞体区域时,将出现一个交互图标。 当您点击图标时,购买窗口将出现,并显示您在模特上设置的物品。 您可以通过点击物品来试穿。 您已经拥有的物品将用勾号标记,而不是价格。 当您离开模特物体的碰撞区域时,试穿将被取消,您将返回到原来的服装。 以下是根据测试场景购买过程的工作方式。 步骤 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 管理玩家对象,这是客户端对象的唯一键值。 // 客户端可以通过将 add onadd 事件添加到 players 对象来检查有关玩家对象的信息。 this state players set(client sessionid, player); } async onleave(client sandboxplayer, consented? boolean) { // 通过设置 allowreconnection,可以保持电路的连接,但在基本指南中立即清理。 // 客户端可以通过将 add onremove 事件添加到 players 对象来检查有关已删除玩家对象的信息。 this state players delete(client sessionid); if (this changeditems has(client sessionid)) { this changeditems delete(client sessionid); } } } 6\) 打开多人服务器并进行测试。 事件功能 事件功能可从 zepeto mannequin 1 1 0 开始使用。 zepeto 模特 模特 true left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type left unhandled content type zepeto 模特 基础预览器 true left unhandled content type left unhandled content type left unhandled content type left unhandled content type onchagedvalue 类的成员变量信息如下: true left unhandled content type left unhandled content type left unhandled content type left unhandled content type 人偶 世界相机 如果未设置人偶 世界相机,则人偶交互图标的相机将设置为低深度的相机。 如果您希望设置特定的相机,可以使用人偶 世界相机来指定一个。 true left unhandled content type left unhandled content type left unhandled content type left unhandled content type 以下是现有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可交互组件 character gameobject addcomponent\<mannequininteractable>(); // 代码将mannequin图标世界画布相机设置为zepeto相机 mannequin worldcamera = zepetoplayers instance localplayer zepetocamera camera; }); // 查找所有mannequin组件 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(); }); }); } } 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 组件 character gameobject addcomponent\<mannequininteractable>(); }); // 查找所有 mannequin 组件 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); // 添加 oncontentsloaded 事件的监听器 this previewer oncontentsloaded addlistener((changedvalues)=>{ console log('内容已加载 ', changedvalues); }); this previewer previewcontents(); }); // 退出碰撞体 m oncancel addlistener(() => { mannequin closeui(); this previewer? resetcontents(); }); }); } }

