找回密码
 立即注册
查看: 340|回复: 0

Xlua学习笔记

[复制链接]
发表于 2021-8-13 12:35 | 显示全部楼层 |阅读模式
本篇笔记是记录"游戏热更新实战案例(基于xLua)"的学习笔记。
1、Xlua的环境搭建
1)导入Xlua插件
上Github上下载Xlua插件,将Xlua解压,将Asset下的所有文件拷贝到当前项目目录Asset下。拷贝与Asset同级目录下的Tools到该该项目中一样的位置。
2)unity菜单栏 File=》BuildSetting=》playsetting =》OtherSettings=》Scripting Define Symbols 输入HOTFIX_ENABLE


搭建功能就完成了。
3)复制相关DLL文件


PS:该捕鱼项目是2017的uinity版本,我用2018打开Xlua部署环境报错,用2017则无问题,原因可能是Xlua版本没有更新,大家学习的时候注意一下版本问题。
2、使用Xlua修复游戏中存在的BUG。
1)如何通过lua文件实现热更新?
首先创建一个调用脚本,挂在物体上,代码如下。这个是固定格式,相关API不明白的话可以自行查阅。
  1. publicclassHotFixScript:MonoBehaviour{privateLuaEnv luaEnv;void Start (){
  2.         luaEnv =newLuaEnv();
  3.         luaEnv.AddLoader(MyLoader);
  4.         luaEnv.DoString("require'fish'");}void Update (){}privatebyte[]MyLoader(refstring filePath){string absPath =@"C:\Users\Administrator\Desktop\XluaProjects\PlayerGamePackage"+filePath+".lua.txt";return System.Text.Encoding.UTF8.GetBytes(File.ReadAllText(absPath));}//在OnDestroy前调用,释放已经注册的委托privatevoidOnDisable(){
  5.         luaEnv.DoString("require'fishDispose'");}privatevoidOnDestroy(){
  6.         luaEnv.Dispose();}}
复制代码
然后在绝对路径创建lua文件。


然后在可能会出现问题的类上打上[Hotfix]标签


在需要修改的函数方法上打上[LuaCallCSharp]标签


