1. Helloworld

 using UnityEngine;
using XLua; public class Helloworld : MonoBehaviour {
// Use this for initialization
void Start () {
LuaEnv luaenv = new LuaEnv();
// 执行代码块,输出 hello world
luaenv.DoString("CS.UnityEngine.Debug.Log('hello world')");
// 释放资源
luaenv.Dispose();
}
}

  该案例实现了在 Unity 控制台输出 hello world。

2. U3DScripting

  

  

  lua 代码如下:

 local speed =
local lightCpnt = nil function start()
print("lua start...")
-- 访问环境变量
print("injected object", lightObject)
-- 查找 Light 组件
lightCpnt= lightObject:GetComponent(typeof(CS.UnityEngine.Light))
end function update()
local r = CS.UnityEngine.Vector3.up * CS.UnityEngine.Time.deltaTime * speed
-- 绕y轴旋转
self.transform:Rotate(r)
-- 修改光线颜色
lightCpnt.color = CS.UnityEngine.Color(CS.UnityEngine.Mathf.Sin(CS.UnityEngine.Time.time) / + 0.5, , , )
end function ondestroy()
print("lua destroy")
end

  注意,如果要插入中文注释,需要将 txt 编码格式改为 UTF-8,否则无法执行。

  C# 代码如下:

 using UnityEngine;
using XLua;
using System; [System.Serializable]
public class Injection
{
public string name;
public GameObject value;
} [LuaCallCSharp]
public class LuaBehaviour : MonoBehaviour {
public TextAsset luaScript; // lua脚本文件
public Injection[] injections; // 需要注入到环境变量的物体 internal static LuaEnv luaEnv = new LuaEnv(); //all lua behaviour shared one luaenv only!
internal static float lastGCTime = ;
internal const float GCInterval = ;//1 second private Action luaStart;
private Action luaUpdate;
private Action luaOnDestroy; private LuaTable scriptEnv; void Awake()
{
scriptEnv = luaEnv.NewTable(); LuaTable meta = luaEnv.NewTable();
meta.Set("__index", luaEnv.Global);
scriptEnv.SetMetaTable(meta);
meta.Dispose(); // 配置环境变量,在lua代码里能直接调用
scriptEnv.Set("self", this);
foreach (var injection in injections)
{
scriptEnv.Set(injection.name, injection.value);
}
// 参数1:Lua代码的字符串
// 参数2:发生error时的debug显示信息时使用
// 参数3:代码块的环境变量
luaEnv.DoString(luaScript.text, "LuaBehaviour", scriptEnv); // 访问函数
Action luaAwake = scriptEnv.Get<Action>("awake");
scriptEnv.Get("start", out luaStart);
scriptEnv.Get("update", out luaUpdate);
scriptEnv.Get("ondestroy", out luaOnDestroy); // 执行事件
if (luaAwake != null)
{
luaAwake();
}
} // Use this for initialization
void Start ()
{
if (luaStart != null)
{
luaStart();
}
} // Update is called once per frame
void Update ()
{
if (luaUpdate != null)
{
luaUpdate();
}
if (Time.time - LuaBehaviour.lastGCTime > GCInterval)
{
// 清楚lua未手动释放的LuaBase对象,需定期调用,这里是1s调用一次
luaEnv.Tick();
LuaBehaviour.lastGCTime = Time.time;
}
} void OnDestroy()
{
if (luaOnDestroy != null)
{
luaOnDestroy();
}
luaOnDestroy = null;
luaUpdate = null;
luaStart = null;
scriptEnv.Dispose();
injections = null;
}
}

  该场景实现了 lua 代码控制 U3D 物体,以实现物体的旋转和颜色变化。

三、UIEvent

  

  

  lua 代码如下:

 function start()
print("lua start...")
-- 给button添加事件
-- 点击输出 input 输入内容
self:GetComponent("Button").onClick:AddListener(function()
print("clicked, you input is '" ..input:GetComponent("InputField").text .."'")
end)
end

  该场景实现了 lua 代码为 button 添加事件响应函数,以实现点击按钮输出输入框内容。

  注意,lua 中 . 和 : 的区别:

    • 定义的时候:Class:test() 与 Class.test(self) 是等价的
    • 调用的时候:object:test() 与 object.test(object) 等价

  在这里,调用类的方法使用 :,调用属性用 . 。

  C# 代码还是上一场景的 LuaBehaviour.cs。

四、InvokeLua

  C# 代码如下:

 using UnityEngine;
