Lua学习,自我问题总结

Lua基础

1、如果想获取某个lua文件的表。记得在该lua文件创建一个方法New,return 这个表。或者直接在lua文件末尾return
2、tolua在C#里经过Dofile的文件,只要全局变量,都能直接获取并进行使用。比如Dofile了Music.lua和Control.lua。Control.lua文件里能直接调用Music表里的函数
3、require也是加载lua文件的方法,但比dofile更好。
有两个优点:
(1) require会搜索目录加载文件
(2) require会判断是否文件已经加载避免重复加载同一文件。
4、静态方法、静态变量、成员变量、成员属性均使用 “.” 来访问,成员方法使用 “:” 来访问。
表用“:”来添加方法,会将自身“self”传入方法内,“.”则需要手动传入。
5、lua带参数方法,可以不传入参数执行,但默认参数为nil
6、setmetatable具有返回值,返回值为setmetatable(o,self)里的o
7、lua中的多线程
8、pairs 和 ipairs区别
(1)pairs可以遍历表中所有的key,并且除了迭代器本身以及遍历表本身还可以返回nil;
(2)ipairs则不能返回nil,只能返回数字0,如果遇到nil则退出。它只能遍历到表中出现的第一个不是整数的key
分为两种情况:
第一种是有整数1、3没有2那么,遍历完1退出遍历
第二种是遇见非整数key,则直接退出遍历
具体情况如下

local tabFiles = {
[1] = "?",
two = "2",
[3] = "test2",
[6] = "test3",
[4] = "test1"
}
for k, v in ipairs(tabFiles) do
	print(k, v)
end--打印结果仅为“1	?-----------------如果用pairs
for k, v in pairs(tabFiles) do
	print(k, v)
end--打印结果为“1 ?|two 2|3 test2|6 test3|4 test1

8、深拷贝(DeepCopy),目前理解主要应用是针对表
(1)什么是拷贝?就是创建出一个和本体一样的副本,并且对副本的任何操作都不影响本体!
(2)浅拷贝,又叫Shallow Copy,只复制对象的基本类型,对象类型仍属于原来的引用。深拷贝,又叫Deep Copy,不仅复制对象的基本类型,同时也复制原对象中的对象,完全产生新对象。
(3)
赋值拷贝:nil、boolean、number、string、function经过以下拷贝,创建出跟本体一样的副本,但对副本的任意操作都不影响本体。
非赋值拷贝:然而在 lua 中并不是所有类型的变量都可以通过直接赋值来实现这样的拷贝——比如 table 、userdata、thread类型(其中table相当于把表索引给赋值过去了)就不行。lua深拷贝学习参考

q=true
w=q
w=false
print(q)--打印出来值为true
------------
q={i=1}
w=q
w["i"]=2
print(q["i"])--打印结果为2

(4)lua中Table它不能简单通过赋值进行拷贝,而是需要创建一个新的 table 并将原 table 的 key-value 递归拷贝,实现方法如下

function DeepCopy(object)
	local searchTable={}

	local function Copy(object)--假设这个object就是个表
		if(type(object)~="table") then--如果不是一个表返回值
			return object
		--elseif searchTable[object] then--感觉可以不要这一段
			--return searchTable
		end

		local newTable={}--创建一个新表
		searchTable[object]=newTable--
		for	key,value in pairs(object) do--object的元素copy进新表里
			newTable[Copy(key)] = Copy(value)--递归调用,参数不是表直接返回值,是表则再次递归
		end
		return setmetatable(newTable,getmetatable(object))
	end

	return Copy(object)
end

lua的面向对象

1、实现类的实例化

Person={name="?"}
p1=Person--这样就实例化了一个Person
p1.name="p1";
p2=Psrson--但批量实例化Person。其实算浅拷贝,既变量索引都指向同一个
p2.name="p2"
print(p1.name..p2.name)--打印结果都是p2.正确实例化以及继承都需要用到元表,具体实现看以下实现代码

2、lua创建如何一个类,以及如何继承
表可以看错C#一个类,以下主要是实现如何继承
(1)官方做法,使用元表实现
其原理是:根据以下Object的new函数,当继承他的子类,成员调用不存在的函数时候都会去self查找,如果有同名方法,则覆盖。

Object = {class_id = 0}
function Object:new(o)
    o = o or {}
    setmetatable(o,self) -- 对象o调用不存在的成员时都会去self中查找,而这里的self指的就是Object
    self.__index = self--
	return o
