cocos lua遇到的一些问题

做完lua版棋牌游戏,下面把我遇到的一些问题记录下。

一、确定版本

关于版本问题真的要好好计划下,目前苹果官方下达通牒,所有app必须支持IPv6。而lua热更新机制是去请求网站,低版本可能不支持IPv6,因此开发的时候务必要选择支持IPv6的cocos版本。这个问题不多说,自己可以模拟下IPv6网段,去试试便知。

开发版本是cocos2d-x 3.2(支持不支持IPv6目前还没有测试,因此最好开发时选择最新版本)
打开lua当前项目文件夹/frameworks/cocos2d-x/cocos/cocos2d.cpp文件
const char* cocos2dVersion()
{
    return "cocos2d-x 3.2";
}
这段代码就表示版本号



二、常用cocos方法

1)cc.FileUtils:getInstance():setSearchPaths(searchPaths) -- 添加搜索路径

e.g.
local fileUtils = cc.FileUtils:getInstance()
	local searchPaths = {}
	local resPrefix = "res/"
	table.insert(searchPaths, 1, resPrefix .. "图片名")
	...
	table.insert(searchPaths, 1, resPrefix .. "abc...d/图片名")
	fileUtils:setSearchPaths(searchPaths)

2)cc.Director:getInstance():getTextureCache():addImageAsync(magePath, callback)

e.g.
cc.Director:getInstance():getTextureCache():addImageAsync("图片名",handler(self, self.AsyncLoaded))
	cc.Director:getInstance():getTextureCache():addImageAsync("图片名",function () self:AsyncLoaded() end)

注意: handler(obj, method)方法在version cocos2d-x 3.2 是没有的(这个方法是quick-3.3里的方法),下面把他添加到当前版本里,打开extern.lua在最后添加如下代码
实际上,除了 C++ 回调 Lua 函数之外,在其他所有需要回调的地方都可以使用handler(obj, method)方法
function handler(obj, method)
return function(...)
return method(obj, ...)
end
end
很明显handler(obj, method)方法,只不过是把function封装了下,跟function () self:AsyncLoaded() end调用时一样的。

3)cc.Director:getInstance():getVisibleSize() -- 手机可视尺寸

4)cc.UserDefault:getInstance():getBoolForKey("字段名", false) 
      cc.UserDefault:getInstance():setBoolForKey("字段名", true)

e.g.
local m_bUserInit = cc.UserDefault:getInstance():getBoolForKey("USER_INIT", false)
	if not m_bUserInit then
		cc.UserDefault:getInstance():setBoolForKey("USER_INIT", true)
		cc.UserDefault:getInstance():setBoolForKey("BackMusic", true)
		cc.UserDefault:getInstance():setBoolForKey("GameMusic", true)
	end

5)cc.Director:getInstance():getScheduler():scheduleScriptFunc(handler(self, self.Login), 0.1, false)

注意:这个方面有2个坑:
参数一:刷新函数
参数二:每次刷新的时间间隔
参数三:是否只执行一次。false为无限次。
1、scheduleScriptFunc第3个参数,只有设置false才执行,true不执行(不是只执行一次)
2、这个定时器除非手动关闭,就算整个场景销毁,也无法关闭(比如在某个场景开启定时器,切换到另个场景,这个场景里的定时器还是运行的)。

没关系,我们可以用动作来完成所需功能:
local delay = cc.DelayTime:create(delay)
	local sequence = cc.Sequence:create(delay, cc.CallFunc:create(callback)
	local action = cc.RepeatForever:create(sequence)
	node:runAction(action)
	-- delay = 1 那么就表示:每1S执行一次callback回调函数
	-- local action = cc.RepeatForever:create(sequence)出掉node:runAction(sequence) 就表示只执行一次

后来才发现原来版本里是有这个函数的:extern.lua里的schedule(node, callback, delay)可以自己试试(我没试)

6)动作:

1、cc.BezierTo:create(time, bezier)方法

e.g.
local bezier = {cc.p(x1,y1), cc.p(x2,y2), cc.p(x3,y3),}
		local pSeqBack = cc.Sequence:create(cc.BezierTo:create(time, bezier))
		node:runAction(pSeqBack)

注意:同样BezierTo(obj, method)方法在version cocos2d-x 3.2是没有的。。。quick-3.3有!

添加BezierTo有3步:

1)打开lua当前项目文件夹/cocos2d-x/cocos/scripting/lua-bindings/manual/lua_cocos2dx_manual.cpp
搜索BezierBy,ctrl+c,ctrl+v到BezierBy下面(有兴趣可以看看这2个方法的区别)

