创造你的世界
聊天
使用语音聊天功能
23 分
zepeto voice chat 预览版本包启用世界中的语音聊天。 安装 zepeto voice chat 并设置模式 1\) 安装 window → 包管理器 → zepeto voice chat。 此功能在实现了多人元素的世界中可用。 测试仅在移动测试中可用,而不在编辑器测试中可用。 由于 ios 政策,在启用语音聊天的世界中,打开麦克风时设备音量不会降至零。 关闭麦克风时,设备音量将降至零。 2\) 点击正在开发的 unity 项目屏幕中间菜单的 \[▼] 按钮。 在弹出菜单中点击 \[打开世界设置] 按钮。 3\) 如果正确安装了 zepeto voice chat 包,您将看到添加的语音聊天模式选项。 4\) 在语音聊天模式中,请设置所需的模式。 基本:使用默认提供的语音聊天功能。 脚本:通过实现语音聊天 api 使用语音聊天功能。 您可以在运行时处理语音聊天的房间访问进出。 为不同团队实现语音聊天(例如,红队语音聊天和蓝队语音聊天) 检测当前说话的用户 基本模式:使用语音聊天功能 一个拥有基本模式语音聊天的世界看起来是这样的。 您还可以使用语音调制功能创建更有趣的语音聊天。 进入具有语音聊天功能的世界时,语音聊天会自动启用。 👍 第一次在zepeto中使用语音聊天功能时,会出现关于麦克风访问的弹出窗口。 您必须允许访问才能使用语音聊天功能。 您可以通过触摸语音聊天按钮来使用它 在 zepeto 应用程序 3 26 000 及以上版本中,语音聊天扬声器图标不显示。 如果您想让语音图标显示,请切换到脚本模式并按照指南编写自己的代码。 脚本模式:使用 voicechat api 脚本模式在团队分隔的频道中启用语音聊天。 请参考下面的功能描述和示例来实现该功能。 api 描述 oninitializedevent 在初始化事件中,当发生true事件时,语音聊天api可用。 如果此事件为true,则语音聊天可用;如果为false,则语音聊天不可用。 enterroom(roomproperty roomproperty) 进入语音聊天房间的功能 成功进入语音聊天房间后,语音聊天按钮将出现 exitroom() 离开语音聊天房间的功能 onroomconnectedevent 检查进入语音聊天房间状态的事件。 如果此事件为真,则用户已进入语音聊天房间;如果为假,则用户已离开语音聊天房间。 onspeechdetectedevent\<string, boolean> 检测当前在语音聊天中说话的用户的事件。 string是说话用户的userid boolean在发言开始时为true,在发言结束时为false changeteamid(number teamid) 更改语音聊天房间中使用的teamid的功能 只能设置为1或更大的整数值 房间属性类 api 描述 setaudiomode 在语音聊天中使用的音频模式 audiomode omnidirectional 语音聊天模式,不基于距离进行语音衰减 (您可以与或不与zepeto角色一起使用) audiomode directional 语音聊天模式,基于距离进行语音衰减 (zepeto角色必须存在于场景中,因为此模式基于zepeto角色的位置) setteamid 在语音聊天中使用的teamid,以启用具有相同teamid的用户之间的语音聊天。 只能设置为1或更高的整数值 特定团队语音聊天实现示例 这里有一些示例代码来尝试语音聊天api。 1\) 添加一个按钮并将文本记录到画布上,如下图所示,以进入语音聊天团队频道并显示状态日志。 按钮 按钮 蓝队 蓝队语音聊天入口按钮 按钮 红队 红队语音聊天入口按钮 按钮 退出 退出语音聊天按钮 文本 文本 日志 显示聊天日志的文本 文本 团队 显示同一语音聊天团队频道成员列表的文本 文本 当前发言 显示当前在语音聊天中发言的用户id的文本。 2\) 创建项目 > 创建 > zepeto > typescript 并将其重命名为 voicechattest。 3\) 编写如下示例脚本。 voicechattest import { button, inputfield, text } from 'unityengine ui'; import { zepetoscriptbehaviour } from 'zepeto script' import { audiomode, roomproperty, voicechatcontroller } from 'zepeto voice chat' export default class voicechattest extends zepetoscriptbehaviour { // 声明 ui 组件为公共成员 public blueteambutton button; public redteambutton button; public exitroombutton button; public logtext text; public currentteamidtext text; public currentspeakinguseridstext text; // 声明私有成员以存储说话用户 id 和团队 id 输入字段 private currentspeakinguserids string\[]; private teamidinputfield inputfield; start() { this currentspeakinguserids = new array(); // 为按钮点击添加事件监听器 this blueteambutton onclick addlistener(()=>{ this enterblueteam(); }); this redteambutton onclick addlistener(()=>{ this enterredteam(); }); this exitroombutton onclick addlistener(()=>{ this exitvoicechatroom(); }); // 为语音聊天控制器添加事件监听器 voicechatcontroller oninitializedevent addlistener(init => this oninitialized(init)); voicechatcontroller onroomconnectedevent addlistener(connected => this onroomconnected(connected)); voicechatcontroller onspeechdetectedevent addlistener((userid, speechdetected) => this onspeechdetected(userid, speechdetected)); this logtext text = "\[voicechat] voicechattest 开始"; } // 当脚本被销毁时调用的 ondestroy 方法 ondestroy() { voicechatcontroller oninitializedevent removealllisteners(); voicechatcontroller onroomconnectedevent removealllisteners(); voicechatcontroller onspeechdetectedevent removealllisteners(); } // 当语音聊天系统初始化时调用的方法 private oninitialized(initialized boolean) { this logtext text = "\[voicechat] oninitialized " + initialized; } // 当语音聊天房间连接时调用的方法 private onroomconnected(connected boolean) { this logtext text = "\[voicechat] onroomconnected " + connected; } // 当检测到用户的语音或未检测到时调用的方法 private onspeechdetected(userid string, speechdetected boolean) { this logtext text = "\[voicechat] onspeechdetected " + userid + ", " + speechdetected; if (speechdetected) { this currentspeakinguserids push(userid); } else { let index = this currentspeakinguserids indexof(userid); this currentspeakinguserids splice(index, 1); } let userids = "\[当前说话用户 ids]\n"; for (let i = 0; i < this currentspeakinguserids length; i++) { userids += this currentspeakinguserids\[i]; userids += "\n"; } this currentspeakinguseridstext text = userids; } // 进入蓝队的语音聊天房间的方法 public enterblueteam(){ this entervoicechatroom(2); } // 进入红队的语音聊天房间的方法 public enterredteam(){ this entervoicechatroom(3); } // 根据给定的团队索引进入语音聊天房间的方法 private entervoicechatroom(teamindex number) { console log("\[voicechat] 进入语音聊天房间"); // 创建一个新的 roomproperty 对象并设置其属性 let roomproperty = new roomproperty(); roomproperty setaudiomode(audiomode omnidirectional); roomproperty setteamid(teamindex); voicechatcontroller enterroom(roomproperty); this currentteamidtext text = "团队 id " + roomproperty teamid tostring(); } // 退出语音聊天房间的方法 public exitvoicechatroom() { this logtext text = "\[voicechat] 退出语音聊天房间"; voicechatcontroller exitroom(); } // 更改当前用户的团队 id 的方法 public changeteamid() { // 从输入字段获取新的团队 id 并将其解析为整数 let teamid = parseint(this teamidinputfield text); this logtext text = "\[voicechat] 更改团队 id " + teamid; this currentteamidtext text = "团队 id " + teamid tostring(); // 在语音聊天系统中更改团队 id voicechatcontroller changeteamid(teamid); } } 代码描述 当脚本运行时,它将在 start() 函数中为每个按钮注册一个事件,并在 voicechatcontroller 上注册 oninitialized、onroomconnected 和 onspeechdetected 事件。 当点击蓝队按钮或红队按钮时,将执行 entervoicechatroom() 函数,用户通过输入指定的 roomproperty 进入语音聊天房间。示例中的房间属性如下。 roomproperty setaudiomode audiomode omnidirectional。omnidirectional 音频模式是一个无论玩家位置如何音量都相同的模式。相比之下,directional 模式是一个 3d 声音模式,这意味着音量会根据角色的位置而有所不同,因此角色离得越远,音量就会越小。 roomproperty setteamid 蓝队为频道 2,红队为频道 3。setteamid 在语音聊天中充当频道。进入频道 2 的团队只能与频道 2 中的玩家进行语音聊天,而进入频道 3 的团队只能与频道 3 中的玩家进行语音聊天。 exitvoicechatroom() 将退出当前的语音聊天团队频道。 onspeechdetected() 将输出当前在团队频道中使用语音聊天的玩家 id 到日志文本中。 4\) 完成脚本后,在检查器中分配步骤 1 中创建的按钮和文本。 5\) 通过二维码或测试链接在移动设备上运行测试,您可以看到在按下“进入团队”按钮时创建了语音聊天激活按钮,并且每当玩家说话时,日志会显示哪个玩家在语音聊天中,如下屏幕所示。 显示语音聊天气泡图像的示例 在zepeto app 3 26 000及更高版本中,语音聊天发言图标不显示。 如果您想处理发言图标的显示,请遵循指南并编写自己的代码。 1\) 当玩家在语音聊天中时,要在角色头上显示气泡,您需要创建一个使用气泡图像的预制件。导入您想使用的气泡png图像,如下所示,并将其纹理类型更改为sprite。 2\) 项目 > 创建 > 预制件,并将其重命名为chatbubble。 3\) 双击chatbubble预制件以进入预制件编辑模式。选择chatbubble预制件并选择变换 > 位置 > 将y值更改为0 35。 4\) 在预制对象内创建一个画布。 双击 chatbubble 预制件以进入预制编辑模式,然后添加层级 > ui > 画布。 将画布的 recttransform 组件的值更改为以下内容 posx 0 , posy 0 宽度 100, 高度 100 缩放x 0 005, 缩放y 0 005, 缩放z 0 005 将画布组件的 rendermove 更改为世界空间。 5\) 在画布内创建一个对话气泡图像。 将层级 > ui > 图像添加为画布的子项,并将其重命名为 chatbubbleimage。 将 chatbubbleimage 的 recttransform 组件的值更改为以下内容 宽度 42, 高度 42 将您在第 1 步中导入的图像精灵注册为图像组件中的源图像。 👍 提示 您还可以为气泡图像精灵添加动画效果。 您还可以为不同的团队使用单独的气泡图像。 6\) 项目 > 创建 > zepeto > 创建一个 typescript 并将其重命名为 voicechatbubblecontroller。 7\) 编写如下所示的示例脚本。 voicechatbubblecontroller import { gameobject, object } from 'unityengine'; import { knowsockets, zepetoplayers } from 'zepeto character controller' import { zepetoscriptbehaviour } from 'zepeto script' import { audiomode, roomproperty, voicechatcontroller } from 'zepeto voice chat'; export default class voicechatbubblecontroller extends zepetoscriptbehaviour { // 公共 gameobject 变量用于存储语音聊天气泡预制件 public voicechatprefab gameobject; // 私有映射用于存储与用户 id 相关的 gameobjects private voicebubblemap map\<string, gameobject> = new map\<string, gameobject>(); start() { // 为语音聊天控制器添加事件监听器 voicechatcontroller oninitializedevent addlistener(init => this oninitialized(init)); voicechatcontroller onroomconnectedevent addlistener(connected => this onroomconnected(connected)); voicechatcontroller onspeechdetectedevent addlistener((userid, speechdetected) => this onspeechdetected(userid, speechdetected)); } // 当语音聊天系统初始化时调用的方法 private oninitialized(initialized boolean) { console log("\[voicechat] oninitialized "); this entervoicechatroom(1); } // 当语音聊天房间连接时调用的方法 private onroomconnected(connected boolean) { console log("\[voicechat] onroomconnected "); } // 根据给定的团队索引进入语音聊天房间的方法 private entervoicechatroom(teamindex number) { console log("\[voicechat] entervoicechatroom"); // 创建一个新的 roomproperty 对象并设置其属性 let roomproperty = new roomproperty(); roomproperty setaudiomode(audiomode omnidirectional); voicechatcontroller enterroom(roomproperty); } // 当检测到或未检测到用户的语音时调用的方法 private onspeechdetected(userid string, speechdetected boolean) { console log("\[voicechat] onspeechdetected " + userid + ", " + speechdetected); // 检查用户 id 是否不在语音气泡映射中,如果不在则创建一个语音气泡 if (!this voicebubblemap has(userid)) { this createvoicebubble(userid); } this setvoicebubble(userid, speechdetected); } // 设置给定用户 id 的语音气泡的活动状态的方法 private setvoicebubble(userid string, speechdetected boolean) { const chatbubble = this voicebubblemap get(userid); chatbubble setactive(speechdetected); } // 为给定用户 id 创建语音气泡的方法 private createvoicebubble(userid string) { // 获取用户角色的头部插槽 const headsocket = zepetoplayers instance getplayerwithuserid(userid) character getsocket(knowsockets head upper); // 在头部插槽位置实例化语音聊天气泡预制件 const instancebubble = object instantiate(this voicechatprefab, headsocket) as gameobject; // 将实例化的气泡添加到语音气泡映射中 this voicebubblemap set(userid, instancebubble); instancebubble setactive(false); } lateupdate() { // 检查语音气泡映射是否为空,如果为空则返回 if (this voicebubblemap size === 0) { return; } // 遍历语音气泡映射并更新每个气泡 gameobject 的旋转 this voicebubblemap foreach((bubbleobject gameobject) => { // 设置气泡对象的旋转以匹配相机的父变换旋转 bubbleobject transform rotation = zepetoplayers instance zepetocamera cameraparent transform rotation; }); } } 代码描述 当脚本执行时,它将在start()函数中注册每个按钮的事件,并在voicechatcontroller的oninitialized、onroomconnected和onspeechdetected事件中注册事件。 在oninitialized()之后,当玩家进入世界时,语音聊天按钮将显示在玩家的屏幕上,当他们按下按钮时,将执行entervoicechatroom()以进入语音聊天房间。 每当玩家激活语音聊天并说话时,onspeechdetected()将被执行,如果speechdetected为true,则启用bubblechat对象,如果为false,则禁用它。 第一次激活onspeechdetected()函数时,createvoicebubble()将实例化一个voicechatprefab游戏对象,漂浮在玩家的头顶,并将其注册为 map数据。 我们使用lateupdate()每帧更新语音聊天气泡的旋转,以匹配zepeto世界的cameraparent。这确保了气泡图像始终面向相机。它首先检查 voicebubblemap是否为空,否则更新气泡图像预制件的旋转。 8\) 完成脚本编写后,在检查器中将voicechatprefab条目分配为您在步骤1中创建的气泡预制件。 9\) 通过二维码或测试链接在移动设备上运行,您应该会看到每当玩家使用语音聊天时,气泡图像出现在角色的头顶。 语音调制 从语音聊天版本 0 2 1 preview 开始,您可以在脚本模式下调节语音聊天的声音。 https //www youtube com/watch?v=yxfpuqypbqk https //www youtube com/watch?v=yxfpuqypbqk 使用 api 指南和示例代码尝试语音调制。 语音类型 (枚举) 值 描述 类型00 0 原始 类型01 1 小松鼠 类型02 2 叔叔 类型03 3 回声 类型04 4 低音 类型05 5 机器人 类型06 6 方言 类型07 7 扩音器 类型08 8 野兽 类型09 9 机器 类型10 10 强流 类型11 11 孩子 类型12 12 刺猬 这是一个声音调节的示例脚本。 import { button } from 'unityengine ui'; import { zepetoscriptbehaviour } from 'zepeto script'; import { roomproperty, voicechatcontroller, voicetype } from 'zepeto voice chat'; export default class voicemodulationmanager extends zepetoscriptbehaviour { // 设置不同语音类型的按钮 public buttons button\[]; start() { const voicetypes = \[ voicetype type00, voicetype type01, voicetype type05, voicetype type03, ]; for (const \[index, button] of this buttons entries()) { button onclick addlistener(() => { // 设置与点击按钮索引对应的语音类型 voicechatcontroller setvoicetype(voicetypes\[index]); }); }; // 当语音聊天系统初始化时调用的方法 voicechatcontroller oninitializedevent addlistener( init => { voicechatcontroller enterroom(new roomproperty());; } ); // 当语音聊天房间连接时调用的方法 voicechatcontroller onroomconnectedevent addlistener( connected => { // 设置初始语音类型并激活回音 voicechatcontroller setvoicetype(voicetypes\[0]); voicechatcontroller enableloopback(true); } ); } // 退出语音聊天房间的方法 ondestroy() { voicechatcontroller oninitializedevent removealllisteners(); voicechatcontroller onroomconnectedevent removealllisteners(); } } 代码描述: 为每个按钮添加一个 onclick 监听器,以设置不同的语音调制类型。 相同索引的元素在 按钮 数组和 语音类型 数组中是匹配的。 进入世界时, voicechatcontroller 被初始化,并且房间连接会自动建立。 初始语音调制类型设置为 type00 ,并启用回音以听到自己的声音。 请注意,调用 setvoicetype 和 enableloopback 时,需要房间连接。因此,初始设置在 onroomconnectedevent 的监听器中处理。 更改本地玩家的音频播放位置 您可以使用 voicechatcontroller setlocalplayertransform() 使用此功能,您可以通过将您的位置设置为特定空间或物体位置来创建各种场景,在语音聊天中进行交流。 📘 提示 语音聊天的变换与本地玩家的zepeto角色变换相关联。 因此,如果本地玩家的zepeto角色尚未在世界中创建,您的声音可能无法传输。 在这种情况下,您可以通过在当前场景中设置语音播放位置来使用语音聊天,使用 setlocalplayertransform() api 描述 public static setlocalplayertransform($transform unityengine transform)\ void 更改本地玩家音频播放位置的功能 ❗️ 注意 setlocalplayertransform() 必须在语音聊天初始化后某个时间调用 voicechatcontroller oninitializedevent(true) 。 1\) 以下是语音位置更改功能的示例脚本。 voicetransformsample import { gameobject, transform, vector3 } from 'unityengine'; import { button } from 'unityengine ui'; import { zepetoscriptbehaviour } from 'zepeto script'; import { audiomode, roomproperty, voicechatcontroller } from 'zepeto voice chat'; export default class voicetransformsample extends zepetoscriptbehaviour { // 设置语音变换为近的按钮 public buttonclosertransform button; // 设置语音变换为远的按钮 public buttonfarthertransform button; // 语音位置的变换 private voicetransform transform; start() { // 创建新的 gameobject 并分配变换以存储语音变换对象 const voicetransformobject = new gameobject; this voicetransform = voicetransformobject transform; // 当语音聊天系统初始化时调用的方法 voicechatcontroller oninitializedevent addlistener( init => { let roomproperty = new roomproperty(); // 将音频模式设置为定向 3d 空间音频 roomproperty setaudiomode(audiomode directional); voicechatcontroller enterroom(roomproperty); // 为本地玩家的语音设置语音聊天变换 voicechatcontroller setlocalplayertransform(this voicetransform); } ); // 当点击 'buttonclosetransform' 时将语音变换位置设置为 (0,0,0) this buttonclosertransform onclick addlistener(()=>{ this voicetransform position = vector3 zero; }) // 当点击 'buttonfartransform' 时将语音变换位置设置为远点 this buttonfarthertransform onclick addlistener(()=>{ this voicetransform position = new vector3(0,0, 10); }) } // 退出语音聊天房间的方法 ondestroy() { voicechatcontroller oninitializedevent removealllisteners(); voicechatcontroller onroomconnectedevent removealllisteners(); } } 代码描述 当场景开始时,在 start() 函数中创建一个名为 voicetransformobject 的游戏对象,并在 voicetransform 中注册 transform。 当语音聊天 oninitialized 监听器被调用时,请应用以下设置: 通过 setaudiomode(audiomode directional) 将语音聊天设置为 3d 空间音频模式。 通过 voicechatcontroller setlocalplayertransform() 将本地玩家的语音聊天位置设置为 voicetransform。 buttonclosertransform 在按钮被点击时将 voicetransform 的位置设置为原点 (0, 0, 0)。 buttonfarthertransform 在按钮被点击时将 voicetransform 的位置设置为 (10, 0, 0)。 2\) 将场景中的 canvas 上的按钮注册到 voicetransformsample 组件的 buttonclosertransform 和 buttonfarthertransform。 3\) 如果您使用二维码或测试链接在手机上运行它,您可以检查以下内容。 当您按下更近按钮时,您的声音会听起来更接近其他人。 当您按下更远按钮时,您的声音会被听到得离其他人很远。 https //www youtube com/watch?v=y pj4rcshts https //www youtube com/watch?v=y pj4rcshts