Unity之热更新:(三)XLua

1. XLua是什么?

  Xlua是Lua在C#环境(.net)下的Lua解决方案,包括C#环境下的Lua代码解释器(Lua虚拟机)。

2. 基于XLua的纯Lua开发环境的基本原则? 

  • Unity场景里不放任务物体,通过代码创建和释放物体。这样避免冲突,方便维护(比如程序和美术都往场景里放了同一物体),可以通过搜索代码查看创建了哪些物体以及结构关系。
  • 运行时只有一个场景,没有场景切换。地图、角色、特效、粒子...都被做成资源或预制体给代码使用。(这一步实现美术与程序分离)
  • 不手动往节点上面挂脚本,而是通过代码AddComponent挂载。(方便维护,直接搜索组件名称就能找到哪里挂载了脚本)
  • 纯AssetsBundle来做资源管理,代替Resources。这样方便更新,方便打空包。
  • 制定一个纯Lua的组件化开发框架。方便写业务逻辑,减少Lua与C#相互调用。
  • 调试模式加载Lua代码、资源。AssetDataBase来加载资源。发布模式,打AB包,更新。

3. 在Unity中使用XLUA

 1)https://github.com/Tencent/xlua 下载xlua

 2)复制Assets文件夹下四个文件到工程Assets文件夹

 

 3)打开宏

 

 4)任何代码的修改都要执行以下两个步骤才能运行:

  5)下面开始写C#调用Lua的代码

写一个lua文件,命名后缀 .lua.txt

注意lua文件要放在C#脚本的同级Resources目录下。

 

 

 下面是C#脚本,演示C#脚本里调用lua。

 1 using System.Collections;
 2 using System.Collections.Generic;
 3 using UnityEngine;
 4 using XLua;
 5 
 6 public class textCSharp : MonoBehaviour 
 7 {
 8     LuaEnv env = new LuaEnv();
 9 
10     private void OnGUI()
11     {
12         if (GUILayout.Button("C#调用Lua语句"))
13             env.DoString("print 'testlua'");
14 
15         if (GUILayout.Button("C#调用Lua文件"))
16             CSharpCallLuaFile();    
17     }
18     void CSharpCallLuaFile()
19     {
20         env.DoString("require 'luatest'");
21         //调用lua全局变量
22         Debug.Log(env.Global.Get<string>("name"));
23         Debug.Log(env.Global.Get<int>("age"));
24         //调用lua表中数据
25         LuaTable table = env.Global.Get<LuaTable>("config");
26         Debug.Log(table.Get<string>("name"));
27         Debug.Log(table.Get<string>("age"));
28     }
29 }

也可以直接映射成类

 1 public class textCSharp : MonoBehaviour 
 2 {
 3     LuaEnv env = new LuaEnv();
 4 
 5     private void OnGUI()
 6     {
 7         if (GUILayout.Button("C#调用Lua文件"))
 8             CSharpCallLuaFile();    
 9     }
10     void CSharpCallLuaFile()
11     {
12         env.DoString("require 'luatest'");
13 
14         Config config = env.Global.Get<Config>("config");
15         Debug.Log(config.name);
16         Debug.Log(config.age);
17     }
18     public class Config
19     {
20         public string name;
21         public int age;
22     }
23 }
1 void CSharpCallLuaFile()
2     {
3         env.DoString("require 'luatest'");
4         //调用lua函数并接收返回值
5         LuaFunction fun = env.Global.Get<LuaFunction>("printInfo");
6         object[] objs = fun.Call();  //lua函数可以有1个或多个返回值
7         Debug.Log(objs[0]);
8     }

结果是:第一行输出的是Call()里面的内容

 