end
function Object.Test(str)
	print(str)
end
---以下我们创建对象来测试以下
local o1 = Object:new()
o1.class_id = 11;
local o2 = Object:new()
o2.class_id = 22;
print(o1.class_id..":"..o2.class_id)
print(o1.Test("3333"))
print(o2.Test("4444"))
--打印结果为11:2233334444。可发现调用均为Object函数的成员变量和函数
-----------------------分割线----------------------------
DisplayObject = Object:new()
-- 现在为止,DisplayObject只是Object的一个实例,注意以下代码
function DisplayObject:new(width,height)
	print(width..":"..height)
	--o=Object:new();--还可以这么写调用父类初始化方法,暂时不知道有没有更好的办法
	--return o;
end

DisplayObject:new(3,4)
--调用该方法得出结果为“34”,此时就没调用Object里的new方法,而是覆盖后的方法

(2)复制表的方式
首先创建一个克隆表(CloneTab)的方法
再创建基类,以及new方法
创建一个拷贝(Copy)方法
将父类方法都Copy进子类方法里

function cloneTab(tab)
	local ins ={}
	for key,var in pairs(tab) do
		ins[key] = var ;
	end
	return ins;
end
-----------------
Object = {class_id=1}

function Object.new()
	local o = cloneTab(Object);
	return o;
end

local p=Object.new()
print(p.class_id)--打印出参数是1
------------------
function copy(dist,tab)
	for key,var in pairs(tab) do
		dist[key]=var
	end
end
------------------
DisplayObject={value=3}

function DisplayObject.new()
	local ss = Object.new()
	copy(ss,DisplayObject)
	return ss
end

local p1 = DisplayObject.new()
print(p1.value.."--"..p1.class_id)--打印出参数是3--1

(3)使用函数闭包的形式实现面向对象(感觉这是最不理想的方案…)

function People(name)
	local self={}
	local function init()
		self.name=name
	end

	self.SayHi=function()
		print("????"..self.name)
	end

	init()
	return self
end

local p =People("HTY")
p:SayHi()

function Man(name)
	local self = People(name);

	self.SayHello=function()
		print("hi"..self.name)
	end

	return self
end

local m=Man("List")

m.SayHi()

ToLua

案例学习

1、C#调用Lua方法

//(1)有回调方法
	LuaState lua = new LuaState();
	LuaFunction luaFunc;
    int CallFunc()
    {        
    	luaFunc = lua.GetFunction("方法名称");
        luaFunc.BeginPCall();
        luaFunc.Push(123456);//有多个参数需要传递就再写Push
        luaFunc.PCall();   
        int num = (int)luaFunc.CheckNumber();
        luaFunc.EndPCall();
        return num;                
        //luaFunc.Invoke();//这是luaFUnc自带回调方法,只有传参方法不一样
    }
//(2)没回调方法
	//基本跟上面一样,除了没回调方法,自带方法调用LuaFcuc.Call()即可

2、C#对lua变量访问(平时很少用)

LuaState lua = new LuaState();
void GetValue()
{
	//使用LuaState访问器
	lua["全局属性名"];
	lua["表名.属性名"]//通过LuaTable
    LuaTable table = lua.GetTable("varTable");//获取表
    table["map.name"] = "new";  //table 字符串只能是key
    table["map.name"]);//获取表中标的属性

    table.AddTable("newmap");//添加表
    LuaTable table1 = (LuaTable)table["newmap"];
    table1["name"] = "table1";
}

3、协程

//lua文件
function Delay()
	local c = 1
	local url = www("网络请求地址");//协程执行www
	coroutine.www(url);
	url : GetAudioClip();//获取声音片段,这个看unityApi
	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
//C#文件
void MyFunc()
{
	lua  = new LuaState();
	lua.Start();
	LuaBinder.Bind(lua);
	DelegateFactory.Init();         
	looper = gameObject.AddComponent<LuaLooper>();
	looper.luaState = lua;

	LuaFunction func = lua.GetFunction("StartDelay");
	func.Call();//执行协程方法
}

4、lua线程,不是真的线程,只是开启了一个迭代器,等需要使用的时候再去研究
5、lua访问C#数组,且如何获取lua方法多个返回值

//lua脚本
function TestArray(array)
	local len = array.Length 
	for i = 0, len - 1 do
		print('Array: '..tostring(array[i]))
	end  
	return 1, '123', true