using XLua; public class InvokeLua : MonoBehaviour
{
[CSharpCallLua]
public interface ICalc
{
int Add(int a, int b);
int Mult { get; set; }
} [CSharpCallLua]
public delegate ICalc CalcNew(int mult, params string[] args); private string script = @"
local calc_mt = {
__index = {
Add = function(self, a, b)
return (a + b) * self.Mult
end
}
} Calc = {
-- 多参数函数
New = function (mult, ...)
print(...)
return setmetatable({Mult = mult}, calc_mt)
end
}
";
// Use this for initialization
void Start()
{
LuaEnv luaenv = new LuaEnv();
Test(luaenv);//调用了带可变参数的delegate,函数结束都不会释放delegate,即使置空并调用GC
luaenv.Dispose();
} void Test(LuaEnv luaenv)
{
luaenv.DoString(script);
// 访问 lua 函数
CalcNew calc_new = luaenv.Global.GetInPath<CalcNew>("Calc.New");
ICalc calc = calc_new(, "hi", "john"); //constructor
Debug.Log("sum(*10) =" + calc.Add(, )); // (1+2)*10
calc.Mult = ;
Debug.Log("sum(*100)=" + calc.Add(, )); // (1+2)*100
}
}

  该场景实现了 C# 调用 lua 代码的函数,table。注意要加上  [CSharpCallLua] 。

五、NoGc

  看不懂。

六、Coroutine

  总共有四个代码文件,关键代码如下。

  1. CoroutineTest.cs

 LuaEnv luaenv = null;
// Use this for initialization
void Start()
{
luaenv = new LuaEnv();
// 执行 coruntine_test
luaenv.DoString("require 'coruntine_test'");
}

  2. coruntine_test.lua

 local util = require 'xlua.util'

 local yield_return = (require 'cs_coroutine').yield_return

 local co = coroutine.create(function()
print('coroutine start!')
local s = os.time()
-- 协程等待3秒
yield_return(CS.UnityEngine.WaitForSeconds())
print('wait interval:', os.time() - s) local www = CS.UnityEngine.WWW('http://www.cnblogs.com/coderJiebao/p/unity3d22.html')
-- 协程加载网页
yield_return(www)
if not www.error then
print(www.bytes)
else
print('error:', www.error)
end
end) assert(coroutine.resume(co))

  3. cs_coroutine.lua

 local util = require 'xlua.util'

 -- 新建物体
local gameobject = CS.UnityEngine.GameObject('Coroutine_Runner')
-- 设置不自动销毁
CS.UnityEngine.Object.DontDestroyOnLoad(gameobject)
-- 添加组件
local cs_coroutine_runner = gameobject:AddComponent(typeof(CS.Coroutine_Runner)) local function async_yield_return(to_yield, cb)
cs_coroutine_runner:YieldAndCallback(to_yield, cb) -- 调用 C# 函数
end return {
yield_return = util.async_to_sync(async_yield_return)
}

  4. Coroutine_Runner.cs

 [LuaCallCSharp]
public class Coroutine_Runner : MonoBehaviour
{
public void YieldAndCallback(object to_yield, Action callback)
{
// 开启协程,回调callback
StartCoroutine(CoBody(to_yield, callback));
} private IEnumerator CoBody(object to_yield, Action callback)
{
if (to_yield is IEnumerator)
yield return StartCoroutine((IEnumerator)to_yield);
else
yield return to_yield;
callback();
}
}

  该场景实现了协程等待3s和加载网页的功能。

  调用流程为:CoroutineTest.Start -> coruntine_test(创建协程,调用 yield_return 方法)-> cs+coroutine.async_yield_return -> Coroutine_Runner.YieldAndCallback。

七、AsyncTest

  继续看不懂,后期补上。

八、Hotfix

1. 使用方式

  (1) 在 github上下载 xlua 源码后,将 Asserts 文件夹内的文件以及 Tools 文件夹直接拖到工程,这时候会报错,删除 Tools 文件夹下的 System.dll 和 System.core.dll 即可。

  (2) 添加 HOTFIX_ENABLE 和 INJECT_WITHOUT_TOOL 两个宏(在 File->Build Setting->Player Setting->Scripting Define Symbols) 

  (3) 执行XLua/Generate Code菜单

  (4) 编写代码,注意在需要热更新的地方添加[Hotfix]标签

  (5) 注入,构建手机包这个步骤会在构建时自动进行,编辑器下开发补丁需要手动执行"XLua/Hotfix Inject In Editor"菜单。注入成功会打印“hotfix inject finish!”或者“had injected!”。    

2. 常用函数