也可以使用委托来调用lua函数

 1 public class textCSharp : MonoBehaviour 
 2 {
 3     LuaEnv env = new LuaEnv();
 4 
 5     delegate int Fun(int num);
 6     private void OnGUI()
 7     {
 8         if (GUILayout.Button("C#调用Lua文件"))
 9             CSharpCallLuaFile();    
10     }
11     void CSharpCallLuaFile()
12     {
13         env.DoString("require 'luatest'");
14         //调用lua函数并接收返回值
15         Fun f = env.Global.Get<Fun>("printInfo");
16         Debug.Log(f(0));
17     }
18 }

输出:

 

 

 

 6)下面演示Lua调用C#

先写一个C#类

 1 public class Hero 
 2 {
 3     private int Hp;
 4     private string Name;
 5 
 6     public Hero(string name, int hp)
 7     {
 8         this.Name = name;
 9         this.Hp = hp;
10     }
11     public void PrintInfo()
12     {
13         Debug.Log(Name + "的血量是:" + Hp);
14     }
15     public int AddHp(int _hp)
16     {
17         Debug.Log("lua传递来的参数:" + _hp);
18         Hp += _hp;
19         return Hp;
20     }
21 }

lua脚本

 

 注意:Lua调用C#类,要加CS

Lua调用 MonoBehaviour 类要加 CS.UnityEngine

 别忘了在C#里执行一下

 1 public class textCSharp:MonoBehaviour
 2 {
 3     LuaEnv env = new LuaEnv();
 4     void OnGUI()
 5     {
 6         if (GUILayout.Button("Lua调用C#"))
 7         {
 8             LuaCallCSharp();
 9         }
10     }
11     void LuaCallCSharp()
12     {
13         env.DoString("require 'luatest'");
14     }
15 }

结果如下:

--------------------------------------------------------------------------------------------------------------------------------------------------------------

XLUA配置三步:

1.打标签 :XLUA会自动生成适配代码,注意子类打了标签,父类也要打。

[LuaCallCSharp]   Lua里适配的委托、接口也要在C#定义里打标签。 

[CSharpCallLua] 

[Hotfix]

2.静态列表

 

3.动态列表

 加 static List<Type> 修饰

详细参考:https://github.com/Tencent/xLua/blob/master/Assets/XLua/Doc/configure.md

 ===================================================================================

