目录

Unity3D的实现

本文将会使用Unity3D来完成上一节中的客户端实现。

本文导览:

Unity版本

本教程中使用的版本为Unity2017.2.0f3,并向下兼容。

先附上客户端Unity3D的源代码:点我下载(里面包含了对应的服务端源代码)。

Unity3D是一款游戏开发引擎,它可以让我们能轻松创建诸如三维视频游戏、建筑可视化、实时三维动画等类型的互动内容多平台综合型游戏开发工具。

第一步:生成客户端SDK

ComblockEngine提供了专属的SDK生成器,它是为了方便开发者而专门制作的工具,使开发者面对不同的客户端引擎时都可以游刃有余。

引擎提供的SDK生成器会自动根据引擎开发过程中涉及的通讯协议、数据结构(包括自定义的数据结构)、Entity实体定义等方面与客户端SDK进行一一对应,保证高度一致性。

介绍完SDK生成器,我们来看看如何修改配置,使其对应Unity3D引擎。

1. 修改SDK生成路径:

在本项目的资产库“getstarted_assets”下,找到gensdk.bat,使用编辑工具或记事本打开,找到最后一行:

start %KBE_BIN_PATH%/kbcmd.exe --clientsdk=unity --outpath=%curpath%/kbengine_unity3d_plugins
start %KBE_BIN_PATH%/kbcmd.exe --clientsdk=ue4 --outpath=%curpath%/kbengine_ue4_plugins

其中:
clientsdk:指定输出SDK的客户端类型,这里填写unity。生成器会自动选择合适的生成模板和逻辑进行生成。

outpath:指定SDK的输出路径。请确保路径是在Plugins文件夹下,并且修改成你的客户端工程所在目录下的对应路径

Tips:

如果引擎脚本开发工程师和客户端工程师是同一人,或者为了立刻验证SDK的结果是否如预期,我们建议outpath设置成Unity3D工程下的对应目录,如:your_project/Assets/Plugins/kbengine/kbengine_unity3d_plugins。每次生成SDK后可直接切回客户端进行测试,减少了重复粘贴复制的操作。

Plugins文件夹是Unity内的特殊文件夹,用于存放插件的。如果没有,请创建该文件夹。

这里我们选择直接输出到Unity3D客户端对应的路径中。


2. 执行工具,生成SDK代码:

编辑完成后保存退出,双击执行gensdk.bat。如下图:

等待生成完毕,进入客户端对应的文件夹查看。


3. 文件夹结构介绍:

接下来,我们看看生成的文件有哪些?(本文使用Visual Studio 2017打开的客户端工程)

1 1

我们可以看到FirstEntityBaseEntityCallFirstEntityBase,这和我们在服务端定义的FirstEntity实体名字很相似。

生成规则:

1、服务端定义了有客户端部分的实体(声明了hasClient=true的),则会生成类似实体名+Base.cs的文件,它是一个抽象类,我们只需继承它、实现它,并使用实体名为类名即可,如这里的FirstEntityBase,该类中会包含def中声明的客户端方法,如本教程中的onEnteronSay

2、被生成的实体,会对应包含一个类似EntityCall+实体名+Base.cs的文件,该文件是对应实体的EntityCall的实现。该类中会包含该实体的被暴露给客户端的通讯方法(被设置了Exposed标签的),如FirstEntity在def中声明的say方法。


第二步:实现Client部分

1. 客户端设计概述

服务器回顾:

先来回顾下本教程的服务器设计,我们把FirstEntity与账户入口关联,使得客户端一旦连接服务器并通过登录认证后就会创建出FirstEntity实体,此时该实体的客户端部分也会被创建。一旦创建完毕后会被立即传送到FirstSpace所在空间中去,完成后会通过onEnter的远程方法通知客户端。接着,客户端向服务器发出say请求后,服务器会进行广播,并通过客户端的onSay方法告知所有在同一空间的客户端。

客户端设计:

我们分为两个场景,一个叫做scene_login登录场景,默认打开,负责与服务器连接、登录认证。一旦成功登录并进入空间后,服务器会调用FirstEntity的客户端远程方法onEnter,从该方法的实现中让客户端进入另一个场景scene_world,其负责say的发送以及处理onSay的远程调用。

1

好了,让我们开始动手吧!

2. 实现scene_login登录场景

2.1 场景制作

场景列表视图如下:

1

其中:

client_app: 是引擎sdk的入口,附上脚本clientapp.cs,并保持默认配置。

1

panel_login:是使用UGUI制作的一个简单的登录界面,附上脚本UILogin.cs,且登录按钮绑定了UILogin的OnLoginClick事件。 1 1

UI效果图如下:

1


2.2 实现UILogin

直接上代码块:

/// <summary>
/// 登录界面的绘制
/// </summary>
public class UILogin : MonoBehaviour
{
    /// <summary>
    /// 响应登录按钮,该按钮在Unity的UGUI系统中被绑定到按钮事件上。
    /// </summary>
    public void OnLoginClick()
    {
        //账号密码都要大于6位
        //得到账户输入框的文本
        string account = GameObject.Find("account").GetComponent<InputField>().text;
        //得到密码输入框的文本
        string password = GameObject.Find("psw").GetComponent<InputField>().text;
        //调用API的登录接口。最后一个参数可暂时无视,具体请参考API手册
        KBEngineApp.getSingleton().login(account, password, System.Text.Encoding.UTF8.GetBytes("kbengine_unity3d_demo"));
    }
}

