创造你的世界
手势
31 分
zepetoworldcontent api 允许您为所需的手势/姿势类别设置缩略图,并在点击缩略图时启用特定的手势/姿势。 要使用 zepetoworldcontent api,您必须按如下方式编写导入语句。 import { officialcontenttype, worldservice, zepetoworldcontent, content } from 'zepeto world'; 包含手势/姿势信息的内容类的成员变量和函数信息如下: api 描述 public get id() string 内容唯一标识符 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 内容类型(世界 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 设置用户界面 步骤 1 1 创建手势按钮 1\) 添加层级 > 用户界面 > 画布,并将排序顺序设置为2,以避免被其他用户界面遮挡。 2\) 添加层级 > ui > 按钮。 步骤 1 2 组织手势面板 1\) 添加层级 > 创建空对象并重命名为 panelparent。 2\) 添加层级 > ui > 面板作为 panelparent 的子项。 3\) 关闭按钮:添加 ui > 按钮后,添加 onclick 事件以禁用手势面板。 4\) 打开按钮:请为上面创建的打开按钮添加一个激活手势面板的 onclick 事件。 5\) 添加一张图片作为标题区域。 6\) 配置一个滚动视图以显示手势缩略图。 添加层级 > ui > 滚动视图。 勾选水平并禁用滚动条图像,因为您只会使用垂直滚动,水平滚动将不需要。 在滚动视图的内容中添加网格布局,以将缩略图对齐为网格模式。 添加内容大小适配器,使对象的大小适合内容的大小。 当您实现脚本时,必须将滚动视图中的内容设置为手势缩略图的父级(以便整个区域被识别并滚动) 7\) 按手势类型配置选项卡。 添加层级 > 创建一个空对象作为面板的子项,并将其重命名为 gesturetitle。 这是切换按钮的父对象。 添加水平布局以水平对齐选项卡。 添加切换组组件。 👍 要配置更多选项卡,添加层级 > ui > 滚动视图,并在滚动视图选项中勾选水平。 8\) 将用作切换按钮的文本添加为gesturetitle的子项,并将其替换为全部。 将文本颜色设置为灰色。 添加在选中时显示的高亮文本作为文本的子项。 设置字体内容、大小和粗细相同,并将颜色设置为黑色。 添加切换组件。 指定组中的父对象。 添加您作为graphic的子项添加的高亮文本。 仅检查将首先显示的所有切换组件的ison。 以相同的方式创建gesture和pose切换按钮。 步骤 1 3 制作缩略图预制件 使用创建缩略图按钮作为预制件的方法,然后在脚本中生成它的实例。 1\) 将 ui > 按钮添加为 scroll view 中 content 的子项,并将其重命名为 prethumb。 2\) 添加 raw image 后,请将名称更改为 thumb。 此图像将作为缩略图。请适当调整大小。 3\) 添加文本。 设置位置以居中图像底部。 调整文字的大小和粗细,并添加内容大小适配器。 水平适配 首选大小 垂直适配 首选大小 4\) 如果设置完成,请将其制作成预制件并放入 resources 文件夹中。 步骤 1 4 用户界面设置指南视频 https //www youtube com/watch?v=v ias8t8wq0 https //www youtube com/watch?v=v ias8t8wq0 👍 视频中显示的用户界面大小和位置值是推荐的,但您可以将其修改为您想要的值! 一旦用户界面设置完成,继续进行脚本编写。 步骤 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\) 调用 contentsrequest() 自定义函数以在加载 zepeto 角色后生成缩略图。 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()函数使用每个缩略图中的手势内容信息为每个相应类别设置。 如果是适用类型则启用,不是则禁用。 完成脚本后,将关闭按钮和类型切换组分配给检查器。 类型切换组的入口是手势面板中切换组的子切换。 步骤 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; } } 手势加载器 多人游戏 默认情况下,单人游戏客户端代码中实现的脚本是相同的。 此外,客户端声明接口以包含 playergestureinfo。 当将您的信息发送到服务器时:请参见 sendmygesture() 自定义函数 当您的玩家按下缩略图以进行手势时,使用 room send() 将手势 id 发送到服务器。 当您取消手势时,处理它以发送您已取消的信息。 从服务器接收来自另一个客户端的手势信息时:"onchangegesture" 房间消息被发送到 this 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); } } } 完成脚本后,检查员将为multiplay分配一个额外的对象,使用zepeto world 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 中的服务器代码。 它创建了一个 onmessage() 回调,当手势在 oncreate() 中变化时,将手势信息发送给其他客户端。 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 管理玩家对象,这是客户端对象的唯一键值。 // 客户端可以通过将 add onadd 事件添加到 players 对象来检查有关添加的玩家对象的信息。 this state players set(client sessionid, player); } onleave(client sandboxplayer, consented? boolean) { // 通过设置 allowreconnection,可以保持电路的连接,但在基本指南中立即清理。 // 客户端可以通过将 add onremove 事件添加到 players 对象来检查有关已删除玩家对象的信息。 this state players delete(client sessionid); } }