下面我们来搭一个XLUA使用框架

  1 using System.Collections;
  2 using System.Collections.Generic;
  3 using UnityEngine;
  4 using XLua;
  5 using System;
  6 
  7 [LuaCallCSharp]
  8 public class LuaEnvMgr
  9 {
 10     //单例
 11     private static LuaEnvMgr instance;
 12     public static LuaEnvMgr Instance
 13     {
 14         get {
 15             if (instance == null)
 16                 instance = new LuaEnvMgr();
 17             return instance;
 18         }
 19     }
 20     //封装Lua虚拟机
 21     private LuaEnv env;
 22     public LuaEnv Env
 23     {
 24         get { return env; }
 25     }
 26     //构造函数初始化Lua虚拟机
 27     public LuaEnvMgr()
 28     {
 29         env = new LuaEnv();
 30     }
 31     //获取Lua table
 32     public LuaTable GetGlobalTable()
 33     {
 34         return env.Global;
 35     }
 36     //创建Lua table
 37     public LuaTable CreateTable()
 38     {
 39         return env.NewTable();
 40     }
 41     //释放
 42     public void Dispose()
 43     {
 44         env.Dispose();
 45     }
 46 }
 47 
 48 [CSharpCallLua]
 49 public delegate void OnCollisionDel(Collision2D collision);
 50 
 51 [CSharpCallLua]
 52 public delegate void OnTriggerDel(Collider2D collision);
 53 /// <summary>
 54 /// 方便Lua调用C#生命周期函数
 55 /// </summary>
 56 [LuaCallCSharp]
 57 public class LuaCallBase : MonoBehaviour {
 58 
 59     public TextAsset textAsset;//lua文件
 60 
 61     protected LuaTable table;//存储lua文件数据的表
 62 
 63     //常用更新生命周期
 64     protected Action luaAwake;
 65     protected Action luaStart;
 66     protected Action luaUpdate;
 67     protected Action luaDestory;
 68     protected Action luaOnGUI;
 69 
 70     //自定义委托生命周期
 71     protected OnCollisionDel luaCollisionEnter;
 72     protected OnTriggerDel luaTriggerEnter;
 73 
 74 
 75     protected virtual void Awake()
 76     {
 77         table = LuaEnvMgr.Instance.CreateTable();
 78         LuaTable meta = LuaEnvMgr.Instance.CreateTable();
 79         meta.Set("__index", LuaEnvMgr.Instance.GetGlobalTable());
 80         table.SetMetaTable(meta);
 81         meta.Dispose();
 82 
 83         LuaEnvMgr.Instance.Env.DoString(textAsset.text, this.GetType().Name, table);
 84         
 85         
 86         SetLuaData();
 87         GetLuaData();
 88         if (luaAwake != null)
 89             luaAwake();
 90     }
 91 
 92     public object GetLuaData(string dataName)
 93     {
 94         object obj;
 95         table.Get(dataName,out obj);
 96         return obj;
 97     }
 98 
 99     protected virtual void SetLuaData()
100     {
101         table.Set("self", this);
102     }
103 
104     protected virtual void GetLuaData()
105     {
106         table.Get("awake", out luaAwake);
107         table.Get("start", out luaStart);
108         table.Get("update", out luaUpdate);
109         table.Get("destroy", out luaDestory);
110         table.Get("ongui", out luaOnGUI);
111 
112         table.Get("onCollisionEnter", out luaCollisionEnter);
113         table.Get("onTriggerEnter", out luaTriggerEnter);
114     }
115 
116     private void Start()
117     {
118         if (luaStart != null)
119             luaStart();
120     }
121     private void Update()
122     {
123         if (luaUpdate != null)
124             luaUpdate();
125     }
126     private void OnGUI()
127     {
128         if (luaOnGUI != null)
129             luaOnGUI();
130     }
131     private void OnDestroy()
132     {
133         if (luaDestory != null)
134             luaDestory();
135     }
136 
137     private void OnCollisionEnter2D(Collision2D collision)
138     {
139         if (luaCollisionEnter != null)
140             luaCollisionEnter(collision);
141     }
142     private void OnTriggerEnter2D(Collider2D collision)
143     {
144         if (luaTriggerEnter != null)
145             luaTriggerEnter(collision);
146     }
147 }
View Code

只需要继承这个框架类,把lua脚本拖上去,就会执行啦!跟C#在Unity里的操作一样,只是挂载的C#脚本里的功能都由Lua脚本来实现了。

如果嫌Lua每次调用C#方法都要加前缀麻烦。可以写一个Lua公共脚本,把这些前缀重新赋值,其他脚本只要 require "公共脚本名",就可以像写C#一样调用Unity方法啦!

System=CS.System
Int=System.Int32
String=System.String

Unity=CS.UnityEngine
Debug=Unity.Debug
GameObject=Unity.GameObject
Transform=Unity.Transform
Renderer=Unity.Renderer
Color=Unity.Color
Vector3=Unity.Vector3
Vector2=Unity.Vector2
Input=Unity.Input
Resources=Unity.Resources
Camera=Unity.Camera
LineRenderer=Unity.LineRenderer
EdgeCollider2D=Unity.EdgeCollider2D
Time=Unity.Time

Vector3List=CS.System.Collections.Generic.List(Vector3)
Vector2List=CS.System.Collections.Generic.List(Vector2)

function getLuaData(obj,script,data)
    local instance=obj:GetComponent(script)
    return instance:GetLuaData(data)
end

  

参考:Unity3D架构师进阶系列: 基于xLua的热更框架

posted @ 2021-12-12 16:49  番茄玛丽  阅读(745)  评论(0编辑  收藏  举报