Unity3D的代码就不再赘述,这里主要调用了API中的login方法进行了登录请求,该API会先进行服务器连接,成功后调用登录方法。


3. 实现FirstEntityBase

按照刚才的设计,登录成功后,FirstEntity的客户端部分会被创建,也就是说客户端上FirstEntity对象会被创建,接着进入空间后,会通过FirstEntity.onEnter通知客户端,所以我们来实现一下FirstEntity的客户端部分。

FirstEntityBase是对应服务端的FirstEntity实体的,我们实现它即可完成其客户端部分。

我们来看一下代码:

/// <summary>
/// FirstEntity的客户端实现
/// </summary>
public class FirstEntity : FirstEntityBase
{
    public override void onEnter()
    {
        //日志
        Dbg.INFO_MSG("FirstEntity::onEnter");
        //当进入后,加载某个场景
        SceneManager.LoadScene("scene_world");      
    }

    public override void onSay(string content)
    {
        Dbg.INFO_MSG(content);
        //找到UI Text对象
        Text text = GameObject.Find("Canvas/Text").GetComponent<Text>();
        //增加一行say的内容
        text.text = text.text + "\n" + content;
    }
}

onEnter:我们注意到,该函数名和服务端FirstEntity实体的DEF配置文件中的client部分定义的一模一样!对,这就是SDK生成器帮你做的事情。在生成的FirstEntityBase类中使用抽象函数public abstract void onEnter();定义了该方法,并由SDK内部进行了通讯上的对应和处理,我们只需要在继承类FirstEntity中实现即可。

onSay:该方法也是和DEF配置文件中的client部分一样,并且连方法签名也是一致的!

注意:

每个被指定有Client部分的实体,在客户端上必须要有实现类且类名和实体名字一致。比如这里的FirstEntity : FirstEntityBase,不能把类名修改成其他,如FirstEntity2就会在客户端SDK启动时报错提示。


4. 实现scene_world空间场景

4.1 场景制作

场景列表视图如下:

1

其中:

helloworld:是使用UGUI制作的一个简单的发送hello world的界面,附上脚本HelloWorld.cs,且hello world按钮绑定了HelloWorld的OnClick事件。 1

UI效果图如下:

1


4.2 实现HelloWorld

直接上代码块:

/// <summary>
/// 进入空间后,HelloWorld交互界面的绘制
/// </summary>
public class HelloWorld : MonoBehaviour
{
    /// <summary>
    /// 响应Helloworld按钮,该按钮在Unity的UGUI系统中被绑定到按钮事件上。
    /// </summary>
    public void OnClick()
    {
        //通过API:player()获得账户自己的实体,在本例中账户自己的实体就是FirstEntity
        FirstEntity entity = KBEngineApp.getSingleton().player() as FirstEntity;
        //由于say方法是在cell上的远程方法,这边使用cellEntityCall属性来调用。
        //如果是一个base上的远程方法,则使用baseEntityCall进行调用
        entity.cellEntityCall.say("hello world");
    }
}

这里主要调用了API中的player()方法获取到客户端自身的账户实体,并转成了FirstEntity类型。同时调用了该实体上的cell的say方法来调用服务器端的对应远程方法,完成向服务器的请求。

对!刚才的onEnteronSay,包括这里的cellEntityCall.say,与服务端一一对应的这一切事情,都是由SDK生成器帮你完成的!

接下来,让我们迎来激动人心的时刻!服务器和客户端的联通验证!


第三步:验证

1. 启动引擎

在本项目的资产库“getstarted_assets”下,找到start_server.bat,并双击运行。

等待所有服务器组件的窗口都出现“Found all the components!”字样,就说明成功启动了。


2. 运行客户端

2.1 确保两个场景都在Build Settings中

1

2.2 打开scene_login场景

2.3 点击Play,启动客户端。

1


3. Hello world

1、启动后,出现登录窗口,随意输入账号和密码(长度都要大于4位),点击Login按钮,就会向服务器发出登录请求。

Tips:本教程中,服务端没有对账户验证做处理,所以任意的账号密码都可以登录成功。
整个过程细节,可以查看客户端中Console窗口的日志。

2、一旦登录成功,会跳转至scene_world场景,里面只有一个UI,即HelloWorld

3、点击hello world按钮,会向服务端发起say的远程调用。

4、收到onSay的通知后,会在UI显示出文字。

Tips:

上图中的“2”是代表实体的id,在服务器的FirstEntity的cell部分实现代码中,onSay输出的content格式:“Entity: ” + self.id + content

恭喜你,Unity3D的客户端实现已完成!

通过Unity3D客户端的实现,我们利用FirstEntity实体的Client部分与服务器建立了连接,并立即进入了FirstSpace所在的空间中,接着,在空间内我们向第一个实体FirstEntity进行了say的操作,并收到了onSay的广播。

这是GetStated章节中客户端Unity3D的源代码:点我下载(里面包含了对应的服务端源代码)

开发者肯定对整个的通讯过程、业务流程还存在一些疑问,让我们进入下一节《GetStated总结》中进行回顾、梳理和总结吧。

点我进入《GetStated总结》。


Copyright © 2018 Yolo Technologies. Publication: 2.0-025. Built: 2018-12-07.