创造你的世界
经济
ZEPETO 模型
25 分
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 编辑器中,并在前面粘贴 'cr '。 📘 如果您是第一次制作物品,请参考以下指南。 \[ 使用模板编辑器轻松创建物品 (2d) docid\ cqp0hzxkf0ddpqfy6eey8 ] 步骤 3 设置人形模型 人形模型可以通过三种方式制作。 只有您制作并发布的物品才能在 zepeto 人形模型中设置和出售。 在审核中被拒绝的物品无法出售。 因此,您必须登录 unity 才能使用此功能。 当您发布带有人形功能的包时,您还必须以编辑身份登录。 使用 zepeto 模板和 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 模特 模特 功能 描述 public static onselecteditem unityengine events unityevent$2\<itemcontent, 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 模特 基础预览器 功能 描述 public onchanged unityengine events unityevent$1\<zepeto mannequin basepreviewer changedvalue\[]>; 每当通过按压模型更改装备物品信息时,都会调用此方法,并传递 onchagedvalue 列表。 onchagedvalue 类的成员变量信息如下: public property zepetopropertyflag 服装部件信息 public id string 物品 id 人偶 世界相机 如果未设置人偶 世界相机,则人偶交互图标的相机将设置为低深度的相机。 如果您希望设置特定的相机,可以使用人偶 世界相机来指定一个。 变量 描述 人偶 世界相机 一个允许您手动设置人偶交互图标相机的变量。 以下是现有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(); }); }); } }