如博文无法正常显示,请访问原文地址: https://blog.csdn.net/ChinarCSDN/article/details/83044148
Chinar 坚持将简单的生活方式,带给世人! (拥有更好的阅读体验 —— 高分辨率用户请根据需求调整网页缩放比例) |
助力快速了解 tolua 热更新框架的具体使用、细节 为新手节省宝贵的时间,避免采坑! |
Chinar 教程效果:
Wait —— 敬请期待
正在整理中。。。。 Chinar 教程简单易懂,但整理资料,写起来并不容易,感谢大家的关注与理解
DoString() —— 该函数:可直接调用指定的 C# 脚本中的指定字符串 lua 代码
注意:
这对于初学者是一个老生常谈的问题了
Lua 中调用C#函数用“:”,字段用“.”
: —— map:GetEnumerator()
/iter:MoveNext()
. ——iter.Current.name
/map.Keys
using UnityEngine;
using LuaInterface;
///
/// Chinar解释-tolua官方测试案例1
///
public class HelloWorld : MonoBehaviour
{
void Awake()
{
LuaState lua = new LuaState();
lua.Start();
string hello = //字符串书写 lua 代码
@"
print('hello tolua#')
";
lua.DoString(hello, "HelloWorld.cs"); //执行C#脚本: HelloWorld 中的 hello字符串
lua.CheckTop(); //检验
lua.Dispose(); //释放
lua = null; //质空
}
}
运行结果:
hello tolua
AddSearchPath() —— 该函数:添加搜索路径,将 lua 与 .Cs 脚本的路径,添加至搜索范围
注意: 只有先添加了AddSearchPath()
搜索路径,才可以保证以下2个函数的正常调用
DoFile() —— 该函数:执行 ScriptsFromFile.lua
脚本
Require() —— 该函数:执行 引用 ScriptsFromFile
lua 脚本
using UnityEngine;
using LuaInterface;
///
/// Chinar解释 —— tolua官方测试案例 2
/// 展示 searchpath 使用,require 与 dofile 区别
///
public class ScriptsFromFile : MonoBehaviour
{
LuaState lua = null;
private string strLog = "";
void Start()
{
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived += Log;
#else
Application.RegisterLogCallback(Log);
#endif
lua = new LuaState();
lua.Start();
//如果移动了ToLua目录,自己手动修复吧,只是例子就不做配置了
//string fullPath = Application.dataPath + "\\ToLua/Examples/02_ScriptsFromFile"; //这是官方默认路径,需要自己修改为自己的
string fullPath = Application.dataPath + "\\LuaFramework/ToLua/Examples/02_ScriptsFromFile";
lua.AddSearchPath(fullPath); //添加搜索路径,将lua与.Cs脚本的搜索路径,添加至搜索范围
}
void Log(string msg, string stackTrace, LogType type)
{
strLog += msg;
strLog += "\r\n";
}
void OnGUI()
{
GUI.Label(new Rect(100, Screen.height / 2 - 100, 600, 400), strLog);
if (GUI.Button(new Rect(50, 50, 120, 45), "DoFile")) //点击 DoFile 按钮
{
strLog = "";
lua.DoFile("ScriptsFromFile.lua"); //执行 ScriptsFromFile.lua 脚本
}
else if (GUI.Button(new Rect(50, 150, 120, 45), "Require")) //点击 Requre 按钮
{
strLog = "";
lua.Require("ScriptsFromFile"); //执行 引用 ScriptsFromFile 脚本
}
lua.Collect(); //收集GC
lua.CheckTop(); //检验
}
///
/// 程序退出时
///
void OnApplicationQuit()
{
lua.Dispose(); //释放
lua = null; //质空
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived -= Log;
#else
Application.RegisterLogCallback(null);
#endif
}
}
GetFunction() —— 该函数:获取lua
中指定test类的luaFunc
函数
注意: 只有先添加了AddSearchPath()
搜索路径,才可以保证以下2个函数的正常调用
DoFile() —— 该函数:执行 ScriptsFromFile.lua
脚本
Require() —— 该函数:执行 引用 ScriptsFromFile
lua 脚本
using UnityEngine;
using LuaInterface;
using System;
///
/// Chinar解释 —— tolua官方测试案例 3
/// C#调用lua函数
///
public class CallLuaFunction : MonoBehaviour
{
private string script =
@" function luaFunc(num)
return num + 1
end
test = {}
test.luaFunc = luaFunc
function ChinarTest()
print('通过lua对象获取函数')
end
";
LuaFunction luaFunc = null;
LuaState lua = null;
string tips = null;
void Start()
{
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived += ShowTips;
#else
Application.RegisterLogCallback(ShowTips);
#endif
new LuaResLoader();
lua = new LuaState();
lua.Start();
DelegateFactory.Init();
lua.DoString(script);
luaFunc = lua.GetFunction("test.luaFunc"); //获取test中的luaFunc函数
if (luaFunc != null)
{
//第一种方法 —— luaFunc.Invoke
int num = luaFunc.Invoke<int, int>(123456); //调用函数返回int值
Debugger.Log("generic call return: {0}", num); //123457
//第二种方法
luaFunc.BeginPCall();
luaFunc.Push(123456);
luaFunc.PCall();
num = (int) luaFunc.CheckNumber();
luaFunc.EndPCall();
Debugger.Log("expansion call return: {0}", num); //123457
//第三种方法 —— 委托调用
Func<int, int> Func = luaFunc.ToDelegate<Func<int, int>>();
num = Func(123456);
Debugger.Log("Delegate call return: {0}", num); //123457
//第四种方法 —— lua.Invoke
num = lua.Invoke<int, int>("test.luaFunc", 123456, true);
Debugger.Log("luastate call return: {0}", num); //123457
//第五种方法 —— LuaFunction . Call()
LuaFunction func = lua["ChinarTest"] as LuaFunction; //lua对象 转 lua函数
func.Call(); //调用lua TestFunc 函数
func.Dispose();
}
lua.CheckTop();
}
void ShowTips(string msg, string stackTrace, LogType type)
{
tips += msg;
tips += "\r\n";
}
#if !TEST_GC
void OnGUI()
{
GUI.Label(new Rect(Screen.width / 2 - 200, Screen.height / 2 - 150, 400, 300), tips);
}
#endif
void OnDestroy()
{
if (luaFunc != null)
{
luaFunc.Dispose();
luaFunc = null;
}
lua.Dispose();
lua = null;
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived -= ShowTips;
#else
Application.RegisterLogCallback(null);
#endif
}
}
注意: lua["变量名"]
—— 通过这种方式对 lua 中的变量进行访问
lua["TestFunc"] as LuaFunction
—— LuaState
对象 转 LuaFunction
,调用 lua 中 TestFunc
函数
lua.GetTable("lua 中的表名")
—— 获取 lua 中的表,返回类型为LuaTable
using UnityEngine;
using LuaInterface;
///
/// Chinar解释 —— tolua官方测试案例 4
/// C#访问lua中的变量
///
public class AccessingLuaVariables : MonoBehaviour
{
private string script =
@"
print('Objs2Spawn is: '..Objs2Spawn)
var2read = 42
varTable = {1,2,3,4,5}
varTable.default = 1
varTable.map = {}
varTable.map.name = 'map'
print(varTable.map.name)
meta = {name = 'meta'}
setmetatable(varTable, meta)
function TestFunc(strs)
print('get func by variable')
end
"; //lua脚本
void Start()
{
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived += ShowTips;
#else
Application.RegisterLogCallback(ShowTips);
#endif
new LuaResLoader();
LuaState lua = new LuaState();
lua.Start();
lua["Objs2Spawn"] = 5; //对lua脚本中 Objs2Spawn 赋值 5
lua.DoString(script);
//通过LuaState访问 —— 从lua中读取 var2read 的值
Debugger.Log("Read var from lua: {0}", lua["var2read"]); //42
//LuaState 拆串式table,读取lua表中的值
Debugger.Log("Read table var from lua: {0}", lua["varTable.default"]); //1
LuaFunction func = lua["TestFunc"] as LuaFunction; //lua对象 转 lua函数
func.Call(); //调用lua TestFunc 函数
func.Dispose();
//cache成LuaTable进行访问
LuaTable table = lua.GetTable("varTable");
Debugger.Log("Read varTable from lua, default: {0} name: {1}", table["default"], table["map.name"]);//1 和 无
table["map.name"] = "new"; //table 字符串只能是key
Debugger.Log("Modify varTable name: {0}", table["map.name"]); //打印 new
table.AddTable("newmap"); //表中添加 newmap
//这里 table["newmap"] 是Object类型,所以需要强转为 LuaTable类型
LuaTable table1 = (LuaTable) table["newmap"];
table1["name"] = "table1";
Debugger.Log("varTable.newmap name: {0}", table1["name"]); //打印table1
table1.Dispose();
table1 = table.GetMetaTable(); //获取元表,并赋值
if (table1 != null)
{
Debugger.Log("varTable metatable name: {0}", table1["name"]);
}
object[] list = table.ToArray();
for (int i = 0; i < list.Length; i++)
{
Debugger.Log("varTable[{0}], is {1}", i, list[i]);
}
table.Dispose(); //释放表
lua.CheckTop(); //检验
lua.Dispose(); //释放
}
private void OnApplicationQuit()
{
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived -= ShowTips;
#else
Application.RegisterLogCallback(null);
#endif
}
string tips = null;
void ShowTips(string msg, string stackTrace, LogType type)
{
tips += msg;
tips += "\r\n";
}
void OnGUI()
{
GUI.Label(new Rect(Screen.width / 2 - 300, Screen.height / 2 - 200, 600, 400), tips);
}
}
coroutine.start(函数名)
—— 在 lua 中开启协程
coroutine.stop(函数名)
—— 停止协程
coroutine.step()
—— 等待一帧
coroutine.www(UnityEngine.WWW("http://www.baidu.com"))
—— 开启www请求
此种写法官方推荐,另一种虽然书写简单,但大量使用时执行效率低,这里都不做介绍
C# 脚本
using UnityEngine;
using LuaInterface;
///
/// Chinar解释 —— tolua官方案例 5
/// 例子5和6展示的两套协程系统勿交叉使用,此为推荐方案
///
public class TestCoroutine : MonoBehaviour
{
public TextAsset luaFile = null;
private LuaState lua = null;
private LuaLooper looper = null;
void Awake()
{
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived += ShowTips;
#else
Application.RegisterLogCallback(ShowTips);
#endif
new LuaResLoader();
lua = new LuaState();
lua.Start();
LuaBinder.Bind(lua); //绑定lua对象
DelegateFactory.Init(); //委托工厂初始化
looper = gameObject.AddComponent<LuaLooper>(); //使用协程必须添加
looper.luaState = lua; //指定对象
lua.DoString(luaFile.text, "TestLuaCoroutine.lua"); //读指定Asset中的资源文本,tolua会自动完成读取,指定文件名
LuaFunction f = lua.GetFunction("TestCortinue"); //获取 lua 脚本中 TestCortinue 对象,赋值f
f.Call(); //调用,协程在lua脚本中 启动
f.Dispose();
f = null;
}
void OnApplicationQuit()
{
looper.Destroy();
lua.Dispose();
lua = null;
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived -= ShowTips;
#else
Application.RegisterLogCallback(null);
#endif
}
string tips = null;
void ShowTips(string msg, string stackTrace, LogType type)
{
tips += msg;
tips += "\r\n";
}
void OnGUI()
{
GUI.Label(new Rect(Screen.width / 2 - 300, Screen.height / 2 - 200, 600, 400), tips);
if (GUI.Button(new Rect(50, 50, 120, 45), "Start Counter"))//开启协程
{
tips = null;
LuaFunction func = lua.GetFunction("StartDelay");
func.Call();
func.Dispose();
}
else if (GUI.Button(new Rect(50, 150, 120, 45), "Stop Counter"))//停止协程
{
LuaFunction func = lua.GetFunction("StopDelay");
func.Call();
func.Dispose();
}
else if (GUI.Button(new Rect(50, 250, 120, 45), "GC"))//回收
{
lua.DoString("collectgarbage('collect')", "TestCoroutine.cs");
Resources.UnloadUnusedAssets();
}
}
}
Lua 脚本
-------tolua官方案例:初始化时,C#调用此函数开启协程----------
function TestCortinue()
coroutine.start(CoFunc)
end
local coDelay = nil
------------------------每隔1秒打印一次输出------------------
function Delay()
local c = 1
while true do
coroutine.wait(1)
print("Count: "..c)
c = c + 1
end
end
----------------------------开启协程------------------------
function StartDelay()
coDelay=coroutine.start(Delay)
end
----------------------------停止协程------------------------
function StopDelay()
coroutine.stop(coDelay)
end
----------------------------每隔0.1秒计算一次------------------------
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')
for i = 0, 10, 1 do
print(fib(i))
coroutine.wait(0.1)--等待0.1秒
end
print("current frameCount: "..Time.frameCount)
coroutine.step()--等待一帧
print("yield frameCount: "..Time.frameCount)
local www = UnityEngine.WWW("http://www.baidu.com")
coroutine.www(www)--开启www请求
local s = tolua.tolstring(www.bytes)
print(s:sub(1, 128))
print('Coroutine ended')
end
func.Push(arrayInts)
—— 将 数组 arrayInts 传至 Lua 中
func.CheckNumber()
—— 得到 Lua 对应函数返回值中的:值类型
func.CheckString()
—— 得到 Lua 对应函数返回值中的:字符串类型
func.CheckBoolean()
—— 得到 Lua 对应函数返回值中的:布尔类型
注意: 书写顺序应该是与函数返回值先后顺序保持一致,否则会报错
C# 脚本
// ========================================================
// 描述:测试数组的调用
// 作者:Chinar
// 创建时间:2018-10-21 14:31:37
// 版 本:1.0
// ========================================================
using LuaInterface;
using UnityEngine;
///
/// Chinar解释 —— tolua官方案例8
///
public class ChinarTestArray : MonoBehaviour
{
private string script =
@"
function TestArray(array)
----------------------------获取数组长度------------------------
local len = array.Length
----------------------------遍历数组输出------------------------
for i = 0, len - 1 do
print('数组: '..tostring(array[i]))
end
----------------------------获取枚举器--------------------------
local iter = array:GetEnumerator()
----------------------调用数组函数MoveNext()--------------------
while iter:MoveNext() do
print('依次取: '..iter.Current)
end
----------------------数组转表----------------------------------
local t = array:ToTable()
for i = 1, #t do
print('转表: ' .. tostring(t[i]))
end
----------------------调用数组函数BinarySearch(3)---------------
local pos = array:BinarySearch(3)
print('数组二进制 BinarySearch: 下标是: '..pos..' 值: '..array[pos])
----------------------调用数组函数IndexOf(4)--------------------
pos = array:IndexOf(4)
print('数组 indexof 4 下标是: '..pos)
----------------------返回值参数--------------------------------
return 5, 'Chinar', true
end
";
LuaState lua = null;
LuaFunction func = null;
string tips = null;
void Start()
{
#if UNITY_2017||UNITY_2018||UNITY_5 //对应版本
Application.logMessageReceived += ShowTips; //监听输出信息函数
#else
Application.RegisterLogCallback(ShowTips);
#endif
new LuaResLoader();
tips = "";
lua = new LuaState();
lua.Start();
lua.DoString(script, "ChinarTestArray.cs"); //运行 script 字符串中的lua脚本,指定C#脚本路径
int[] arrayInts = {1, 2, 3, 4, 5};
func = lua.GetFunction("TestArray"); //取得 lua script 脚本中的 TestArray 函数
func.BeginPCall();
#region 第一种写法
func.Push(arrayInts);
func.PCall();
// 接受返回值时顺序要一一对应。 顺序写错,会报错
// 另外 int string float 这些会自动完成转换,不会报错
// 如: 10.3 —— func.CheckValua(); 这里会自动 返回 int
// 如: 1 —— func.CheckNumber();
// 如: `123` —— func.CheckString();
// 如: true —— func.CheckBoolean();
double arg1 = func.CheckNumber();
string arg2 = func.CheckString();
bool arg3 = func.CheckBoolean();
Debugger.Log("返回值:{0}|{1}|{2}", arg1, arg2, arg3);
//-------------------------------------------
func.EndPCall();
#endregion
#region 第二种通用写法
//调用通用函数需要转换一下类型,避免可变参数拆成多个参数传递
//func.LazyCall((object) arrayInts);
//相当于 ↓↓
//func.Push(arrayInts);
//func.PCall();
object[] objects = func.LazyCall((object) arrayInts);
if (objects != null)
{
Debugger.Log("return is {0} {1} {2}", objects[0], objects[1], objects[2]);
}
func.EndPCall();
lua.CheckTop(); //检查返回值
#endregion
}
void OnGUI()
{
GUI.Label(new Rect(Screen.width / 2 - 300, Screen.height / 2 - 300, 600, 600), tips);
}
///
/// 显示输出提示
///
private void ShowTips(string msg, string stacktrace, LogType type)
{
tips += msg; //信息
tips += "\r\n"; //换行
}
private void OnApplicationQuit()
{
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived -= ShowTips;
#else
Application.RegisterLogCallback(null);
#endif
func.Dispose();
lua.Dispose();
}
}
map.Add(1, new TestAccount(1, "水水", 0));
—— 字典中添加元素:利用构造函数,新建测试账号对象时,在对象中直接完成赋值
注意:
这对于初学者是一个老生常谈的问题了
Lua 中调用C#函数用“:”,字段用“.”
: —— map:GetEnumerator()
/iter:MoveNext()
. ——iter.Current.name
/map.Keys
C# 脚本
using UnityEngine;
using System.Collections.Generic;
using LuaInterface;
///
/// Chinar解释 —— tolua官方案例9
/// Lua中使用字典
///
public sealed class TestAccount
{
public int id;
public string name;
public int sex;
///
/// 构造函数
///
public TestAccount(int id, string name, int sex)
{
this.id = id;
this.name = name;
this.sex = sex;
}
}
public class UseDictionary : MonoBehaviour
{
private Dictionary<int, TestAccount> map = new Dictionary<int, TestAccount>();
string script =
@"
function TestDict(map)
------------调用字典函数GetEnumerator()---------------
local iter = map:GetEnumerator()
-------------调用字典函数MoveNext()-------------------
while iter:MoveNext() do
local v = iter.Current.Value
print('id: '..v.id .. ' name: '..v.name..' sex: '..v.sex)
end
-------------调用字典函数TryGetValue()-----------------
local flag, account = map:TryGetValue(1, nil)
if flag then
print('TryGetValue 返回结果正确时: '..account.name)
end
--------------------获取字典中的键---------------------
local keys = map.Keys
iter = keys:GetEnumerator()
print('------------打印输出字典中的键---------------')
while iter:MoveNext() do
print(iter.Current)
end
print('----------------------over----------------------')
local values = map.Values
iter = values:GetEnumerator()
print('------------打印输出字典中的值---------------')
while iter:MoveNext() do
print(iter.Current.name)
end
print('----------------------over----------------------')
-----------获取字典中2键对应的name值---------------------
print('kick '..map[2].name)
-----------移除map中下标2对应的元素---------------------
map:Remove(2)
iter = map:GetEnumerator()
-----------重新输出---------------------
while iter:MoveNext() do
local v = iter.Current.Value
print('id: '..v.id .. ' name: '..v.name..' sex: '..v.sex)
end
end
";
void Awake()
{
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived += ShowTips;
#else
Application.RegisterLogCallback(ShowTips);
#endif
new LuaResLoader();
map.Add(1, new TestAccount(1, "水水", 0));
map.Add(2, new TestAccount(2, "王伟", 1));
map.Add(3, new TestAccount(3, "王芳", 0));
LuaState luaState = new LuaState();
luaState.Start();
BindMap(luaState);
luaState.DoString(script, "UseDictionary.cs");
LuaFunction func = luaState.GetFunction("TestDict");
func.BeginPCall();
func.Push(map);
func.PCall();
func.EndPCall();
func.Dispose();
func = null;
luaState.CheckTop();
luaState.Dispose();
luaState = null;
}
void OnApplicationQuit()
{
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived -= ShowTips;
#else
Application.RegisterLogCallback(null);
#endif
}
string tips = "";
void ShowTips(string msg, string stackTrace, LogType type)
{
tips += msg;
tips += "\r\n";
}
void OnGUI()
{
GUI.Label(new Rect(Screen.width / 2 - 300, Screen.height / 2 - 200, 600, 400), tips);
}
//示例方式,方便删除,正常导出无需手写下面代码
//Chinar:这里不用管,这是tolua作者为方便我们删除示例预留的代码
//为了保证删除示例是,不影响我们的整体工程的其他 wrap 文件
void BindMap(LuaState L)
{
L.BeginModule(null);
TestAccountWrap.Register(L);
L.BeginModule("System");
L.BeginModule("Collections");
L.BeginModule("Generic");
System_Collections_Generic_Dictionary_int_TestAccountWrap.Register(L);
System_Collections_Generic_KeyValuePair_int_TestAccountWrap.Register(L);
L.BeginModule("Dictionary");
System_Collections_Generic_Dictionary_int_TestAccount_KeyCollectionWrap.Register(L);
System_Collections_Generic_Dictionary_int_TestAccount_ValueCollectionWrap.Register(L);
L.EndModule();
L.EndModule();
L.EndModule();
L.EndModule();
L.EndModule();
}
}
LuaBinder.Bind(lua);
—— 首先这一步不能少
lua["space"] = Space.World;
—— Lua 脚本中的 space 变量,进行枚举类型赋值
C# 脚本
using UnityEngine;
using LuaInterface;
///
/// Chinar解释 —— tolua官方案例 10
/// Lua中使用Unity枚举类型
///
public class AccessingEnum : MonoBehaviour
{
string script =
@"
space = nil
function TestEnum(e)
print('枚举是:'..tostring(e))
----------------枚举类型转int----------------
if space:ToInt() == 0 then
print('枚举转Int成功')
end
-------------枚举类型int与0比较--------------
if not space:Equals(0) then
print('枚举类型(与int型)比较成功')
end
-------------枚举类型直接比较----------------
if space == e then
print('枚举类型比较成功')
end
-------调用Unity中的Space枚举值转枚举--------
local s = UnityEngine.Space.IntToEnum(0)
if space == s then
print('int转枚举,比较成功')
end
end
----------------改变Unity光照类型---------------
function ChangeLightType(light, type)
print('改变光照类型为: '..tostring(type))
light.type = type
end
";
LuaState state = null;
string tips = "";
int count = 1;
///
/// 格式化打印输出
///
void ShowTips(string msg, string stackTrace, LogType type)
{
tips += msg;
tips += "\r\n";
}
///
/// 初始化函数
///
void Start()
{
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived += ShowTips;
#else
Application.RegisterLogCallback(ShowTips);
#endif
new LuaResLoader();
state = new LuaState();
state.Start();
LuaBinder.Bind(state); //绑定,必须要写
state.DoString(script);
state["space"] = Space.World; //Lua脚本中的space变量,进行枚举类型赋值
LuaFunction func = state.GetFunction("TestEnum");
func.BeginPCall();
func.Push(Space.World);
func.PCall();
func.EndPCall();
func.Dispose();
func = null;
}
///
/// 绘制函数
///
void OnGUI()
{
GUI.Label(new Rect(Screen.width / 2 - 300, Screen.height / 2 - 200, 600, 400), tips);
if (GUI.Button(new Rect(0, 60, 120, 50), "ChangeType"))
{
Light light = GameObject.Find("/Light").GetComponent<Light>(); //获取层次列表中对象的Light组件
LuaFunction func = state.GetFunction("ChangeLightType");
func.BeginPCall();
func.Push(light); //将light传入ChangeLightType函数
LightType type = (LightType) (count++ % 4); //简单计算得到类型
func.Push(type); //将type类型传入ChangeLightType函数
func.PCall(); //调用ChangeLightType函数
func.EndPCall();
func.Dispose();
}
}
///
/// 应用退出时执行函数
///
void OnApplicationQuit()
{
state.CheckTop();
state.Dispose();
state = null;
#if UNITY_5 || UNITY_2017 || UNITY_2018
Application.logMessageReceived -= ShowTips;
#else
Application.RegisterLogCallback(null);
#endif
}
}
输出:
项目文件为 unitypackage 文件包:
下载导入 Unity 即可使用
点击下载 —— 项目资源 (积分支持)
点击下载 —— 项目资源 (Chinar免费)
拥有自己的服务器,无需再找攻略! Chinar 提供一站式教程,闭眼式创建! 为新手节省宝贵时间,避免采坑! |
先点击领取 —— 阿里全产品优惠券 (享受最低优惠)
1 —— 云服务器超全购买流程 (新手必备!)
2 —— 阿里ECS云服务器自定义配置 - 购买教程(新手必备!)
3—— Windows 服务器配置、运行、建站一条龙 !
4 —— Linux 服务器配置、运行、建站一条龙 !
本博客为非营利性个人原创,除部分有明确署名的作品外,所刊登的所有作品的著作权均为本人所拥有,本人保留所有法定权利。违者必究
对于需要复制、转载、链接和传播博客文章或内容的,请及时和本博主进行联系,留言,Email: [email protected]
对于经本博主明确授权和许可使用文章及内容的,使用时请注明文章或内容出处并注明网址