-
Notifications
You must be signed in to change notification settings - Fork 3
Get Started
本手册旨在让大家快速上手本框架,更多的作为范例供大家查阅,若有不足或者遗漏,请随时指出。
- 适用人群:本手册适用于对编辑器、Lua以及面向对象有一定了解,想快速上手框架的同学。
- 适用框架版本:v 3.x.
World
世界根节点
Global
全局作用域,客户端和服务器都会执行
LuaFunctionScript
Lua常用函数库ModuleRequireScript
Ava框架模块脚本载入脚本,用于自定义模块载入Utility
工具模块目录,客户端服务器可通用Framework
Ava框架目录,用于启动游戏主循环,与游戏业务无关Plugin
插件模块目录,用于存放独立的自定义插件Define
定义模块目录,用于存储数据Module
游戏逻辑模块目录,游戏启动后,服务器/客户端会分别载入对应的模块目录
详细框架结构参考Hierarchy
- 游戏逻辑层:
Define
,S_Module
,C_Module
- 框架层:
Framework
- 基础层:
LuaFunctionScript
,ModuleRequireScript
,Utility
引用关系:自上而下引用,禁止反向引用。
- 逻辑层可以引用框架层和基础层的模块脚本
- 框架层可以引用基础层,但是不允许引用游戏逻辑层的
- 基础层不引用任何其他模块
(Plugin
插件内容独立于框架,稍后会更新)
- 运行
LuaFunctionScript
,在_G
下扩展Lua标准库 - 运行
ModuleRequireScript
,载入Global
下的所有脚本,载入顺序自上而下- 客户端/服务器在各自的Lua虚拟机中载入基础层、框架层、游戏逻辑层代码
- 启动框架
- 服务器:运行
World.S_Code.ServerMainScript
,会执行ServerModule
中的Run
函数 - 客户端:运行
Player.C_Code.ClientMainScript
,会执行ClientModule
中的Run
函数
- 服务器:运行
- 框架层运行:在
ServerModule
和ClientModule
中启动服务器/客户端框架- 初始化全局随机种子,用于Lua的
math.random()
函数 - 初始化心跳
- 根据
EventsModule
中定义的事件,生成对应的CustomEvent
节点 - 预加载所有的CSV表格,转换为Lua Table,加载的CSV在
ConfigModule
里定义 - 启动心跳
- 初始化游戏逻辑层模块:顺序执行运行游戏逻辑层模块的
InitDefault()
、Awake()
、Start()
函数 - 启动
更新
函数:顺序执行运行游戏逻辑层每个模块中的Update()
、LateUpdate()
、FixedUpdate()
更新函数
- 初始化全局随机种子,用于Lua的
框架相对于原本编辑器新增了一些脚本,本部分将讲解这些脚本的作用
打开World->Global下的LuaFunctionScript
,可以看到非常多的函数定义,这些是对Lua标准库的扩展,具体的用法可以查看注释上的使用说明
框架的模块引用脚本,所有模块都在这里引用,按照正确的框架目录进行模块的存放,即可不需要在这里手动进行模块的引用。
服务器代码的入口,原则上不必更改ServerMain中的内容
--- 服务器代码入口
-- @script Server Main Function
-- @copyright Lilith Games, Avatar Team
-- @author Yuancheng Zhang
Server:Run()
客户端代码的入口,不用更改里面的内容
--- 客户端代码入口
-- @script Client Main Function
-- @copyright Lilith Games, Avatar Team
Client:Run()
框架中所有的模块都存放在World->Global->Module下,打开编辑器中的目录可以看到S_Module和C_Module两个文件夹,分别存放服务器模块和客户端模块。此部分主要介绍框架中自带的模块,以及如何着手编写模块。
框架的World->Define目录下自带了四个模块,在模块下可以进行一些全局的定义。
全局变量在GlobalDef下定义
全局常量在ConstDef下定义
用于载入Xls文件夹的模块
CustomEvent的定义模块,用于事件动态生成
本部分具体讲解如何自己编写一个服务器模块。
在World->Module->S_Module中新建一个ModuleScript
,命名为PrintAModule
,代码如下:
---这是一个只会打印A的模块
-- @module PrintAModule
local PrintA, this = ModuleUtil.New('PrintA', ServerBase)
--- 初始化
function PrintA:Init()
print('[信息]PrintAModule:初始化数据')
end
--- Update函数
-- @param dt delta time 每帧时间
function PrintA:Update(dt)
print('我是一个每帧都会打印的A')
end
return PrintA
运行编辑器会在Output中得到以下结果:
[06:02:33.351][信息]PrintAModule:初始化数据
[06:02:33.495]我是一个每帧都会打印的A
[06:02:33.543]我是一个每帧都会打印的A
[06:02:33.577]我是一个每帧都会打印的A
[06:02:33.611]我是一个每帧都会打印的A
[06:02:33.645]我是一个每帧都会打印的A
[06:02:33.679]我是一个每帧都会打印的A
[06:02:33.712]我是一个每帧都会打印的A
[06:02:33.746]我是一个每帧都会打印的A
[06:02:33.780]我是一个每帧都会打印的A
[06:02:33.814]我是一个每帧都会打印的A
[06:02:33.848]我是一个每帧都会打印的A
至此,我们就在框架中添加了一个会每帧输出字母'A'的模块。
首先在Archetype->Player->Local->ControlGui下新建一个Button
,命名为PrintBtn
,然后在World->Module->C_Module中新建一个ModuleScript
,命名为ButtonPrintModule
,代码如下:
---这是一个玩家点击对应按钮就会输出的模块
-- @module ButtonPrintModule
local ButtonPrint, this = ModuleUtil.New('ButtonPrint', ClientBase)
--- 初始化
function ButtonPrint:Init()
print('[信息]ButtonPrintModule:初始化')
--绑定按钮事件
localPlayer.Local.ControlGui.PrintBtn.OnClick:Connect(PrintButton)
end
function PrintButton()
print('[客户端]你点击了按钮')
end
return ButtonPrint
在这里要注意,应该将客户端模块放在指定的地方
然后运行编辑器,可以看到Output中有以下输出:
[2020-04-27 00:26:41.935] [信息]ButtonPrintModule:初始化
点击界面中的按钮,Output中会增加一行输出:
[2020-04-27 00:26:48.410] [客户端]你点击了按钮
至此,我们就编写了一个简单的客户端模块.
框架中提供了NetUtilModule
模块来进行双端通信
这一部分主要讲解如何进行事件绑定、事件监听以及NetUtil模块。
打开World->Global->Utility下的NetUtilModule
,其中内置了以下三种函数:
NetUtil.Fire_C(_eventName, _player, ...args)
NetUtil.Fire_S(_eventName, ...args)
NetUtil.Broadcast(_eventName, ...args)
其中Fire_C
是向客户端通信,Fire_S
是向服务端通信,Broadcast
是向客户端广播。
例如:
NetUtil.Fire_C('PlayerRebornEvent',_player,1)
会触发客户端下名为PlayerRebornEvent
的事件,传输的参数为1
。
CustomEvent
节点在框架中可以通过更改World->Global->Define下的EventsModule
模块来添加或删除,你在该模块中所列举的事件都会在框架运行时被创建。
对于CustomEvent
的绑定,我们会使用事件名+'Handler'进行绑定,但在绑定之前,应该先在EventsModule
中先枚举你需要的事件名。
在编写一个客户端模块的基础上,在World->S_Event下新建一个Custom Event
,命名为BtnPrintEvent
然后在S_Module下新建一个ModuleScript
,命名为BtnModule
,代码如下:
---这是接收玩家点击按钮信息的模块
-- @module BtnModule
local Btn, this = ModuleUtil.New('Btn', ServerBase)
--- 初始化
function Btn:Init()
print('[信息]BtnModule:初始化')
end
function Btn:BtnPrintEventHandler()
print('[服务器]BtnModule知道了你点击了按钮')
end
return Btn
在C_Module下ButtonPrintModule
的PrintButton函数中加入以下代码:
NetUtil.Fire_S('BtnPrintEvent')
运行编辑器并点击按钮后会得到以下输出:
[2020-04-27 01:10:08.253] [客户端]你点击了按钮
[2020-04-27 01:10:08.255] [信息] 服务器事件: BtnPrintEvent
[2020-04-27 01:10:08.270] [服务器]BtnModule知道了你点击了按钮
对于编辑器内置的事件(可以查看API文档),我们仍然需要使用Connect方法绑定事件,如:
--- 初始化
function ButtonPrint:Init()
print('[信息]ButtonPrintModule:初始化')
--绑定按钮事件
localPlayer.Local.ControlGui.BtnPrint.OnClick:Connect(PrintButton)
end
中的按钮绑定事件:
localPlayer.Local.ControlGui.BtnPrint.OnClick:Connect(PrintButton)
这个代码可以在C_Module下的ButtonPrintModule
中找到
至此,我们就进行了一次服务器端模块的绑定
原则上,在框架中最好不要通过跨模块引用进行其他模块方法的调用,这样会增加耦合度。
推荐的方法是使用事件通信来调用。
本框架鼓励同学们自己开发插件,在World->Global->Plugin下自带了UI动效编辑的插件
若想快速查阅框架中自带的一些方法,可以查阅参考手册
Davinci - API Reference - Forum - ©copyright Lilith Games, Avatar Team