end            
//c#
void MyFunc()
{	
	int[] array = { 1, 2, 3, 4, 5 };
    func = lua.GetFunction("TestArray");
    func.BeginPCall();
    func.Push(array);
    func.PCall();
    double arg1 = func.CheckNumber();
    string arg2 = func.CheckString();
    bool arg3 = func.CheckBoolean();
    Debugger.Log("return is {0} {1} {2}", arg1, arg2, arg3);//获取lua方法3个返回值
    func.EndPCall();
}

6、Tolua如何使用C#的字典

//lua代码
function TestDict(map)      
	//字典遍历                  
	local iter = map:GetEnumerator() 
	while iter:MoveNext() do
	    local v = iter.Current.Value
	    print('id: '..v.id ..' name: '..v.name..' sex: '..v.sex)                                
	end
	
	//根据key获取Value
	local flag, account = map:TryGetValue(1, nil)
	if flag then
	    print('TryGetValue result ok: '..account.name)
	end
	
	//获取keys
	local keys = map.Keys
	iter = keys:GetEnumerator()
	print('------------print dictionary keys---------------')
	while iter:MoveNext() do
	    print(iter.Current)
	end
	print('----------------------over----------------------')
	
	//获取Values
	local values = map.Values
	iter = values:GetEnumerator()
	print('------------print dictionary values---------------')
	while iter:MoveNext() do
	    print(iter.Current.name)
	end
	print('----------------------over----------------------')                
	
	//移除
	print('kick '..map[2].name)
	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                        

7、toLua访问C#枚举

//lua文件,首先要将枚举注册才能使用
function ChangeLightType(light, type)
	print('change light type to '..tostring(type))
	light.type = type