执行到这里的时候就会调用Lua脚本。
功能需求以及解决方法的相关代码。
1.1点击宝箱领取的金币钻石太拥挤,分散一点
  1. --1.1点击宝箱领取的金币钻石太拥挤,分散一点--常用的变量可以定义一个局部变量去接收--[[
  2. Lua调用C#中的类要添加前缀CS.
  3. C#中调用自身对象是this.XXX
  4. 但是lua中需要加上self.
  5. 此处想调用自身的金币, C#完整代码是this.gold,但是在lua中要写全,为self.gold。--]]local UnityEngine = CS.UnityEngine
  6. --标准格式,第一个参数是C#中打上标签的类(即你想修改的类,第二个参数是要修改的方法,第三个参数是自身)--此处金币拥挤,我们只需查看代码,将相关间隔的相关代码数值增大即可。
  7. xlua.hotfix(CS.Treasour,'CreatePrize',function(self)for i=0,4,1dolocal go = UnityEngine.GameObject.Instantiate(self.gold,self.transform.position + UnityEngine.Vector3(-10+i*40,0,0),self.transform.rotation)
  8.                 go.transform.SetParent(go.transform,self.cavas)local go1 = UnityEngine.GameObject.Instantiate(self.diamands,self.transform.position + UnityEngine.Vector3(0,40,0)+ UnityEngine.Vector3(-10+i*40,0,0),self.transform.rotation)
  9.                 go1.transform.SetParent(go1.transform,self.cavas)endend)
复制代码

lua中代码将30改为40,即可完成这个初步的简单任务。
1.1玩家金币钻石不够时没有相关处理
这个问题处理起来有个小坑,C#代码中调用了私有变量,lua中直接调用会报错,需要加上相关代码,如下。
另外lua中调用自身的方法为XX.Func(self) 或者XX:Func()
  1. --如果想访问私有变量需要加上下面这一行代码,此处bullectAudio是私有变量
  2. xlua.private_accessible(CS.Gun)
  3. xlua.hotfix(CS.Gun,'Attack',function(self)if UnityEngine.Input.GetMouseButtonDown(0)thenif UnityEngine.EventSystems.EventSystem.current:IsPointerOverGameObject()thenreturnendif self.gold<1+(self.gunLevel-1)*2or self.gold==0thenreturnend
  4.                 self.bullectAudio.clip = self.bullectAudios[self.gunLevel-1]--self.bullectAudio.Play(self) 两种调用自身方法的形式
  5.                 self.bullectAudio:Play()if self.Butterfly then
  6.                                 UnityEngine.GameObject.Instantiate(self.Bullects[self.gunLevel-1],self.attackPos.position,self.attackPos.rotation*UnityEngine.Quaternion.Euler(0,0,20))
  7.                                 UnityEngine.GameObject.Instantiate(self.Bullects[self.gunLevel-1],self.attackPos.position,self.attackPos.rotation*UnityEngine.Quaternion.Euler(0,0,-20))end
  8.                         UnityEngine.GameObject.Instantiate(self.Bullects[self.gunLevel-1],self.attackPos.position,self.attackPos.rotation)ifnot self.canShootForFree then
  9.                                 self:GoldChange(-1-(self.gunLevel-1)*2)end
  10.                         self.attackCD =0
  11.                         self.attack =falseendend)
复制代码
–1.2 技能扣除钻石太多
解决方法,一样查看相关代码,然后修改


发现代码写在Start中,这里要注意,我们调用luaEnv的脚本要写在Awake中,补丁需要在代码前执行。写在Start顺序可能会出问题从而导致无效。
  1. xlua.private_accessible(CS.Fire)
  2. xlua.hotfix(CS.Fire,'Start',function(self)
  3.         self.reduceDiamands =8end)
复制代码
–1.2boss撞击玩家数值变动一样且不是减少是增加
依旧和之前一样,找到相关代码,用lua修改


但这次使用更简便的方法,不需要重写全部,而是在执行完之后再执行我们的lua代码
需要注意,util的这个文件要和当前的lua脚本在同级目录下,这个文件可以下xlua文件下种搜索到。复制过来粘贴即可。注销委托的时候格式与之前一样,依旧是xlua.hotfix(CS.Boss,‘Start’,nil)
  1. local util = require 'util'
  2. xlua.private_accessible(CS.Boss)
  3. util.hotfix_ex(CS.Boss,'Start',function(self)
  4.         self:Start()
  5.         self.m_reduceGold = self.m_reduceGold-10;end)
复制代码
–1.3 boss撞击玩家当钻石金币不够时产生负数
这个与之前有点区别,需要传参,改动方法如下


  1. util.hotfix_ex(CS.Gun,'GoldChange',function(self,number)
  2.         self:GoldChange(number)if self.gold <-number then
  3.                 self.gold =0returnendend)
复制代码
–1.4捕鱼概率修改
捕鱼代码中用到了GetComponent方法,但是lua中不支持泛型,好在C#中也支持参数为string的GetComponent方法,穿的参数改为string类型即可。
  1. itemGo:GetComponent('Gold').bossPrize =true
复制代码
–1.4游戏操作方式更改
无新的知识点,lua重写代码即可。
–2.0新增海浪
这个比较麻烦,首先需要一个预制体,其次这个预制体上还要有脚本代码。解决方法,先创建一个空的脚本,里面有几个常用的空方法,挂在预制体上,然后打包成AssetBundle文件上传至服务器,加载的时候可以先从服务器下载到本地指定位置,然后再读取。
  1. //空的C#脚本,留给lua脚本实现[Hotfix]publicclassHotFixEmpty:MonoBehaviour{// Use this for initializationvoid Start (){}// Update is called once per framevoid Update (){}privatevoidBehaviourMethod(){}privatevoidOnTriggerEnter(Collider other){}}
复制代码
  1. --2.0新增海浪--lua脚本实现功能。
  2. xlua.private_accessible(CS.HotFixEmpty)
  3. xlua.hotfix(CS.HotFixEmpty,'Start',function(self)
  4.         self:Invoke('BehaviourMethod',8)end)
  5. xlua.hotfix(CS.HotFixEmpty,'Update',function(self)
  6.         self.transform:Translate(-self.transform.right*4*UnityEngine.Time.deltaTime,UnityEngine.Space.World)end)
  7. xlua.hotfix(CS.HotFixEmpty,'OnTriggerEnter',function(self,other)if other.tag~='Untagged'and other.tag~='Wall'then
  8.         UnityEngine.Object.Destroy(other.gameObject)endend)
  9. xlua.hotfix(CS.HotFixEmpty,'BehaviourMethod',function(self)
  10.         CS.Gun.Instance.level = CS.Gun.Instance.level +1if CS.Gun.Instance.level ==4then
  11.                 CS.Gun.Instance.level =1end
  12.         canCreateNewFish =true
  13.         CS.Gun.Instance.changeAudio =true
  14.         UnityEngine.Object.Destroy(self.gameObject)end)
复制代码
总结:使用Xlua时需要注意的坑。
1、普通成员方法与静态成员方法调用的区别。
静态成员方法直接XX.Function()即可。有参数直接写在括号里 XX.Function(a,b…)
普通成员方法调用格式为 XX.Function(self)有参数写在self后面 XX.Function(self,a,b)
或者XX:Function()有参数直接写在括号里XX:Function(a,b)
2、lua中不存在new,如果C#脚本中存在new,直接无视即可。
3、lua中不支持泛型,如果C#中用到了泛型,请替代为string参数,或者单独写一个方法获取值,lua调用方法获得返回值
4、过于复杂的代码建议C#实现,lua直接调用即可,虽然lua也能实现,但是比较麻烦且性能消耗不如C#,例如
  1. [LuaCallCSharp]publicvoidLoadResource(string resName,string filePath){StartCoroutine(LoadResourceCorotine(resName, filePath));}IEnumeratorLoadResourceCorotine(string resName,string filePath){UnityWebRequest request= UnityWebRequest.GetAssetBundle(@"http://localhost/AssetBundles/"+ filePath);yieldreturn request.SendWebRequest();//AssetBundle ab = AssetBundle.LoadFromFile(@"C:\Users\Administrator\Desktop\XluaProjects\FishingJoy\AssetBundles" + filePath);AssetBundle ab =(request.downloadHandler as DownloadHandlerAssetBundle).assetBundle;GameObject gameObject = ab.LoadAsset<GameObject>(resName);
  2.         prefabDict.Add(resName, gameObject);}
复制代码
  1. xlua.hotfix(CS.CreateFish,'Start',function(self)
  2.         self.hotFixScript:LoadResource('level3fish3','gameobject\\enemy.ab')
  3.         self.hotFixScript:LoadResource('SeaWave','gameobject\\wave.ab')end)
复制代码
这里lua调用起来就很方便。
5、lua主要是用来修复紧急BUG,不建议做大改动,例如2.0版本开发的海浪功能,先把资源打包好上传到服务器,代码全部是lua写,开发效率较低。
如果预制体上挂有脚本,本地一定要先有脚本在解压,不然AssetBundle解压出来没有脚本则会丢失,无法完成相应的功能。
资源图片较多,文件较大,想看源码的建议移步siki学院搜索热更新

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2025-1-18 03:21 , Processed in 1.009351 second(s), 26 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表