int tolua_cocos2d_BezierTo_create(lua_State* tolua_S)
	{
		if (NULL == tolua_S)
			return 0;
		
		int argc = 0;
		bool ok = true;
		
	#if COCOS2D_DEBUG >= 1
		tolua_Error tolua_err;
		if (!tolua_isusertable(tolua_S,1,"cc.BezierTo",0,&tolua_err)) goto tolua_lerror;
	#endif
		
		argc = lua_gettop(tolua_S) - 1;
		
		if (argc == 2)
		{
			double t = 0.0;
			ok &= luaval_to_number(tolua_S, 2, &t);
			if (!ok)
				return 0;
			
			int num = 0;
			cocos2d::Vec2 *arr = NULL;
			ok &= luaval_to_array_of_vec2(tolua_S, 3, &arr, &num);
			if (!ok)
				return 0;
			
			if (num < 3)
			{
				CC_SAFE_DELETE_ARRAY(arr);
				return 0;
			}
			
			ccBezierConfig config;
			config.controlPoint_1 = arr[0];
			config.controlPoint_2 = arr[1];
			config.endPosition = arr[2];
			CC_SAFE_DELETE_ARRAY(arr);
			
			BezierTo* tolua_ret = BezierTo::create(t, config);
			if (NULL != tolua_ret)
			{
				int nID = (tolua_ret) ? (int)tolua_ret->_ID : -1;
				int* pLuaID = (tolua_ret) ? &tolua_ret->_luaID : NULL;
				toluafix_pushusertype_ccobject(tolua_S, nID, pLuaID, (void*)tolua_ret,"cc.BezierTo");
				return 1;
			}
		}
		
		CCLOG("'create' has wrong number of arguments: %d, was expecting %d\n", argc, 2);
		return 0;
		
	#if COCOS2D_DEBUG >= 1
	tolua_lerror:
		tolua_error(tolua_S,"#ferror in function 'create'.",&tolua_err);
		return 0;
	#endif
	}

2)搜索BezierBy,ctrl+c,ctrl+v到BezierBy下面(有兴趣可以看看这2个方法的区别)

static void extendBezierTo(lua_State* tolua_S)
	{
		lua_pushstring(tolua_S,"cc.BezierTo");
		lua_rawget(tolua_S,LUA_REGISTRYINDEX);
		if (lua_istable(tolua_S,-1))
		{
			lua_pushstring(tolua_S,"create");
			lua_pushcfunction(tolua_S,tolua_cocos2d_BezierTo_create);
			lua_rawset(tolua_S,-3);
		}
		lua_pop(tolua_S, 1);
	}

3)打开lua当前项目文件夹/frameworks/cocos2d-x/cocos/scripting/lua-bindings/auto/lua_cocos2dx_auto.cpp
搜索BezierBy,ctrl+c,ctrl+v到BezierBy下面(有兴趣可以看看这2个方法的区别)

static int lua_cocos2dx_BezierTo_finalize(lua_State* tolua_S)
	{
		printf("luabindings: finalizing LUA object (BezierTo)");
		return 0;
	}


	int lua_register_cocos2dx_BezierTo(lua_State* tolua_S)
	{
		tolua_usertype(tolua_S,"cc.BezierTo");
		tolua_cclass(tolua_S,"BezierTo","cc.BezierTo","cc.BezierBy",nullptr);


		tolua_beginmodule(tolua_S,"BezierTo");
		tolua_endmodule(tolua_S);
		std::string typeName = typeid(cocos2d::BezierTo).name();
		g_luaType[typeName] = "cc.BezierTo";
		g_typeCast["BezierTo"] = "cc.BezierTo";
		return 1;
	}

7)动画:

1、直接加载.png

e.g.
local animation =cc.Animation:create()
        for i=0,5 do
            local szName =string.format("图片%d.png",i)
            animation:addSpriteFrameWithFile(szName)
        end

2、加载.plist里的.png

e.g.
local animation =cc.Animation:create()
	for i=0,13 do
	local szName =string.format("图片%d.png",i)
		local spriteFrame = cc.SpriteFrameCache:getInstance():getSpriteFrame(szName)
		animation:addSpriteFrame(spriteFrame)
	end

	animation:setDelayPerUnit(time)
        animation:setRestoreOriginalFrame(true)
        local action =cc.Animate:create(animation) 
        node:runAction(cc.RepeatForever:create(action))

8)TableView使用方法和注意点

