热更新实现方式:
1、使用Lua脚本编写游戏的UI或者其他逻辑,Lua是一个精悍小巧的脚本语言,可以跨平台运行解析,而且不需要编译过程。
2、使用C#Light
3、使用C#反射技术
关于AssetBundle
Unity提供了一个资源更新技术,就是通过AssetBundle,我们可以通过AssetBundle更新游戏UI,也可以把脚本或者其他代码当成资源打包成AssetBundle然后更新到客户端。
在所有的热更新技术中都需要AssetBundle.
Lua热更新原理
在移动端可以编写Lua的解析器,通过这个解析器,可以运行最新的Lua脚本,然后我们把控制游戏逻辑的代码都写成Lua脚本。
Lua工具
1、Lua官网 Lua.org
2、Luaforwindows
http://luaforge.net/projects/luaforwindows/
http://luaforwindows.luaforge.net/(可安装的exe文件,一整套的lua开发环境,有lua的解析器,参考手册,范例和库,文档和编辑器)
3、安装Luaforwindows,关于Luaforwindows的目录介绍
Lua编程
从Hello World开始:print("Hello World!")
注:1.print()是lua内置的方法
2.在lua中字符串用“”或者‘’都可以表示
3.lua中每条语句后面是没有;结尾的
定义变量
num = 100
这里定义了一个全局变量叫做num,赋值为100
在lua中定义变量是没有类型的,根据存储什么数据,来决定是什么类型
变量的命名不能以数字开头
变量避免下划线加大字母开头,这种格式Lua自身保留
推荐使用C#中的命名规范和驼峰命名
注释
1、单行注释 --
2、多行注释 --【【 这里是注释内容 】】--
变量类型
1、nil表示空数据,等同于null
2、boolean 布尔类型,存储true和false
3、string 字符串类型,字符串可以双引号也可以使用单引号表示
4、number小数类型(lua中没有整数类型)
5、table表类型
myTable={34,34,2,342,8}
myTable[3]
所有从1开始
我们可以使用type()来取得一变量的类型
局部变量和全局变量
默认定义的变量都是全局变量,定义局部变量需要在前面加一个local;
在代码块中声明的局部变量,当代码块运行结束的时候,这个变量就会被释放。
eg: temp = 34
local var = 555
运算符
1、算数运算符 + - * 、 %(lua中没有++ --)
2、关系运算符 <= < > >= ==
3、逻辑运算符 and or not 分别表示 与 或 非 (类似于C#中的&& || !)
流程控制
if语句
注:if后面必then
1、if [condition] then
end
2、if [ condition] then
else
end
3、 if [condition] then
elseif [condition] then
else
end
循环结构while循环
1、while语法结构
while [condition] do
end
repeat 循环
1、语法结构 (相当于 do - while())
repeat
[code to execute]
until[condition]
for循环结构
for index=[start],[end] do
[code to execute]
end
注:break可以终止循环 没有continue语法
函数
定义函数
function [function name](param1,param2)
[function code]
end

标准库(标准函数)
lua内置提供了一些常用的函数帮助我们开发
1、数学处理的math相关函数

2、字符串处理的string相关函数

3、表处理的table相关函数
在lua中的table类似C#中的字典,其实就是一个key-value键值对的数据结构。
第一种创建方式
1.table的创建
myTable = {}
表名后面使用{}赋值,表示一个空的表
2.table的赋值
myTable[3] = 34 当键是一个数字的时候的赋值方式
myTable["name"] = "taikr" 当键是一个字符串的赋值方式
myTable.name = "jianguang" 当键是一个字符串的赋值方式
3.table的访问
myTable[3] 当键是数字的时候,值有这一种访问方式
myTble.name 当键是字符串的时候有两种访问方式
myTable["name"]
第二种创建方式
myTable = {name="dalian",age = 18,isMan = false}
(创建表之后依然不可以添加数据)
数据访问
myTable.name
myTable["name"]
第三种创建方式
myTable = (31,55,68)
当没有键的时候,编译器会默认给每一值,添加一数字键,该键从1开始




4、文件操作的io相关函数
通过表来实现面向对象
myTable = {} 申明对象
local this = myTable 申明this关键字代表当前对象
--定义并声明对象中的属性
myTable,name = "jianguang"
myTable.age = 110
--定义并声明对象中的方法
myTable.function = function()
[code to execute]
end
function myTable.function()
[code to execute]
end

LuaInterface
LuaInterface 包括两个核心库 一个是LuaInterface.dll,一个是Luanet.dll,我们可以通过LuaInterface完成Lua和C#(CLR)之间的互相调用。
eg:创建LuaInterface项目,把 luainterface.dll 和luanet.dll添加到项目中

添加引用

代码:(引用命名空间)

运行结果:

在C#中执行访问Lua代码
Lua lua = new Lua(); //创建Lua解析器
lua["num"] = 5; //定义一个 num
lua["str"] = "a string"; //定义一个字符串
lua.newTable("tab"); //创建一个表 tab={}
取得Lua环境中的变量
double num = (double)lua["num"];
string str = (string)lua["str"];
在C#脚本中执行Lua脚本文件,或者脚本字符串
lua.DoFile("script.lua");//执行script.lua脚本
lua.DoString("num = 2");//执行lua代码
lua.DoString("str = 'a string'");
object[] retVals = lua.DoString("return num,str");
在热更新中,只需要写好解析Lua脚本的代码,然后C#代码不需要变动,只需要修改lua脚本就好,通过lua脚本控制游戏逻辑


Lua 和 C#中类型的对应
nil null
String system.String
number System.Double
boolean System.Boolean
table Lualnterface.LuaTable
function LuaInterface.LuaTable
把一个C#方法注册进Lua的一个全局方法
//把一个类中的普通方法注册进去
Lua.RegisterFunction("NormalMethod",obj,obj.GetType().GetMethod("NormalMethod"))
lua.DoString("NormalMethod()")

//把一个类的静态方法注册进去
lua.RegisterFunction("StaticMethod",null,typeof(ClassName).GetMethod("StaticMethod"))
lua.DoString("StaticMethod()")

在Lua中使用C#脚本
require "luanet"
--加载CLR的类型、实例化CLR对象
luanet.load_assembly("System.Windows.Forms")
luanet.load_assembly("System.Drawing")
Form = luanet.import_type("System.Windows.Forms.Form")
StartPosition = luanet.import_type("System.Windows.Forms.FormStartPosition")
print(Form)
print(StartPosition)
在Lua中使用C#中的类创建对象的时候,会自动匹配最合适的构造方法。


在Lua中访问C#中的属性和方法
Lua代码中,访问C#对象的属性的方法和访问table的键索引一样,比如obj.name 或者 obj["name"]
Lua代码中,访问C#对象的普通函数的方式和调用table的函数一样,如:obj:method()


注:在Lua中访问C#中的方法 - 特殊情况
当函数中有out或者ref参数时,out参数和ref参数和函数的返回值一起返回,并且调用的时候,out参数不需要传参


注:Lua中的调用和返回值 out参数不需要参数,这个返回一个table. ref参数需要传入参 数,返回一个table.
AssetBundle
参考我的文章 Unity之AssetBundle
uLua simpleframework
把框架导入项目中
我们首先需要做,点击菜单栏Lua - Welcome Screen 取消开始时候显示对话框,然后 Clear LuaBinder File + Wrap Files.然后点Gen Lua Wrap Files生成包装文件,把C#里的一些类包装成Lua里的Table,包装类会把自身注册到Lua的环境里。(先Clear 后 生成)
菜单栏Game 是用来Buile AssetBundle的。Buile 相应的平台,Project下会生成StreamingAssets文件夹,所有动态更新的资源都会打包到这个文件夹下。
生成游戏物体


在C#中访问Lua中的变量
方法一


方法二:


执行Lua脚本文件,调用Lua方法,在Lua中使用协程
调用Lua脚本,方法一

调用Lua脚本方法二

调用Lua方法
方法一:


方法二:


在Lua中使用协程



框架使用
框架采用了Pure MVC的架构,GlobalGenerator整个项目的启动器。

然后进入StartUp()方法(管理类)

注册的时候会调用StartUpCommand,F12点进去了解一下
我们来看一下GameManager中对资源的更新处理








然后我们来看一下Lua的代码结构:
View:视图的一些代码
System:和Unity对应的一些类
Logic:对应的逻辑类
Controller:控制UI的类
Common:共有的类
3rd:一些开源项目案例
热更新案列
首先我们来做一个界面

然后我们进行打包,我们把BottomPanel和SettingPanel拉成预设体,并设置bundle属性,bottom.assetbundle 和 setting.assetbundle
注:框架属性命名格式定我 名字.assetbundle

因为引用 : 所以我们把图片打成一个包字体打成一个包(一般情况下我们会把同一个界面的图片打成一个包,具体按公司要求来)
sprite.assetbundle 和 font.assetbundle
然后我们打成win下的bundle
然后我们新建一个空物体并命名为GlobalGenerator,并挂上脚本GlobalGenerator

GloabalGenerator脚本的代码我们不需要修改,作用:创建GameManage,然后进行初始化
GameManage的代码我们需要修改一下,把LuaManage.DoFile("Logic/GameManager")中的GameManger改成我们调用的Lua脚本名称,在这里我们就不改了,把原来的GameManager改成GameManager_back,自己再创建一个Lua脚本GameManager

新lua的GameManager代码如下

然后我们需要做的就是写View视图下的BottomPanel脚本

然后我们回到Unity编辑器给Bg添加动画

选择Window ->Animation -> Create - >命名为SettingsPanel(由做一个小变大的动画),调节Scale属性

刚开始的时候设为 0 0 0 如下

60帧的时候变为 1 1 1

这是我创建面板由小变大的一个动画,下面我们来场景面板隐藏的动画 点击右上角 SettingsPanel - 》create new clip... 创建一个新的动画 SettiongsPanelHide
创建步骤何第一个动画一样,0帧的时候大小为1 1 1 60帧的时候大小为 0 0 0
然后我们来设置一下状态机

我们在SettingPanel面板设置一个关闭按钮,而SettingPanel默认是不显示的,然后把SettingPanel面板的Bg的Scale设为0 0 0

然后我们来写Lua View视图中SettingsPanel.lua

视图层写好,我们来写控制层Controller 下 BottomCtl 和 SettingsCtrl 来对相应视图控制




然后我们的代码热更新就做好了
网友评论