写在前面
Hello,小伙伴们中秋节快乐呀。我又给大家带来最新一期的开发日志了。这一期我们要搞定的是UE4和KBEngine之间的,前后端通信。并且我们尝试理清楚登录过程中的逻辑。为下一步的开发做好准备工作。废话不多说我们开始吧!
这篇文章的视频版在这里:
====
视频地址
====
交流QQ群:872537977
项目地址github:
https://github.com/Liweimin0512/uRPG
准备工作
上一期的开发日志中,我们已经顺利地启动了服务器。
这一期最开始我们要做的就是新建一个客户端项目,这次我们直接安装第三人称C++项目。并且将这个项目存在了这里:
然后我们要搞定KBEngine的客户端插件,我们可以参考官方的UE4Demo,项目地址:
https://github.com/kbengine/kbengine_ue4_demo
将其中的插件拷贝到我们的客户端项目下,或者直接下载官方的插件项目也是一样的:
https://github.com/kbengine/kbengine_ue4_plugins
安装插件
关于UE4插件的安装这里我多介绍两句,虽然是很简单的知识:
首先就是要在这里新建一个必须命名为Plugins的文件夹,并将相关的插件放入这个文件夹。在之后,要在UE4项目专门管理项目结构的CS文件中添加相应的配置。
这个文件的名称是*.Build.cs,如上图所示,在 PublicDependencyModuleNames中添加你的插件即可。
这里我们需要用到KBEngine的客户端SDK自动生成工具。如下图所示:
箭头位置就是客户端SDK生成工具的批处理文件,运行之后会同时生成UE4和Unity两款引擎的插件。将UE4的复制到我们上文中提到的地址。
然后我们尝试编译运行项目,OK,没什么问题。那么这一步可以先告一段落了。
登录流程
这里我花了一些时间搞清楚KBEngine的登录逻辑究竟是怎样的。这方面主要是通过看官方文档以及源代码来研究的。其实也不是很难。但是理解清楚还是要花些时间。我这里将思路整理出来给大家分享下,希望能给大家节省点时间。
官方说引擎和客户端的通信,绝大多数是依赖于Entity的。而在登录这个环境就是绝大多数之外的。因为在登录时我们还没有建立客户端代理类。所以这个过程更像是web应用的收发模式。简单说就是客户端发起请求,服务器接收到请求并处理后将结果通过回调函数的方式返回给客户端。客户端依靠返回的消息在界面上做出相应的展示即可。
只不过这过程中涉及到一层服务器引擎为我们生成的客户端SDK,让事情变得简单多了。我们只需要处理好客户端和SDK之间的事件即可。而不是直接与服务器进行交互。举个例子,我们把Login请求发送给SDK,SDK进行一系列底层运算之后,发送给服务器。
而服务器又是怎么做的呢?它通过LoginApp、LoginAppScript和dbmgr层层回调,在每一层回调中我们都可以进行相应的操作。当Login操作成功后,引擎才会通知BaseAppMgr,它会为我们分配一个BaseApp。之后的事情就是我们和这个App之间的通信了。而这种通信依赖于一个名为Account的特殊Entity。官方称之为用户入口实体。
此外,查看官方Demo和官方文档发现我们需要创建一个Actor并且添加一个KBEMain的组件。命名随意,官方命名为ClientApp我决定挺准确的就跟着这么命名吧。KBEMain这个组件就是我们前后端通信的桥梁了。我们需要格外注意。
客户端目录结构
首先我们在content 根目录下新建一个文件夹,命名为MMORPG
。我们给它标记一个黄色。这样更显眼一些。
我们点进来,创建三个文件夹。分别命名为Levels(关卡)、Buleprints(蓝图)和Widgets(界面)。如下图所示:
登录场景和登录界面
在魔兽世界中,我们玩家从打开游戏到进入游戏世界经历的过程:
登录界面 -> 角色选择界面 -> 游戏主场景
所以这一期我们先来完成登录界面的制作。首先新建一个关卡命名为Map_Login。然后新建一个Widget,命名为UMG_LoginMain。配套的也新建一个GameMode蓝图Bp_LoginGameMode。
这里补充说明一下,这里的GameMode需要继承自C++的GameMode。我这里命名为RPGLoginGameMode。参考官方Demo的写法。考虑到我们这个游戏至少会有三个GameMode,分别是Login,Select和Main(对应3个场景)。所以我们在这三个GameMode上再抽象出一个RPGGameModeBase的类。并将一些通用的方法放在这个类中。
然后我们的蓝图Bp_LoginGameMode再继承自这个RPGLoginGameMode即可:
之后我们将Login的关卡GameMode设置为这个GameMode即可:
再说回我们的UMG_LoginMain ,这里我们先用几个简单的控件实现效果:
这个界面十分简单,这里就不多提了,简单说就是两个文本输入框和两个按钮而已。重点的是按钮交互响应的部分。
当BT_login被点击时,我们直接调用ClientApp中KBMain组建的Login方法,并将UserName和Password传给它。就算是搞定了。此外这里还允许我们将一些自定义数据传给后端,没传会报错。所以这里我们对应新建一个变量。在事件开始时候清空变量即可。这样就确保这个数据是我们事件内部的数据(没有为空)了。
这里补充一下ClientApp这个变量,我们在Construct事件中通过查找Class的方式找到所有ClientApp的实例,因为我们知道这个Actor理论上应该是单例。所以我们直接取第一个,然后将其存为变量,持有。方便之后调用。
登录界面是我们登录关卡的主界面,因此我们在Bp_LoginGameMode中将它直接创建出来,并且为了方便点击我们还要将鼠标显示出来,方法很简单,相信看过我之前的开发日志的小伙伴都应该清楚怎么操作了:
登录响应
当我们调用了Login方法,经过一连串的事件通信,最后会传给后端。后端再经过一连串处理后,会给与我们响应。这个相应通过SDK的包装,依然是以事件的形式传递给我们前端的。还记得我们前文中创建的RPGGameModeBase和LoginGameModeBase这两个C++类么?这里我们着重研究下这两个类。
这两个类,我们临摹KBEngine的官方Demo。来看看有哪些发现,首先看RPGGameModeBase.h这个头文件,可以看到最主要的是installEvents这个方法,官方注释是“安装登录时需要坚挺的KBE事件”,之后便是一些事件的声明:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "Scripts/LogicEvents.h"
#include "GameFramework/GameModeBase.h"
#include "RPGGameModeBase.generated.h"
/**
*
*/
UCLASS() class CLIENT_API ARPGGameModeBase : public AGameModeBase {
GENERATED_UCLASS_BODY()
public: //一些集成的方法这里不多提
// ...
/*
安装登陆时需要监听的KBE事件
*/
virtual void installEvents();
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = KBEngine)
bool startRelogin;
UFUNCTION(BlueprintCallable, Category = KBEngine)
void fire(const FString& eventName, UKBEventData* pEventData);
/* KBE事件
玩家被踢出服务器
*/
UFUNCTION(BlueprintNativeEvent, BlueprintCallable, Category = "KBEngine")
void onKicked(const UKBEventData* pEventData);
/* KBE事件
*/
//后面是一些事件的声明,这里暂且不表
};
那我们看看installEvents是如何实现的:
void ARPGGameModeBase::installEvents() {
// common
KBENGINE_REGISTER_EVENT(KBEngine::KBEventTypes::onKicked, onKicked);
KBENGINE_REGISTER_EVENT(KBEngine::KBEventTypes::onDisconnected, onDisconnected);
KBENGINE_REGISTER_EVENT(KBEngine::KBEventTypes::onConnectionState, onConnectionState);
KBENGINE_REGISTER_EVENT(KBEngine::KBEventTypes::onReloginBaseappSuccessfully,onReloginBaseappSuccessfully);
KBENGINE_REGISTER_EVENT(KBEngine::KBEventTypes::onReloginBaseappFailed,onReloginBaseappFailed);
}
这些具体事件我们暂时不了解含义,没关系。我们现在至少清楚KBEngine引擎是通过在installEvents这个方法中使用KBENGINE_REGISTER_EVENT注册事件的。这也是官方所说的我们客户端和客户端SDK之间事件通信的起点。在我们注册之后,SDK接收到来自服务器的消息后就可以通过事件的形式回调我们对应的客户端方法。然后我们就可以在回调函数中进行我们需要的操作了。
不过这里只有一些通用的事件,我们还是要看更具体的LoginGameModeBase中是什么样的,来一起看看其中注册了哪些事件吧:
void ALoginGameModeBase::installEvents() {
Super::installEvents(); // login
KBENGINE_REGISTER_EVENT(KBEngine::KBEventTypes::onCreateAccountResult,onCreateAccountRes
ult);
KBENGINE_REGISTER_EVENT(KBEngine::KBEventTypes::onLoginFailed,onLoginFailed);
KBENGINE_REGISTER_EVENT(KBEngine::KBEventTypes::onVersionNotMatch,onVersionNotMatch);
KBENGINE_REGISTER_EVENT(KBEngine::KBEventTypes::onScriptVersionNotMatch,onScriptVersionNotMatch);
KBENGINE_REGISTER_EVENT(KBEngine::KBEventTypes::onLoginBaseappFailed,onLoginBaseappFailed);
KBENGINE_REGISTER_EVENT(KBEngine::KBEventTypes::onLoginBaseapp, onLoginBaseapp);
KBENGINE_REGISTER_EVENT("onLoginSuccessfully", onLoginSuccessfully);
KBENGINE_REGISTER_EVENT("Loginapp_importClientMessages", Loginapp_importClientMessages);
KBENGINE_REGISTER_EVENT("Baseapp_importClientMessages", Baseapp_importClientMessages);
KBENGINE_REGISTER_EVENT("Baseapp_importClientEntityDef", Baseapp_importClientEntityDef);
}
果然,这里有我们最需要的登录成功和登陆失败事件。由于我们的Bp_LoginGameMode蓝图继承自LoginGameModeBase,所以这里可以找到相关事件:
成功和失败事件都很简单,成功时我们直接跳转到Map_SelectAvatar即可。失败的话我们就将报错信息打印出来即可。如下图所示:
验证
看起来似乎一切都准备好了,我们来启动服务器和客户端验证一下。
提前说明一下,如果我们客户端成功登录,按照流程是会跳转到选择角色关卡的。这里要将Map_SelectAvatar准备好。并且最好将其他情况的回调事件中也都PrintString中打印出来。这样方便我们调试。我这里图块,为了让咱们这期的开发日志看起来简单些。这里就没做多余的操作。
运行前后端,随便输入账户名和密码(服务端和客户端都没有做验证),点击登录按钮,顺利的跳转到Map_SelectAvatar关卡了!很好,我们这一期的开发日志算是完美的完成了!