e.g.
local tableView = cc.TableView:create(cc.size(width, height))
		tableView:setDirection(cc.SCROLLVIEW_DIRECTION_HORIZONTAL)
		tableView:setPosition(0, 0)
		tableView:setDelegate()
		self:addChild(tableView)
		--registerScriptHandler functions must be before the reloadData funtion
		tableView:registerScriptHandler(handler(self, self.numberOfCellsInTableView),cc.NUMBER_OF_CELLS_IN_TABLEVIEW)  
		tableView:registerScriptHandler(handler(self, self.scrollViewDidScroll),cc.SCROLLVIEW_SCRIPT_SCROLL)
		tableView:registerScriptHandler(handler(self, self.scrollViewDidZoom),cc.SCROLLVIEW_SCRIPT_ZOOM)
		tableView:registerScriptHandler(handler(self, self.tableCellTouched),cc.TABLECELL_TOUCHED)
		tableView:registerScriptHandler(handler(self, self.cellSizeForTable),cc.TABLECELL_SIZE_FOR_INDEX)
		tableView:registerScriptHandler(handler(self, self.tableCellAtIndex),cc.TABLECELL_SIZE_AT_INDEX)
		tableView:reloadData()
		
		function ScrollView:scrollViewDidScroll(view)
			print("scrollViewDidScroll")
		end


		function ScrollView:scrollViewDidZoom(view)
			print("scrollViewDidZoom")
		end


		function ScrollView:tableCellTouched(table,cell)
			print("cell touched at index: " .. cell:getIdx())
		end


		function ScrollView:cellSizeForTable(table,idx) 
			--error cocos2dx
			return  self.m_cellSize.width, self.m_cellSize.width 
		end


		function ScrollView:tableCellAtIndex(table, idx)
			local cell = table:dequeueCell()
			if not cell then
				cell = cc.TableViewCell:new()
				item = cc.Sprite:create("图片名")
				item:setPosition(self.m_cellSize.width/2, self.m_cellSize.height/2)
				item:setTag(60)
				cell:addChild(item)
			else
				item = cell:getChildByTag(60)
			end
			return cell
		end


		function ScrollView:numberOfCellsInTableView(table)
		   return ScrollView:GetCount()
		end
注意:
1、setDelegate()方法必须要加上,不然回调不起作用。
2、打开cocos2dx源码/tests/lua-tests/src/ExtensionTest/ExtensionTest.lua
搜索TableView,这个文件就是官方例子下面有段话:
-- registerScriptHandler functions must be before the reloadData funtion
注册方法必须要在reloadData之前,不然回调不起作用。
3、cellSizeForTable函数的坑
发现没有: 返回的宽高居然是一样的,而且取宽高最小值,这里宽小。
function ScrollView:cellSizeForTable(table,idx) 
return  self.m_cellSize.width, self.m_cellSize.width 
end

9)粒子、其他动作、场景跳转等就不说了,官方例子。

三、常用lua方法

1)随机函数

1、随机种子

math.randomseed(tonumber(tostring(os.time()):reverse():sub(1,6)))

2、随机值

math.random([n [, m]]) 有三种用法: 无参调用, 产生 (0,1) 之间的浮点随机数; 只有参数 n, 产生 1-n 之间的整数; 有两个参数 n, m, 产生 n-m 之间的随机整数

2)table.sort的一个坑

e.g.
table.sort(self.m_Data, 
        function(a,b) 
            return a.m_cbData
注意:当self.m_Data表里有2个相同的m_cbData字段值时,如果多次调用sort时,这2个值的位置会互换。
什么意思呢?假如表self.m_Data = { m_pSprite, m_cbData } 2个字段
local pData = {}
	pData.m_pSprite = cc.Sprite:create(a)
	pData.m_cbData = 1
	table.insert(self.m_Data, pData)
		
	pData.m_pSprite = cc.Sprite:create(b)
	pData.m_cbData = 2
	table.insert(self.m_Data, pData)
		
	pData.m_pSprite = cc.Sprite:create(c)
	pData.m_cbData = 2
	table.insert(self.m_Data, pData)
当调用时:
table.sort(self.m_Data, 
        function(a,b) 
            return a.m_cbData
假如是:a b c
下次在调用时,可能就是:a c b 

所以必须要有个字段2值不相同,才能排序,例如再增加个字段
local pData = {}
	pData.m_pSprite = cc.Sprite:create(a)
	pData.m_cbData = 1
	pData.m_iIndex = self.m_iIndex 
	table.insert(self.m_Data, pData)
	self.m_iIndex = self.m_iIndex + 1
		
	pData.m_pSprite = cc.Sprite:create(b)
	pData.m_cbData = 2
	pData.m_iIndex = self.m_iIndex 
	table.insert(self.m_Data, pData)
	self.m_iIndex = self.m_iIndex + 1
		
	pData.m_pSprite = cc.Sprite:create(c)
	pData.m_cbData = 2
	pData.m_iIndex = self.m_iIndex 
	table.insert(self.m_Data, pData)
	self.m_iIndex = self.m_iIndex + 1
		
	-- 这样排序就不会有问题了,精灵就不会互换了。
	table.sort(self.m_Data, 
        function(a,b) 
            if a.m_cbData==b.m_cbData then
                return a.m_iIndex < b.m_iIndex
            else
                return a.m_cbData

3)函数参数传递问题

function hanshu(Data, iCount) -- Data为表 iCount为数值
		Data = {}
		for i = #Data+1, #Data + 5 do
			Data[i] = i
			iCount = iCount + 1
		end
	end
	----------------------
	local Data = {1,2,3,4,5,6,7,8,9,10}
	local iCount = 10
	hanshu(Data, iCount)
	for i = 1, #Data do
		print(Data[i])
	end
	print(iCount)

这个结果是多少呢?->1,2,3,4,5 10

1、为什么不是1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 15

因为:Data = {} 这一句的意思是把原来的表释放,创建一个新表
所以:#Data的大小为0 值为1,2,3,4,5

2、为什么iCount不是15 或者 5 呢?

因为:iCount传递给函数的是值的拷贝,而不是引用

修改:
function hanshu(Data, iCount) -- Data为表 iCount为数值
		for i = #Data+1, #Data + 5 do
			Data[i] = i
			iCount = iCount + 1
		end
		return iCount
	end

4)os.time时间戳问题

os.time使用范围1970-1-1到2038-1-1(unix系统中范围
local tmMember = os.time({
                        year = MyUserData:GetMemberOverDate().wYear, 
                        month = MyUserData:GetMemberOverDate().wMonth, 
                        day = MyUserData:GetMemberOverDate().wDay,
                        hour = MyUserData:GetMemberOverDate().wHour,
                        min = MyUserData:GetMemberOverDate().wMinute,
                        sec = MyUserData:GetMemberOverDate().wSecond})
如果使用的日期不在这个范围内,在win32上是正常的,移植到Android手机上就会出错

四)2个类的写法

1)普通的继承类

