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. jquery检测input checked 控件是否被选中的方法

    jquery检测input checked 控件是否被选中 js部分 复制代码代码如下: function tongyianniu(){ var gouxuan=$('input[type=check ...

  2. 链表的实现、输出和反向 python

    链表节点包含两个元素:节点的值和指向的下一个节点,因此可以定义链表的类为: class linknode: def __init__(self,value=None,next=None): self. ...

  3. 第十课 C++异常简介

    异常不是错误,异常是程序中可预料到的另一条执行分支,是可预见的.错误是不可预料的. C++内置了异常处理的语法元素try...catch...,如下: C++通过throw语句抛出异常信息: 上图中t ...

  4. 中国的 Python 量化交易工具链有哪些

    摘抄自知乎:https://www.zhihu.com/question/28557233 如题,提问的范围限于适合中国大陆金融市场使用的工具链,所以IbPy和Quotopian之类主要面向欧美市场的 ...

  5. [BZOJ5330][SDOI2018]反回文串

    luogu bzoj sol 枚举一个长度为\(n\)为回文串,它的所有循环位移都可以产生贡献. 但是这样算重了.重复的地方在于可能多个回文串循环同构,或者可能有的回文串经过小于\(n\)次循环位移后 ...

  6. 【idea】idea的常规设置

    [一]在输入框输入字符,自动提示代码 File->Power Save Mode  去掉“对号” [二]自动代码提示的快捷键设置 (1)不区分大小写提示 (2)修改快捷提示快捷键.将basic= ...

  7. 使用caddy 进行nodejs web应用近实时编译更新

    caddy 相比nginx 是一个不错的轻量代理服务器,支持的功能也是比较多的, 同时插件也挺多 demo 测试的是通过git 插件进行一个使用spec-md 编写的文档近实时编译以及预览 项目使用d ...

  8. 在IE7+ 中弹出窗口并关闭本身窗口的脚本(备忘)

    window.onload =function(){ window.open("http://www.126.com"); window.opener=null; window.o ...

  9. linux pwd命令查看当前路径命令

    命令简介: 该命令用来显示目前所在的工作目录.指令英文原义:print work directory执行权限 :All User指令所在路径:/usr/bin/pwd 或 /bin/pwd 命令语法: ...

  10. [java] java 实现FTP服务器文件的上传和下载

    利用Apache commons-net 实现: package com.xwolf.driver.util; import com.xwolf.driver.exception.RunExcepti ...