end
//C#
void MyFunc()
{
	GameObject go = GameObject.Find("/Light");
    Light light = go.GetComponent<Light>();
    LuaFunction func = state.GetFunction("ChangeLightType");
    func.BeginPCall();
    func.Push(light);
    LightType type = (LightType)(count++ % 4);
    func.Push(type);
    func.PCall();
    func.EndPCall();
    func.Dispose();
{

8、委托和事件
(1)想要在toLua中使用委托,首先需要在CustomSettings中注册对应委托(后面版本的tolua不用手动注册了),然后在代码开始开启的时候激活委托

//lua代码
function SetClick1(listener)
	if listener.onClick then//自定义的一个委托,如果委托不为空
	     listener.onClick:Destroy()//删除委托
	end
	listener.onClick = DoClick1//添加委托
end
function AddClick1(listener)       
	if listener.onClick then
	    listener.onClick = listener.onClick + DoClick1//添加委托
	else
	    listener.onClick = DoClick1
	end                
end
function RemoveClick1(listener)
	if listener.onClick then
	    listener.onClick = listener.onClick - DoClick1//移除委托
	else
	    print('empty delegate')
	end
end
function DoClick1(go)                
	print('click1 gameObject is '..go.name)                    
end

function AddEvent(listener)//添加事件
   listener.onClickEvent = listener.onClickEvent + TestEvent
end

function RemoveEvent(listener)//删除事件
    listener.onClickEvent = listener.onClickEvent - TestEvent
end
function TestEvent()
	print('this is a event')
end

//C#代码
//正常注册在lua里的普通方法,不同的委托类型也需要单独注册(现在框架作者已经帮忙做了这个事了)
public class TestEvent : MonoBehaviour
{
    public event Action<GameObject> onClickEvent = delegate { };
    public Action<GameObject> onClick=delegate { print("初始空方法"); };

    [NoToLuaAttribute]
    public void OnClickEvent(GameObject go)
    {
        onClickEvent(go);
    }
}
//C#调用文件,放一个举例就ok
void AddDelegate()
{
	if(AddClick1==null)
		AddClick1 = state.GetFunction("AddClick1");
	CallLuaFunction(AddClick1);
}
void CallLuaFunction(LuaFunction func)
{
    func.BeginPCall();
    func.Push(listener);
    func.PCall();
    func.EndPCall();
}

9、在toLua中创建GameObject

//lua代码
//将C#注册进lua的方法重命名
local Color = UnityEngine.Color
local GameObject = UnityEngine.GameObject
local ParticleSystem = UnityEngine.ParticleSystem 
//DoTween完成后的回调方法
function OnComplete()
    print('OnComplete CallBack')
end                       

local go = GameObject('go')
go:AddComponent(typeof(ParticleSystem))//添加粒子组件
local node = go.transform
node.position = Vector3.one                  
--go.transform:DOPath({Vector3.zero, Vector3.one * 10}, 1, DG.Tweening.PathType.Linear, DG.Tweening.PathMode.Full3D, 10, nil)
--go.transform:DORotate(Vector3(0,0,360), 2, DG.Tweening.RotateMode.FastBeyond360):OnComplete(OnComplete)            
GameObject.Destroy(go, 2)
go.name = '123'

//C#
void Update()
{
    lua.CheckTop();//不用也能正常执行
    lua.Collect();//没有这个代码就不会执行GameObject.Destroy(go, 2)
    //或者有LuaLooper loop=gameObject.AddComponent<LuaLooper>().luaState = lua;也可以,这个不放循环里
}

10、toLua调用C#带有out/ref的方法如何取值

//lua脚本
local box = UnityEngine.BoxCollider
                                                                            
function TestPick(ray)    
    local num= 998//待传递ref值
    local num1,num2=TestEvent.RefFunc(num);
    print(num1..'----'..num2) //打印结果100,20                                                             
	local _layer = 2 ^ LayerMask.NameToLayer('Default')                
	local time = os.clock()                                                  
	local flag, hit = UnityEngine.Physics.Raycast(ray, nil, 5000, _layer)//第一个为方法返回值,第二个为out返回值
	--local flag, hit = UnityEngine.Physics.Raycast(ray, RaycastHit.out, 5000, _layer)//这样也可以,但我没明白RayCastHit.out这参数是怎么编译的                                
	                
	if flag then
	    print('pick from lua, point: '..tostring(hit.point))                                        
	end
end

//C#
public class TestEvent
{
	public static int RefFunc(ref int num)
	{
	   num = 20;
	   return 100;
	}
}

11、(15_ProtoBuffer暂时没看懂,也不知道有啥用)
12、toLua解析Json文件(感觉还不如C#里写工具类调用LitJson)

//lua文件
local json = require 'cjson'

function Test(str)
	local data = json.decode(str)
	   print(data.glossary.title)
	s = json.encode(data)
	print(s)
end

13、toLua中调用C#String,Int32

string = System.String
int = System.Int32
function Test(num)
    str1='男儿当自强';//lua的String,并不能调用C#String方法
    int1= int.New();//创建一个int32值为0,放入参数还是0原因暂不知
    int1=3;
    print(int1)
    print(string.IsNullOrEmpty(str1))//可以用C#的静态方法判断lua的String
    local str = System.String.New('男儿当自强')//C#的String创建
    --print(str:Remove(3))//成员方法调用
    local index = str:IndexOfAny('儿自')
    print('and index is: '..index)
    local buffer = str:ToCharArray()
    print('str type is: '..type(str)..' buffer[0] is ' .. buffer[0])
    local luastr = tolua.tolstring(buffer)
    print('lua string is: '..luastr..' type is: '..type(luastr))
    luastr = tolua.tolstring(str)
    print('lua string is: '..luastr)                    
end

14、toLua里List的使用(感觉跟在C#用着没什么区别…感谢toLua作者大大)
//需要导出委托类型如下:
//System.Predicate
//System.Action
//System.Comparison

#lua代码
function Exist2(v)
	return v == 2
end
function IsEven(v)
	return v % 2 == 0
end
function Test(list,list1)
	list:Add(123);
	print(list[0]);
	list:AddRange(list1);
	index = list:IndexOf(123);
	local pos = list:BinartSearch(123);
	print(list:Contains(123));
	local f = list:Find(Exist2);
	local fa = list:FindAll(IsEven);
	list:Remove(123);
	list:Insert(0,123);
	list:RemoveAt(0);
	list:Insert(0, 123);
	--注意推导后的委托声明必须注册, 这里是System.Predicate<int>
	local index = list:FindIndex(System.Predicate_int(Exist2))
	list:Clear();
end

x.零散知识
(1)重要方法lua.AddSearchPath ,通过此方法添加lua文件的路径,只有添加了文件路径之后,在该路径上的lua文件才可以被读取
(2)使用完lua虚拟机之后记得要销毁,具体操作如下:先进行lua虚拟机栈的判空(不知道是不是指还有没运行完代码意思),具体对应的就是lua.CheckTop , 然后就是析构掉lua虚拟机,具体方法为lua.Dispose
(3)lua 中强制类型转换,暂时没测试能不能对注册的C#类有用
tolua.cast(object,”CCSprite”)

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值