e.g.
local A = class("A", function() return Layer:create() end)


	--init()
	function A:init()
		print("A:init")
		local m_visibleSize =  cc.Director:getInstance():getVisibleSize()
		self.m_pSprite = cc.Sprite:create(a)
		self:addChild(self.m_pSprite, 0)
	end


	--function SetTexture
	function A:SetTexture(strPngName)
		print("A:SetTexture")
		self.m_pSprite:setTexture(strPngName)
	end


	--ctor()
	function A:ctor()
		print("A:ctor")
		self:ignoreAnchorPointForPosition(false)
		self:init()
	end


	--create( ... )
	function A_createLayer( ... )
		print("A_createLayer")
		local layer = A.new()
		return layer
	end
	------------------------------------
	local m_ALayer = A_createLayer()
	self:addChild(m_ALayer, 0)
	m_ALayer:SetTexture(b)

说明:
1、local A = class("A", function() return Layer:create() end) 类A继承Layer可以使用Layer里所有公有方法
2、init()相当于cocos2d-x init函数
3、SetTexture 类的普通成员函数,创建A类的对象m_ALayer可以调用
4、ctor 类A的构造函数


2)单例模式

e.g.
A = class("A", nil)
	function A:new(o)
		print("A:new")
		o = o or {}
		setmetatable(o,self)
		self.__index = self
		return o
	end

	function A:GetInstance()
		if self.instance == nil then
			self.instance = self:new()
			self:Reset()
		end
		return self.instance
	end


	function A:ReleaseInstance()
		print("A:ReleaseInstance")
		if self.instance then
			self.instance = nil
		end
	end


	function A:GetA()
		return self
	end
	
	function A:Reset()
		-- clear()
		self.dwUserID = 0                      
		self.dwGameID = 0                     
		self.dwGroupID = 0                   
		self.szNickName = ""    
		self.szGroupName = ""      
		self.szUnderWrite = ""       
		self.wFaceID  = 0                            
		self.dwCustomID  = 0    
	end
		
	-- 成员方法
	...
	function A:SetUserID(dwUserID)
		self.dwUserID = dwUserID
	end
		
	function A:GetUserID()
		return self.dwUserID
	end
	-------------------------------
	local m_AInstance = A:GetInstance():GetA()
	m_AInstance.dwUserID = 1101
m_AInstance.dwGameID = 1120
	m_AInstance.szNickName = "test001"
	....
	m_AInstance.dwCustomID = 100
	A:GetInstance():SetUserID(1102)
	print(A:GetInstance():GetUserID())

总结:

大体上开发cocos lua遇到情况就这些了,当然还有些,C++绑定,socket网络消息传递,调试等等,我所用的知识就这些了(当然其他API,像什么粒子啊,那些官方都有demo自行查找),就可以开发一款游戏了。希望对大家有帮助,如果有错误或不合理之处请帮我指出,我也是刚刚才学习lua,谢谢~~!


你可能感兴趣的:(cocos lua遇到的一些问题)