xlua.hotfix(class, [method_name], fix)
  • 描述 : 注入lua补丁
  • class : C#类,两种表示方法,CS.Namespace.TypeName或者字符串方式"Namespace.TypeName",字符串格式和C#的Type.GetType要求一致,如果是内嵌类型(Nested Type)是非Public类型的话,只能用字符串方式表示"Namespace.TypeName+NestedTypeName";
  • method_name : 方法名,可选;
  • fix : 如果传了method_name,fix将会是一个function,否则通过table提供一组函数。table的组织按key是method_name,value是function的方式。
xlua.private_accessible(class)
  • 描述 : 让一个类的私有字段,属性,方法等可用
  • class : 同xlua.hotfix的class参数
util.hotfix_ex(class, method_name, fix)
  • 描述 : xlua.hotfix的增强版本,可以在fix函数里头执行原来的函数,缺点是fix的执行会略慢。
  • method_name : 方法名;
  • fix : 用来替换C#方法的lua function。
base(csobj)
  • 描述:子类 override 函数通过 base 调用父类实现
  • csobj:对象
  • 返回值:新对象

3. 打补丁

  xlua 可以用 lua 函数替换 C# 的构造函数,函数,属性,事件的替换。

  (1) 函数

  可以指定一个函数,也可以传递由多个函数组成的 table。

 -- 注入lua补丁,替换HotfixCalc.Add
xlua.hotfix(CS.HotfixCalc, 'Add', function(self, a, b)
-- 原来为 a-b
return a + b
end)
 -- 通过table提供一组函数
-- table的组织按key是methodname,value是function的方式
xlua.hotfix(CS.HotfixCalc, {
Test1 = function(self)
print('Test1', self)
return
end;
Test2 = function(self, a, b)
print('Test2', self, a, b)
return a + , , b
end;
-- static 函数不需要加self
Test3 = function(a)
print(a)
return
end;
Test4 = function(a)
print(a)
end;
-- 多参数
Test5 = function(self, a, ...)
print('Test4', self, a, ...)
end
})

  (2) 构造函数

  构造函数对应的 method_name 是 ".ctor",和普通函数不一样的是,构造函数的热补丁并不是替换,而是执行原有逻辑后调用 lua。

 -- 构造函数
['.ctor'] = function(csobj)
return {evt = {}, start = }
end;

  (3) 属性

  每一个属性都对应一个get,set函数。

 -- 属性AProp的赋值和取值
set_AProp = function(self, v)
print('set_AProp', v)
self.AProp = v
end;
get_AProp = function(self)
return self.AProp
end;

  (4) [] 操作符

  赋值对应 set_Item,取值对应 set_Item。

 -- []操作符,赋值和取值
get_Item = function(self, k)
print('get_Item', k)
return
end;
set_Item = function(self, k, v)
print('set_Item', k, v)
end;

  对于其他操作符,C#的操作符都有一套内部表示,比如+号的操作符函数名是op_Addition。

  (5) 事件

  += 操作符是 add_...,-= 操作符是 remove_... ,函数第一个参数是自身,第二个参数是操作符右边的 delegate。

 -- 事件AEvent +=
add_AEvent = function(self, cb)
print('add_AEvent', cb)
table.insert(self.evt, cb)
end;
-- 事件AEvent -=
remove_AEvent = function(self, cb)
print('remove_AEvent', cb)
for i, v in ipairs(self.evt) do
if v == cb then
table.remove(self.evt, i)
break
end
end
end;

  (6) 析构函数

  函数名是 Finalize,传一个 self 参数。和普通函数不一样的是,析构函数的热补丁并不是替换,而是开头调用 lua 函数后继续原有逻辑。

 -- 析构函数
Finalize = function(self)
print('Finalize', self)
end

  (7) 泛化类型

  每个泛化类型都是一个独立的类型,需要对实例化后的类型分别打补丁。

 xlua.hotfix(CS['GenericClass`1[System.Double]'], {
['.ctor'] = function(obj, a)
print('GenericClass<double>', obj, a)
end;
Func1 = function(obj)
print('GenericClass<double>.Func1', obj)
end;
Func2 = function(obj)
print('GenericClass<double>.Func2', obj)
return
end
})

  (8) 子类调用父类

 -- 子类调用父类的方法
xlua.hotfix(CS.BaseTest, 'Foo', function(self, p)
print('BaseTest', p)
base(self):Foo(p)
end)
xlua.hotfix(CS.BaseTest, 'ToString', function(self)
return '>>>' .. base(self):ToString()
end)

