创造你的世界
手势
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); } }