有奖捉虫:办公协同&微信生态&物联网文档专题 HOT
本文主要介绍如何快速运行 GME Unity Sample Project,并将工程示例代码接入到项目中。

跑通 Unity Sample Project

环境要求

Unity 2018.4.3f1 及以上版本。
Windows 平台设备。
能运行 Unity 工程的配置环境。

前提条件

请提前申请开通 GME 实时语音、语音消息服务,获取到 AppId 以及 Key。申请 GME 服务,详情请参见 服务开通,appId 对应控制台的 AppID,authKey 对应控制台的权限密钥。

打开工程

步骤1:下载工程

通过 下载指引 下载 Unity Sample Project,下载后请将文件进行解压。




步骤2:导入工程

在 Unity Hub 中点击【Open】按钮,导入步骤1中下载并解压过的工程,请注意导入工程的方式根据不同的 Unity Hub 版本会有所不同。




步骤3:修改配置

导入工程后,通过 Unity Hub 打开此工程。打开过程中会进行编译,请耐心等待一段时间。工程打开后会在 Console 窗口中显示报错信息,如下图:



此处报错信息为引导作用,具体修改方法如下参考操作 :
在 Project 窗口中, 通过路径 Assets/Scripts/Demo 找到代码文件 UserConfig.cs,打开此文件后,将如下代码中的 appID 及 appKey 修改为所申请的 GME 控制台 服务管理-应用设置 中的 AppID 以及权限密钥。
public static string GetAppID() {
return PlayerPrefs.GetString("AppID", AppID To Replace Here https://www.tencentcloud.com/document/product/607/10782);
}
public static string GetAuthKey(){
return PlayerPrefs.GetString("AuthKey", AppKey To Replace Here https://www.tencentcloud.com/document/product/607/10782);
}
此处如果是使用 macOS 平台 Unity 引擎进行开发,某些 Unity 版本下需要将路径 Assets/Editor 路径下的 add_dylib.cs 文件以及 iosProjectScript.cs 文件删除,才可以编译通过,并且需要参考 接入指引 文档对 SDK 文件进行配置,才可以顺利运行工程。

步骤4:编译运行

工程游戏场景存放在路径 Assets/Scene/ExperientialDemo 中,其中 ExHomeScene 为启动的第一个 Scene,请双击切换到此游戏场景。

运行程序

单击编辑器运行按钮,进入运行程序。




步骤1:初始化

UserID:相当于 openID,openID 是应用内用户的唯一标识符,每个端的 openid 必须唯一。
Login:单击 Login,进行初始化
 


点击 Login 后,会出现 2 个新按钮,单击 Voice Chat 进入实时语音房间配置界面。
Voice Chat:实时语音功能界面。
Voice Message:语音消息功能界面。



此界面的代码在 ExHomeViewController.cs 文件中。

步骤2:实时语音房间配置

RoomId:房间号码,同房间的人可以互相语音交流。
RoomType:请使用 Fluency 进入房间。
JoinRoom:进入语音房间。
配置好实时语音房间号后,单击 JoinRoom 进入实时语音房间。



此界面代码在 ExEnterRoomViewController.cs 文件中。

步骤3:实时语音功能体验

界面上会显示进房的 RoomID 以及本端的 openID。
RoomID:实时语音房间 ID。
Self Id:本端 openID。
Talking Members:房间内正在说话的成员,界面将会显示正在说话的成员 ID。
Mic:麦克风,勾选表示打开。 
Speaker:扬声器,勾选表示打开。
3D Voice Effect:3D 音效,勾选表示打开,需要同房间的用户同时打开麦克风、扬声器以及 3D Voice Effec 才可体验,通过设置以下参数进行效果配置:
Range:设置语音接收范围,单位为游戏引擎单位。
X:自身 X 轴。
Y:自身 Y 轴。
Z:自身 Z 轴。
XR:绕 X 坐标轴旋转的方向。
YR:绕 Y 坐标轴旋转的方向。
ZR:绕 Z 坐标轴旋转的方向。
Voice Change:实时语音音效,可通过选择不同的参数类型,改变播放音效特性,详情可参考 实时语音音效
QuitRoom:退出实时语音房间,回到上一界面。



此界面代码在 ExRoomViewController.cs 文件中。

步骤4:语音消息功能

在 ExHomeScene 界面中,点击 Login 之后,单击 Voice Message 进入语言消息界面:



Language:选择所录制的语言,录制后将转换为对应语言的文本,显示在 Audio-to-Text 一栏中。
Push To Talk:长按 Push To Talk,开始录制;松开 Push To Talk,结束录制。
Audio:录制的语音消息和语音时长。单击 

 按钮播放录音,播放过程中再次单击,结束播放。
Audio-to-Text:语音转换成的文字。
此界面代码在 ExPttViewController.cs 文件中。

Sample Project 代码介绍

使用 GME 实时语音主要的流程是 Init > EnterRoom > EnableMic > EnableSpeaker。

初始化相关

初始化相关的代码在 ExHomeViewController.cs 文件中的 OnClickLogin 方法中。这里面包含了初始化、语音消息的鉴权初始化、启动周期性调用 Poll 接口功能。
void OnClickLogin(){
string userId = transform.Find ("userId").GetComponent<InputField> ().text;
if (userId.Equals ("")) {
ShowWarnning("user is empty.");
return;
}
EnginePollHelper.CreateEnginePollHelper();
int ret = ITMGContext.GetInstance().Init(UserConfig.GetExperientialAppID(), userId);
if (ret != QAVError.OK){
ShowWarnning(string.Format("Init Failed {0}", ret));
return;
}
UserConfig.SetUserID(transform.Find("userId").GetComponent<InputField>().text);
byte[] sig = UserConfig.GetAuthBuffer(UserConfig.GetExperientialAppID(), "0", userId,UserConfig.GetExperientialauthkey());
if (sig != null){
ITMGContext.GetInstance().GetPttCtrl().ApplyPTTAuthbuffer(sig);
ShowWarnning("ApplyPTTAuthbuffer success");}
else{
ShowWarnning("get ptt token failed.");}
transform.Find("luanchPanel").gameObject.SetActive(true);
}
使用 GME 需要周期性的调用 Poll 接口。上面代码中调用了 EnginePollHelper.CreateEnginePollHelper 方法,该方法在 EnginePollHelper.cs 文件中。

进房相关

进房相关的代码在 ExEnterRoomViewController.cs 文件中的 OnClickJoinRoomBtn 方法中。
void OnClickJoinRoomBtn(){
string sRoomId = transform.Find("outroomPanel/roomIDInputField").GetComponent<InputField> ().text;
string roomtyepString = roomTypeDropdown.options[roomTypeDropdown.value].text; ITMGRoomType roomtype = _RoomtypeDic [roomtyepString];
showLoadingView(true, "JoiningRoom...");
byte[] authBuffer = UserConfig.GetAuthBuffer(UserConfig.GetExperientialAppID(), UserConfig.GetUserID(), sRoomId,UserConfig.GetExperientialauthkey());
ITMGContext.GetInstance().EnterRoom(sRoomId, roomtype, authBuffer);
UserConfig.SetRoomID(sRoomId);
UserConfig.SetRoomType(roomtype);
}
进房回调监听代码如下:
ITMGContext.GetInstance().OnEnterRoomCompleteEvent += new QAVEnterRoomComplete(OnEnterRoomComplete);
进房回调在同一脚本中的 OnEnterRoomComplete 方法中。
void OnEnterRoomComplete(int err, string errInfo){
showLoadingView (false, "");
if (err != 0) {
ShowWarnning (string.Format ("join room failed, err:{0}, errInfo:{1}", err, errInfo));
return;
}
else{
UnityEngine.Application.LoadLevel("ExRoomScene");
}
}

打开设备

进房成功后打开设备,相关代码在 ExRoomViewController.cs 中按钮相关的 Toggle 事件。
void onMicToggle(bool value){
ITMGContext.GetInstance().GetAudioCtrl().EnableMic(value);
}
void onSpeakerToggle(bool value){
ITMGContext.GetInstance().GetAudioCtrl().EnableSpeaker(value);
}

3D 音效相关

3D 音效的接入可以参考 3D 音效文档。在工程中,首先初始化 3D 音效功能,相关代码在 ExRoomViewController.cs 代码文件的 OnVoice3DToggle 方法中。
public void OnVoice3DToggle(bool value){
if (value){
ITMGContext.GetInstance().GetAudioCtrl().InitSpatializer(null);
}
ITMGContext.GetInstance().GetAudioCtrl().EnableSpatializer(value, false);
transform.Find("inroomPanel/3DVoicePanel").gameObject.SetActive(value);
updateSpatializer();
}
通过 updateSpatializer 接口更新自身位置坐标及朝向信息。
public void updateSpatializer(){
string strRange = transform.Find("inroomPanel/3DVoicePanel/InputFieldRange").GetComponent<InputField>().text;
int range = 0;
if (Int32.TryParse(strRange, out range)){
ITMGContext.GetInstance().GetRoom().UpdateAudioRecvRange(range);}
int x = (int)transform.Find("inroomPanel/3DVoicePanel/SliderX").GetComponent<Slider>().value;
int y = (int)transform.Find("inroomPanel/3DVoicePanel/SliderY").GetComponent<Slider>().value;
int z = (int)transform.Find("inroomPanel/3DVoicePanel/SliderZ").GetComponent<Slider>().value;
float xRotate = transform.Find("inroomPanel/3DVoicePanel/SliderXRotate").GetComponent<Slider>().value;
float yRotate = transform.Find("inroomPanel/3DVoicePanel/SliderYRotate").GetComponent<Slider>().value;
float zRotate = transform.Find("inroomPanel/3DVoicePanel/SliderZRotate").GetComponent<Slider>().value;
transform.Find("inroomPanel/3DVoicePanel/TextXShow").GetComponent<Text>().text = string.Format("{0}", x);
transform.Find("inroomPanel/3DVoicePanel/TextYShow").GetComponent<Text>().text = string.Format("{0}", y);
transform.Find("inroomPanel/3DVoicePanel/TextZShow").GetComponent<Text>().text = string.Format("{0}", z);
transform.Find("inroomPanel/3DVoicePanel/TextPitchShow").GetComponent<Text>().text = string.Format("{0}", (int)xRotate);
transform.Find("inroomPanel/3DVoicePanel/TextYawShow").GetComponent<Text>().text = string.Format("{0}", (int)yRotate);
transform.Find("inroomPanel/3DVoicePanel/TextRollShow").GetComponent<Text>().text = string.Format("{0}", (int)zRotate);
Quaternion rotation = Quaternion.Euler((float)xRotate, (float)yRotate, (float)zRotate); Matrix4x4 matrix = Matrix4x4.TRS(Vector3.zero, rotation, Vector3.one);
int[] position = new int[3] { z, x, y };
float[] axisForward = new float[3] { matrix.m22, matrix.m02, matrix.m12 };
float[] axisRight = new float[3] { matrix.m20, matrix.m00, matrix.m10 };
float[] axisUp = new float[3] { matrix.m21, matrix.m01, matrix.m11 };
ITMGContext.GetInstance().GetRoom().UpdateSelfPosition(position, axisForward, axisRight, axisUp);
}