Unity XLua 官方案例学习的更多相关文章

  1. Unity Dotween官方案例学习

    本文只涉及一些案例,具体查看 DoTween 官方文档. 一. Basics public class Basics : MonoBehaviour { public Transform redCub ...

  2. Unity XLua 官方教程学习

    一.Lua 文件加载 1. 执行字符串 using UnityEngine; using XLua; public class ByString : MonoBehaviour { LuaEnv lu ...

  3. Unity EasyTouch官方案例学习

    一.代码检测手势事件 1. EasyTouch4.x 写法 首先要手动在 Hierarchy 窗口添加 EasyTouch 物体,以触摸(Touch)手势为例,代码如下: using UnityEng ...

  4. 8.3 ContosoMVCWeb官方案例学习

    1. 分页案例学习 2. 排序搜索案例学习 3.使用Configuration.cs中的Seed方法 在数据库迁移过程中,使用update-database,会运行seed方法.seed方法能够将初始 ...

  5. Egret官方案例学习笔记

    1.资源记载方式 (1)Egret引擎是2.0.5. (2)resource/resource.json文件是: { "resources": [ { "name&quo ...

  6. UE4的AI学习(2)——官方案例实例分析

    官方给出的AI实例是实现一个跟随着玩家跑的AI,当玩家没有在AI视野里时,它会继续跑到最后看到玩家的地点,等待几秒后如果仍然看不到玩家,则跑回初始地点.官方的案例已经讲得比较详细,对于一些具体的函数调 ...

  7. Unity CommandBuffer的一些学习整理

    1.前言 近期在整理CommandBuffer这块资料,之前的了解一直较为混乱. 算不上新东西了,但个人觉得有些时候要比加一个摄像机再转RT廉价一些,至少省了深度排序这些操作. 本文使用两个例子讲解C ...

  8. 通过angularJS官方案例快速入门

    官方案例-angular-phonecat angularJS官方提供了一个官方案例给大家进行循序渐进的学习,但是如果之前没有接触过node.js以及git的同学这个案例拿着也无从下手-这里就介绍一下 ...

  9. Siki_Unity_2-4_UGUI_Unity5.1 UI 案例学习

    Unity 2-4 UGUI Unity5.1 UI 案例学习 任务1-1:UGUI简介 什么是GUI: 游戏的开始菜单 RPG游戏的菜单栏.侧边栏和功能栏(比如背包系统.任务列表等) 设计用来控制移 ...

随机推荐

  1. vsftpd日志配置及查看——可以将vsftpd记录在系统日志里

    vsftpd日志配置及查看 vsftpd ftp服务器的日志设置,可以通过修改主配置文件/etc/vsftpd.conf实现.主配置文件中与日志设置有关的选项包括xferlog_enable .xfe ...

  2. ViewPager + Fragment 实现主界面底部导航栏

    1. 四个类似的Frament布局 tab_main_fragment.xml <LinearLayout xmlns:android="http://schemas.android. ...

  3. VS中的生成事件

    1:为什么需要使用生成事件? 在实际开发过程中,一个公共使用的类库,在项目生成DLL后需要被复制到不同的目录下被引用,是不是觉得每次生成之后都需要人工复制是很麻烦的一件事情 我们可以利用VS中的项目生 ...

  4. L203 词汇题

    Conditions for the growth of this plant are optimum in early summer.we will live as free people, not ...

  5. New Concept English Two 21 55

    $课文53  触电的蛇 544. At last firemen have put out a big forest fire in California. 消防队员们终于扑灭了加利福尼亚的一场森林大 ...

  6. 一个简单的观察者模式的JS实现

    这不是原创文章,主要是写给自己看的.原文比较详细容易让人,我提取最简单最好理解的部分,便于我以后用到.参考http://www.cnblogs.com/TomXu/archive/2012/03/02 ...

  7. CF1143C Queen

    CF1143C Queen 开始想大力维护 \(bfs\) 序+数据结构解决,但 \(bfs\) 序的变化不太好推. 换了一个思路,注意到删除一个点后,原来可以被删除的点仍然可以被删除,原来不能被删除 ...

  8. 使用defined和require引入js

    define(function(require, exports, module) { var ceshiTwo = { dataCeshi:[1,2,3,4,5], arrCeshi:functio ...

  9. CentOS 6.5 下HeartBeat的安装与配置

    CentOS 6.5 下HeartBeat的安装与配置 参考网站: http://wenku.baidu.com/link?url=BvqJatdx1m12PLil-7YA1zkM0yUOEO8OnN ...

  10. 锐捷 rg-S2026f 学习笔记

    1.通过串口连接交换机: http://support.ruijie.com.cn/forum.php?mod=viewthread&tid=32250&extra=page%3D1& ...