一、使用UGUI SimpleFramework来使用uLua
首先,上https://github.com/jarjin/SimpleFramework_UGUI/下载它,它是一个工程文件,里面包含了许多uLua需要用的东西,Editor、Lua、Script、Source文件都十分的重要,确保它们的存在,我们就能正常使用该框架。
注意:Unity 2017系列不可以用该框架,必须要用Unity5.0左右的版本。
二、基本使用方法(围绕自带的案例进行说明)
前提工作:
在Unity打开上面我们下载的工程后,会看到菜单栏上多了2个菜单,Lua和Game,接下来我们会用这2个菜单去布置我们Lua框架的环境。
1.点击Lua->Gen Lua Wrap Files ,做完这一步后会在uLua文件夹的Source文件夹生成一个LuaWarp文件夹,它存放了很多脚本,都是用于预先注册Unity封装的类进入Lua环境的,与luanet.import_type()方法和LuaScriptMgr有关。
2.点击Game->Build Window Resources,做完这一步后会在工程下生成一个StreamingAssets文件夹,它包含了AssetBundles资源和lua文件,这个StreamingAssets文件夹是非常关键的,因为我们会用到它来处理热更新,我们写的lua文件都要放在这个文件夹里面。
然后,我们点击Examples文件夹里面的Scenes文件夹的login场景,进入login场景,进行运行,这一步必须要做,因为login场景会对工程的一些文件进行操作的,这样我们才可以运行其他自带案例。
如果,不出意料,运行成功,会出现一个UI。
案例分析:
1、uLua->Examples->HelloWorld案例:(下面uLua->Examples->省略)
using UnityEngine;
using System.Collections;
using LuaInterface;
public class HelloWorld : MonoBehaviour {
// Use this for initialization
void Start () {
LuaState l = new LuaState();
string str = "print('hello world 世界')";
l.DoString(str);
}
// Update is called once per frame
void Update () {
}
}
在HelloWorld案例里面,我们可以看到有一个物体挂载了HelloWorld脚本(上面),在Start方法中创建了一个LuaState对象,该对象是类似于我们的luainterface.dll的Lua类,它就是在Lua类的再一层封装成为了LuaState类。
2、CreateGameObject01案例:
using UnityEngine;
using System.Collections;
using LuaInterface;
public class CreateGameObject01 : MonoBehaviour {
private string script = @"
luanet.load_assembly('UnityEngine')
GameObject = luanet.import_type('UnityEngine.GameObject')
ParticleSystem = luanet.import_type('UnityEngine.ParticleSystem')
local newGameObj = GameObject('NewObj')
newGameObj:AddComponent(luanet.ctype(ParticleSystem))
";
//反射调用
void Start () {
LuaState lua = new LuaState();
lua.DoString(script);
}
}
该案例和上面一样,一个物体挂着CreateGameObject01脚本,可发现script里的字符串就是lua代码,为什么在前面没有require 'luanet',却可以直接用luanet的方法?是因为这个框架的作用!即LuaState已经封装好了luanet,直接调用也OK了。其他也没什么好说的,导入UnityEngine的dll,然后加载UnityEngine.GameObject类和ParticleSystem类,使用它们创建一个物体,名叫NewObj,在该物体上调用AddComponent方法加上一个ParticleSystem组件。注意 参数不是直接写ParticleSystem那么简单,而是luanet.ctype(ParticleSystem).
3、CreateGameObject02案例:
using UnityEngine;
using System.Collections;
using LuaInterface;
public class CreateGameObject02 : MonoBehaviour {
private string script = @"
luanet.load_assembly('UnityEngine')
GameObject = UnityEngine.GameObject
ParticleSystem = UnityEngine.ParticleSystem
local newGameObj = GameObject('NewObj')
newGameObj:AddComponent(ParticleSystem.GetClassType())
";
//非反射调用
void Start () {
LuaScriptMgr lua = new LuaScriptMgr();
lua.Start();
lua.DoString(script);
}
}
可以发现这个案例与上面案例相差无几,只不过把LuaState换成了LuaScriptMgr类,这个类就是我上面所说的与Wrap文件有关的类,使用这个类的DoString()之前必须使用Start进行一些初始化操作。那么与LuaState区别的哪呢?
区别:使用LuaScriptMgr来执行的lua代码中,如果有需要加载类,无须用luanet.import_type()来导入了。直接在导入了UnityEngine的dll后,使用(UnityEngine.)的形式来导入里面的类,像案例那样UnityEngline.GameObject就可以了,而且添加组件的参数也可以不用luanet.ctype(xxx)了,直接用xxx.GetClassType()来。
说明:LuaState是在LuaInterface下的类,它在uLua文件夹的Core文件夹的Lua脚本中;LuaScriptMgr是在LuaState的再一封装,对LuaState进行管理的,它放在uLua->Source->Base文件夹下。
4、AccessingLuaVariables_01案例:
using UnityEngine;
using System.Collections;
using LuaInterface;
public class AccessingLuaVariables01 : MonoBehaviour {
private string script = @"
luanet.load_assembly('UnityEngine')
GameObject = luanet.import_type('UnityEngine.GameObject')
ParticleSystem = luanet.import_type('UnityEngine.ParticleSystem')
particles = {} --定义一个表
-- Objs2Spawn是C#定义的lua变量,值是5
for i = 1, Objs2Spawn, 1 do
local newGameObj = GameObject('NewObj' .. tostring(i))
local ps = newGameObj:AddComponent(luanet.ctype(ParticleSystem))
--local ps = newGameObj:AddComponent('ParticleSystem') PS:Unity5.x已经废弃这种方式,Unity4.x可用--
ps:Stop() --粒子播放停止
table.insert(particles, ps) --粒子组件放入表
end
var2read = 42 --定义一个变量
";
// Use this for initialization
void Start () {
LuaState l = new LuaState();
// Assign to global scope variables as if they're keys in a dictionary (they are really)
l["Objs2Spawn"] = 5; //首先C#这边给lua环境定义一个变量
l.DoString(script);
// Read from the global scope the same way
print("Read from lua: " + l["var2read"].ToString());// 访问lua的var2read变量即42
// Get the lua table as LuaTable object
LuaTable particles = (LuaTable)l["particles"]; //获取lua的particles表 ,放入LuaTable类型变量
// Typical foreach over values in table
foreach( ParticleSystem ps in particles.Values ) //遍历表的值
{
ps.Play();//播放
}
}
}
5、AccessingLuaVariables_02案例:
using UnityEngine;
using System.Collections;
using LuaInterface;
public class AccessingLuaVariables02 : MonoBehaviour
{
//cstolua要求必须要先定义变量才能使用
private string var = @"Objs2Spawn = 0";
private string script = @"
luanet.load_assembly('UnityEngine') --这句代码其实可以省去,在不同版本的uLua框架有些许不同吧.
ParticleSystem = UnityEngine.ParticleSystem --因为用的是LuaScriptMgr故获取方式,直接这样也可以.
particles = {}
for i = 1, Objs2Spawn, 1 do
local newGameObj = GameObject('NewObj' .. tostring(i))
local ps = newGameObj:AddComponent(ParticleSystem.GetClassType())
ps:Stop()
table.insert(particles, ps)
end
var2read = 42
";
// Use this for initialization
void Start () {
LuaScriptMgr mgr = new LuaScriptMgr();
mgr.Start();
// Assign to global scope variables as if they're keys in a dictionary (they are really)
LuaState l = mgr.lua; //获取mgr的LuaState脚本
l.DoString(var); //类似于l["Objs2Spawn"]=0,定义变量Objs2Spawn
l["Objs2Spawn"] = 5; //修改为5
l.DoString(script);
// Read from the global scope the same way
print("Read from lua: " + l["var2read"].ToString());
// Get the lua table as LuaTable object
LuaTable particles = (LuaTable)l["particles"];
// Typical foreach over values in table
foreach( ParticleSystem ps in particles.Values )
{
ps.Play();
}
}
}
6、ScriptsFromFile_01案例:
using UnityEngine;
using System.Collections;
using LuaInterface;
public class ScriptsFromFile_01 : MonoBehaviour
{
public TextAsset scriptFile; //TextAsset是文本类型
void Start()
{
LuaState l = new LuaState();
l.DoString(scriptFile.text); //执行外部传递的文本 ,该文本就写了一句print()
}
}
7、ScriptsFromFile_02案例:
using UnityEngine;
using System.Collections;
using LuaInterface;
public class ScriptsFromFile_02 : MonoBehaviour
{
void Start()
{
//只是展示如何加载文件。不是推荐这么做
LuaState l = new LuaState();
string path = Application.dataPath + "/uLua/Examples/04_ScriptsFromFile/ScriptsFromFile02.lua";
l.DoFile(path); //使用DoFile来执行文件的lua代码
}
}
Application.dataPath是工程的Assets目录。
8、CallLuaFunction_01案例:
using UnityEngine;
using System.Collections;
using LuaInterface;
public class CallLuaFunction_01 : MonoBehaviour {
private string script = @"
function luaFunc(message)
print(message)
return 42
end
";
// Use this for initialization
void Start () {
LuaState l = new LuaState();
// First run the script so the function is created
l.DoString(script);
// Get the function object
LuaFunction f = l.GetFunction("luaFunc");//上面的不解释了,应该都会,这里LuaFunction是获取luaFunc这个lua方法
// Call it, takes a variable number of object parameters and attempts to interpet them appropriately
object[] r = f.Call("I called a lua function!");//执行f方法的方式是f.Call(参数),用object[]接收返回值
// Lua functions can have variable returns, so we again store those as a C# object array, and in this case print the first one
print(r[0]); --输出第一个值,因为lua的luaFunc方法只有一个返回值42
}
}
9、CallLuaFunction_02案例(暂且看不懂)
using UnityEngine;
using System.Collections;
using LuaInterface;
using System;
public class CallLuaFunction_02 : MonoBehaviour {
private string script = @"
function luaFunc(num)
return num
end
";
LuaFunction func = null;
// Use this for initialization
void Start () {
LuaScriptMgr mgr = new LuaScriptMgr();
mgr.DoString(script);
// Get the function object
func = mgr.GetLuaFunction("luaFunc");
//有gc alloc
object[] r = func.Call(123456);
print(r[0]);
// no gc alloc
int num = CallFunc();
print(num);
}
void OnDestroy()
{
if (func != null)
{
func.Release();
}
}
int CallFunc() //无法理解下面
{
int top = func.BeginPCall();
IntPtr L = func.GetLuaState();
LuaScriptMgr.Push(L, 123456);
func.PCall(top, 1);
int num = (int)LuaScriptMgr.GetNumber(L, -1);
func.EndPCall(top);
return num;
}
}
10、06_LuaCoroutines案例:
using UnityEngine;
using System.Collections;
using LuaInterface;
public class LuaCoroutines : MonoBehaviour
{
private string script = @"
function fib(n)
local a, b = 0, 1
while n > 0 do
a, b = b, a + b
n = n - 1
end
return a
end
function CoFunc()
print('Coroutine started')
local i = 0
for i = 0, 10, 1 do
print(fib(i)) --输出前i个数的斐波数列之和
coroutine.wait(1) --相当于yield return new WaitForSeconds(1)
end
print('Coroutine ended')
end
function myFunc()
coroutine.start(CoFunc) --相当于StartCoroutine()方法
end
";
private LuaScriptMgr lua = null;
void Awake ()
{
lua = new LuaScriptMgr();
lua.Start();
lua.DoString(script);
LuaFunction f = lua.GetLuaFunction("myFunc");
f.Call();
f.Release();
}
//Lua环境模拟Unity的更新,这样做是为了让协程有计时的效果,这lua.Update、LateUpdate、FixedUpdate都是已经封装好的方法
void Update ()
{
lua.Update();
}
void LateUpdate()
{
lua.LateUpate();
}
void FixedUpdate()
{
lua.FixedUpdate();
}
}
其他案例不说明了,自己看看就OK了