Lua------------------unity与lua的热更新






版权声明:本文采用国际知识共享“署名-非商业使用-禁止演绎”协议4.0进行授权许可。转载请注明作者姓名和文章出处。
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
喜欢我的博客请记住我的名字:秦元培,我的博客地址是blog.csdn.net/qinyuanpei。
转载请注明出处,本文作者:秦元培, 本文出处:http://blog.csdn.net/qinyuanpei/article/details/40213439
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
大家好,我是秦元培,欢迎大家关注我的博客,我的博客地址是blog.csdn.net/qinyuanpei。在之前的三篇系列文章《Unity3D游戏开发之Lua与游戏的不解之缘》中,博主带领大家一起领略了Lua在游戏开发中强大而迷人的作用,通过UniLua这个开源项目我们将Lua引入了Unity3D的世界,并且在此基础上我们写出了Lua'与Unity3D交互的第一个示例程序。今天呢,我们来说说Unity3D配合AssetBundle和;Lua实现热更新。
首先,我们来了解一下什么是热更新吧!所谓热更新是指在不停机的状态下对系统进行更改,例如我们的Windows可以在不重启的状态下完成补丁的更新、Web服务器在 不重启的前提下完成对数据和文件的替换等都是热更新的经典实例。那么对于Unity3D而言,什么是热更新呢?如果我们最终发布的Unity3D游戏是一个Web游戏,那么每次游戏加载的过程中实现对资源代码的更新就是热更新。如果我们最终发布的Unity3D游戏是一个客户端游戏,那么我们在重重启客户端以后实现对资源代码的更新就是热更新。为什么这么说呢?因为Web游戏需要保证玩家能够及时快速地进入游戏,因此在游戏加载完之前,我们必须完成对游戏资源和代码的更新。可是对于客户端游戏而言,玩家可以在等待本次更新结束后再进入游戏,而且大部分的客户端程序在更新完后都会要求玩家重启客户端,所以对于客户端游戏而言,热更新并非是严格意义上的热更新。那么,我们为什么要进行热更新呢?答案是为了缩短用户获取新版本客户端的流程、改进用户体验。这其实就是博主在前文中提到的传统单机游戏依靠光盘载体进行发售所面临的问题,玩家为了获取最新版本的游戏,需要下载全新的客户端并将它安装到计算机或者手机设备上。在互联网产品开发中有一种称为快速迭代的理念,试想如果我们每次对客户端进行局部的调整,就需要玩家去下载新版本的客户端,试问这样的用户体验真得能让用户满意吗?所以现在为了方便用户、留住用户、进而从留住的用户身上赚到钱,我们总能在游戏产品中找到热更新的影子。我们知道在Unity3D中可以通过AssetBundle来实现对游戏中资源的更新,在http://blog.csdn.net/janeky/article/details/17666409这篇文章中作者janeky已经给出了较为完美地解决方案,因为博主使用的Unity3D免费版无法使用AssetBundle的功能,而博主本人不愿意使用破解版,因为这是一个程序员的良心,所以本文更多的是从代码更新的这个角度来讲Unity3D的热更新,对于资源的热更新大家建议大家还是去看janeky的这篇文章吧。好了,下面正式开始Unity3D代码级的热更新之旅!
在Unity官方的API中官方给出了一种基于反射的思路,即将C#脚本存储为文本文件,然后将其转化为byte字节,再通过反射技术取得该类型及其方法。理论上这样当然没有问题,可是我们知道由于IOS是一个封闭的系统,设计者出于安全的考虑不允许在该平台下使用反射技术。那么问题来了,反射并不是一个完美地解决方案。关于反射技术实现Unity3D的热更新,大家可以参考这篇文章:http://blog.csdn.net/janeky/article/details/25923151。好了,下面我们来说说博主是如何通过Lua实现Unity3D的热更新的吧。我们知道在Lua提供的C#接口中有一个DoString()的方法,该方法可以直接利用Lua虚拟机执行字符串中的脚本。所以,我们可以通过在本地读取Lua脚本来执行脚本中的命令,如果我们脚本中的命令可以直接对Unity3D进行操作,那么我们就可以通过Lua脚本来更新游戏中的代码逻辑。那么,我们怎么能让Lua脚本操作Unity3D呢?在前一篇文章中,我们介绍了一种Require的方法,该方法可以将C#库引入到Lua脚本中并通过Lua来执行C#库中的方法。顺着这样的思路,博主便有了下面的设想:
在这个设想中,我们首先需要将Unity API封装成一个C#类库,在这个类库中我们将会涉及动态加载场景和动态创建场景,因为我们更新游戏的逻辑的时候将会用到这些方法。这些方法通过封装后我们便可以在Lua脚本通过Require方式来引用,进而我们就可以通过Lua脚本来动态地进行设计。我们设计一个固定的位置来存储Lua脚本更新文件,这样我们只需要对比本地版本和服务器版本是否相同就可以知道我们是否需要更新。这里我们通过WWW来从远程服务器上下载最新的Lua脚本更新文件,下载下来的Lua脚本处于项目外部,我们无法使用Resource.Load()这样的方法来加载,可是我们可以通过WWW来加载一个本地文件,这样我们就实现了Lua脚本文件的更新。当然,我们可以使用AssetBundle来更新Lua脚本文件,可是博主的免费版不支持AssetBundle,所以博主想出了这样一个曲线救国的方法。当Lua脚本文件更新后,我们就可以在游戏主逻辑里通过DoString()方法来执行脚本文件中的代码。在游戏主逻辑里主要的任务是比较当前版本号和服务器版本号来判断是否需要更新,如果需要更新就下载Lua脚本更新文件然后执行脚本中的代码,这样我们就实现了客户端程序的更新。好了,下面我们继续以前一篇文章中的项目为例来将博主的这个设想变成现实。
首先,我们在CSharpLib.cs这个类中增加下面两个方法并完成方法的注册:
- /// <summary>
- /// 设置场景中物体的坐标
- /// </summary>
- /// <returns>返回当前坐标</returns>
- /// <param name="lua">Lua.</param>
- public static int SetPosition(ILuaState lua)
- {
- //物体的名称
- string mName=lua.L_CheckString(1);
- //传入参数x,y,z
- float mX=(float)lua.L_CheckNumber(2);
- float mY=(float)lua.L_CheckNumber(3);
- float mZ=(float)lua.L_CheckNumber(4);
- //获取物体
- GameObject go=GameObject.Find(mName);
- //获取Transform
- Transform mTrans=go.transform;
- //设置游戏体的位置
- mTrans.position=new Vector3(mX,mY,mZ);
- //返回游戏体当前坐标
- lua.PushNumber(mTrans.position.x);
- lua.PushNumber(mTrans.position.y);
- lua.PushNumber(mTrans.position.z);
- return 3;
- }
- /// <summary>
- /// 使用本地预设创建一个物体
- /// </summary>
- /// <returns>The resource.</returns>
- /// <param name="lua">Lua.</param>
- public static int CreateResource(ILuaState lua)
- {
- //传入资源名称
- string mName=lua.L_CheckString(1);
- //加载本地资源
- GameObject go=(GameObject)Resources.Load(mName);
- //传入坐标参数x,y,z
- float mX=(float)lua.L_CheckNumber(2);
- float mY=(float)lua.L_CheckNumber(3);
- float mZ=(float)lua.L_CheckNumber(4);
- //创建一个新物体
- Object.Instantiate(go,new Vector3(mX,mY,mZ),Quaternion.identity);
- //返回该物体的名称
- lua.PushString(go.name);
- return 1;
- }
好了,这样我们就完成了一个简单的C#类库,下面我们来在主逻辑代码中增加一个更新脚本的方法UpdateScripts():
- void UpdateScript()
- {
- StartCoroutine("Download");
- }
- /// <summary>
- /// 下载Lua脚本更新文件
- /// </summary>
- IEnumerator Download()
- {
- //从本地加载Lua脚本更新文件,假设文件已经从服务器下载下来
- WWW _WWW=new WWW(mUpdateFilesPath);
- yield return _WWW;
- //读取服务器版本
- mLua.L_DoString(_WWW.text);
- }
这里的代码逻辑很简单,就是读取脚本更新本地文件然后执行脚本,其中mUpdateFilePath是脚本更新文件路径:
- //初始化路径
- mUpdateFilesPath="file://D:\\lua_update.txt";
这里博主设想的是在本地存储一个版本号,每次更新前先获取服务器端的版本号,如果两个版本号不同则需要从服务器上下载更新脚本文件进行更新。不过博主这里没有想到什么好方法来获取版本号,所以这里就只写了更新。那么,我们来看看更新脚本文件都做了哪些事情吧!
- local csharplib=require"CSharpLib.cs"
- csharplib.SetPosition("Cube",2,1,0)
- csharplib.CreateResource("Sphere",0,0,0)
- csharplib.CreateResource("Cube",1,1,0)
首先我们通过Require引入了CSharpLib.cs 这个类库,接下来,我们将场景中名称为Cube的物体的位置设为(2,1,0)、 利用本地的两个Prefab资源创建了一个Cube和一个Sphere。那么,我们的设想能不能实现呢?我们一起来看最终效果吧!
执行Lua脚本更新前:
执行Lua脚本更新后:
如我们所愿,Lua脚本成功地对场景实现了一次更新。可能有的朋友会问,这里用的是本地资源,如果我想用服务器上的资源怎么办呢?答案是博主最不愿意提及的AssetBundle,即利用AssetBundle加载远程资源,然后用Lua实现更新,这些逻辑可以添加到CSharpLib这个类库中。大家可以设想一下,如果有一天我们能够将Unity的所有方法都封装起来,那么我们就可以直接用Lua来创建场景了,如果要更新客户端,只要更换Lua文件就可以了,怎么样是不是很简单呢?可是Unity不开源啊,这些想法终究只是想法啦。好了,今天的内容就是这样了,欢迎大家关注我的博客,谢谢大家!
Lua------------------unity与lua的热更新的更多相关文章
- Unity应用的iOS热更新
Unity应用的iOS热更新 作者:丁治宇 Unity TechnologiesChina Agenda • 什么是热更新 • 为何要热更新 • 如何在iOS 上对Unity 应用进行热更新 • ...
- 关于lua 5.3 服务端热更新流程
脚本的热更新的流程都大同小异, 第一步先保存旧代码的块的数据, 第二部加载新的代码块,第三步将旧代码块的局部和全局数据拷贝到新代码块的对应的 变量中. 在服务器热更新中,主要考虑热更的内容是什么, 一 ...
- Unity 安卓下DLL热更新一(核心思想)
大家都知道一谈起热更新的话首选是Ulua这个插件, 其实Unity可以使用dll热更新的,如果你实在不想用Lua来编写逻辑,0.0请下看Dll+AssetBundle如何实现热更新的.让你看完这个文章 ...
- Unity官方发布热更新方案性能对照
孙广东 2016.3.11 Unity应用的iOS热更新 作者:丁治宇 Unity TechnologiesChina Agenda • 什么是热更新 • 为何要热更新 • 怎样在iOS 上对 ...
- unity热更新方案对比
Unity应用的iOS热更新 • 什么是热更新 • 为何要热更新 • 怎样在iOS 上对Unity 应用进行热更新 • 支持Unity iOS 热更新的各种Lua 插件的对照 什么是热更新 • ...
- Unity3D热更新之LuaFramework篇[10]--总结篇
背景 19年年初的时候,进到一家新单位,公司正准备将现有的游戏做成支持热更的版本.于是寻找热更方案的任务就落在了我头上. 经过搜索了解,能做Unity热更的方案是有好几种,但是要么不够成熟,要么不支持 ...
- ios app 实现热更新(无需发新版本实现app添加新功能)
目前能够实现热更新的方法,总结起来有以下三种 1. 使用FaceBook 的开源框架 reactive native,使用js写原生的iOS应用 ios app可以在运行时从服务器拉取最新的js文件到 ...
- ios app 实现热更新(无需发新版本号实现app加入新功能)
眼下可以实现热更新的方法,总结起来有下面三种 1. 使用FaceBook 的开源框架 reactive native,使用js写原生的ios应用 ios app能够在执行时从server拉取最新的js ...
- 出售一套Unity + Lua热更新框架代码
出售一套Unity + Lua的客户端框架代码,功能有资源管理.网络通信.配置文件解析.热更新.文件读写.Lua加密揭秘.UI框架.打包工具.编辑器工具等,已经在多个实际项目(已上线)中使用.代码优雅 ...
- Unity3D热更新之LuaFramework篇[07]--怎么让unity对象绑定Lua脚本
前言 在上一篇文章 Unity3D热更新之LuaFramework篇[06]--Lua中是怎么实现脚本生命周期的 中,我分析了由LuaBehaviour来实现lua脚本生命周期的方法. 但在实际使用中 ...
随机推荐
- 漫游Kafka之过期数据清理【转】
转自:http://blog.csdn.net/honglei915/article/details/49683065 Kafka将数据持久化到了硬盘上,允许你配置一定的策略对数据清理,清理的策略有两 ...
- plsql连接远程oracle和like无法查询中文问题
https://blog.csdn.net/yangguangzhidi/article/details/53301979 ************************************** ...
- django 部署,gunicorn、virtualenv、nginx
声明: 1.本篇文章是我边写命令边写的,请尊重我的劳动成果,转载请加上链接. 2.我既然公开写出来,是希望大家遇到问题的时候有个参考,所以,大家可以免费转载,使用该文章 3.但是,如果你要用这篇文章来 ...
- Delphi中的三目运算函数有哪些?(XE10.2+WIN764)
相关资料:https://www.cnblogs.com/rogge7/p/6078903.html 问题现象:在做一个判断时突然想到了C++的三目运算,就在想Delphi中一共有几个? 问题处理: ...
- 6. EM算法-高斯混合模型GMM+Lasso详细代码实现
1. 前言 我们之前有介绍过4. EM算法-高斯混合模型GMM详细代码实现,在那片博文里面把GMM说涉及到的过程,可能会遇到的问题,基本讲了.今天我们升级下,主要一起解析下EM算法中GMM(搞事混合模 ...
- WebSphere ILog JRules 域的介绍和定制
WebSphere ILog JRules 域的介绍和定制 引言 随着企业业务的不断发展,越来越多的企业正经历着以下的情形: 企业需要对于业务系统的频繁变化做出及时的关注和响应,例如,竞争对手或经济环 ...
- python学习笔记十四:wxPython Demo
一.简介 wxPython是Python语言的一套优秀的GUI图形库,允许Python程序员很方便的创建完整的.功能键全的GUI用户界面. wxPython是作为优秀的跨平台GUI库wxWidgets ...
- Java中LinkedList实现原理
数据结构 LinkedList是基于链表结构实现,所以在LinkedList类中包含了first和last两个指针(类型为Node).Node中包含了对prev节点.next节点的引用,这样就构成了双 ...
- Thrift——栗子
这张经典的图:黄色部分是用户实现的业务逻辑,褐色部分是根据Thrift定义的服务接口描述文件(IDL,接口定义语言)生成的客户端和服务端代码框架,红色部分是根据Thrift文件生成代码实现数据的读写操 ...
- Android——使用Toolbar + DrawerLayout快速实现高大上菜单侧滑(转)
今天就来使用官方支持库来快速实现这类效果,需要使用到Toolbar和DrawerLayout,详细步骤如下:(如果你还不知道这两个Widget,先自己Google吧~) 1.首先需要添加appcomp ...