本文不会涉及到任何公司项目等相关的内容,完全是个人平时的积累。
lua相关
1.pairs 和 ipairs 的区别:
- pairs可以遍历表中的所有元素,可以返回Nil
- ipairs则不可以返回nil,只能返回0,遇到nil则退出,他只能遍历到表中出现的第一个不是整数的key
2.lua深拷贝table
lua 除了简单类型分配内存外,table只是传递引用,所以不能用简单的”=”来copy两个表,并试图修改一个表中的值。
下面方法实现table copy: –lua table 拷贝
function table_copy_table(ori_tab)
if (type(ori_tab) ~= "table") then
return nil
end
local new_tab = {}
for i,v in pairs(ori_tab) do
local vtyp = type(v)
if (vtyp == "table") then
new_tab[i] = table_copy_table(v)
elseif (vtyp == "thread") then
new_tab[i] = v
elseif (vtyp == "userdata") then
new_tab[i] = v
else
new_tab[i] = v
end
end
return new_tab
end
3.”_G”lua的全局表
4.关于lua绑定C++代码
自从Cocos2d-x 3.0,我们使用 bindings-generator 自动生成 c++ lua 绑定。
bindings-generator 是基于 tolua++,你可以配置 tools/tolua目录下的ini文件,
然后运行genbindings.py脚本生成绑定代码。通过使用这种方法,大大降低了记录的pkg文件的配置工作。
http://segmentfault.com/a/1190000000631630
关于cocos2d-x下Lua调用C++的文档看了不少,但没有一篇真正把这事给讲明白了,我自己也是个初学者,摸索了半天,总结如下:
cocos2d-x下Lua调用C++这事之所以看起来这么复杂、网上所有的文档都没讲清楚,是因为存在5个层面的知识点:
1、在纯C环境下,把C函数注册进Lua环境,理解Lua和C之间可以互相调用的本质
2、在cocos2d-x项目里,把纯C函数注册进Lua环境,理解cocos2d-x是怎样创建Lua环境的、以及怎样得到这个环境并继续自定义它
3、了解为什么要使用toLua++来注册C++类
4、在纯C++环境下,使用toLua++来把一个C++类注册进Lua环境,理解toLua++的用法
5、在cocos2d-x项目里,使用cocos2d-x注册自身的方式把自定义的C++类注册进Lua环境,
理解cocos2d-x是怎样通过bindings-generator脚本来封装toLua++的用法来节省工作量的
只有理解了前4层,在最后使用bindings-generator脚本的时候心里才会清清楚楚。而网上的文档,要么是只解释了第1层,
要么是只填鸭式地告诉你第5层怎么用bindings-generator脚本,不仅中间重要的知识点一概不提,示例代码往往也写的不够简洁,
这让我这种看见C++就眼晕的人理解起来大为头疼(不是我不会C++,而是我非常不接受C++的设计哲学,能避就避)。
所以接下来的讲解我会对每一层知识点逐一讲解,示例代码也不求完整严谨,而是尽量用最简洁的方式把程序的关键点说明白。
5.如何实现?
总结一下cocos2d-x 3.8将C++类注册进lua环境
前提工具:
cocos2d-x 3.8
NDK_ROOT 必须为android-ndk-r9b(解压缩引擎,运行setup.py时设置ndk_root)
python插件:Cheetah、PyYAML(3.10以上版本、有32、64可选,但现在必选32,这个设置在下面有说明)
下面提到的所有路径都是基于新创建工程的路径,而不是引擎的路径。注意大小写!!!!
创建新工程的命令 : cocos.py new MyGame -p com.test.mygame -l cpp -d C:\test
1.自定义C++类,按照cocos2d-x的方法继承Ref类。包括.h和.cpp文件
首先是自定义的C++类。我习惯将文件保存在frameworks/runtime-src/Classes/目录下:
#include “cocos2d.h”
using namespace cocos2d;
class MyClass : public Ref{
public:
MyClass() {};
~MyClass() {};
bool init() { return true; };
CREATE_FUNC(MyClass);
int foo(int i);
};
#include “MyClass.h”
int MyClass::foo(int i){
return i + 100;
}
2.编写.ini文件,在tools/tolua目录,只需要修改部分的东西就可以使用
[MyClass]
prefix = MyClass
target_namespace = my
headers = %(cocosdir)s/../runtime-src/Classes/MyClass.h
classes = MyClass
更详细的说明:
headers 填入你所编写的代码的头文件
classes 填入要生成的类,支持多个类,支持正则表达式,如classes = A,^A,^A
skip指定屏蔽函数,即不需要暴露给lua的函数,支持正则表达式,如skip=Sprite::[getQuadgetBlendFuncsetPosition
setBlendFunc]
rename_functions 重新命名暴露到lua中函数名(一般以C++编写函数名暴露到lua),如
rename_functions = SpriteFrameCache::[addSpriteFramesWithFile=addSpriteFrames getSpriteFrameByName=getSpriteFrame],
等号前是原函数名,等号后是lua中的新函数名
rename_classes重命名类,如 rename_classes = SimpleAudioEngine::AudioEngine。前面是原名,后面是lua新名。这个好像没效果,生成后还是那个名字
classes_have_no_parents 指定一些没有父类的类
base_classes_to_skip 指定一些需要跳过的基类
abstract_classes 指定一些抽象类或者没有构造函数的类,以手动方式编写注册到lua函数
自动生成的代码会自动过滤掉C++中的protect、private属性、重载父类的函数、带省略号参数的函数(如Menu::create(MenuItem* item, …) )
3.运行genbindings.py(一定要cd 进入到cocos2d-x/tools/tolua目录,不能使用完全路径,否则不成功)
编写或者修改genbindings.py要注意点的:
在129行左右,设置cmd_args参数时,第一是ini文件名,最后一个是要生成的文件名,重点是第二个,这个参数是生成器在ini文件里面
查找对应的块(即ini文件中中括号对应的文字,如[cocos2dx],一般是第一行),形如
cmd_args = {‘custom.ini’ : (‘custom’, ‘lua_custom_auto’) }就是查找custom.ini中的[custom]段配置,
最后生成名为lua_custom_auto的文件,如果第二个参数没对应上,出现Section not found in config file的错误
(在Mac系统上可能会遇到缺少yaml、Cheetah包的问题,安装这些Python包很简单,先sudo easy_install pip,把pip装好,
然后用pip各种pip search、sudo pip install就可以了)
运行的时间比较长,在最后会提示
Generating lua bindings succeeds.
表示成功了,我们就能在cocos/scripting/lua-bindings/auto/找到lua_myClass_auto.cpp和对应的hpp文件了
4.如何调用?
在tools/simulator/framework/runtime-src/Classes/AppDelegate.cpp文件修改如下内容
添加 #include “lua_myClass_auto.hpp”
register_all_myClass(stack->getLuaState());
将lua_myClass_auto.hpp 和cpp文件添加到工程目录中
===编译成功,连接时候出错了。。。
Undefined symbols for architecture x86_64:
“register_all_myClass(lua_State*)”, referenced from:
AppDelegate::applicationDidFinishLaunching() in AppDelegate.o
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
不知道改了什么,现在又变成myClass.h找不到了,重新配置编译时工程引用的头文件位置
参考文章:
http://segmentfault.com/a/1190000000631630
http://www.bubuko.com/infodetail-424341.html
6.lua与C++通信的过程
7 -> -> ->
C++ | lua堆栈 | lua | lua全局表
<- <- <-
1.C++想要获取lua的myname字符串的值,所以把myname放到lua堆栈的栈顶
2.lua从栈顶获取myName,此时栈顶变为空
3.lua拿着myName去lua全局表查找myName对应的字符串
4.全局表返回一个字符串”mmmmm“
5.lua把取得的字符串放到栈顶
6.C++获取到栈顶的名字”mmmmm“
7.——3.x中场景切换的函数:
场景的切换是通过导演类来实现的
·runWithScene(scene) 只在启动第一个场景的时候调用,如果已经有一个场景运行则不可调用这个函数
·replaceScene(scene) 切换场景,旧的场景会被释放掉
·pushScene(scene) 切换场景,当前场景会被挂起放入场景堆栈中,然后在切换到下一个场景
·popScene(scene) 与pushScene配合使用,可以回到上一个场景
·popToRootScene() 与pushScene 配合使用,可以回到根场景
例:
cc.Director:getInstance():replaceScene(scene)
cc.Director:getInstance():pushScene(scene)
Director:getInstance()->popScene(); // 回到上一个场景
Scene以及所有节点(Node)的生命周期:
·enter
·enterTransitionFinish 进入场景并过度动画结束时触发
·exit 退出
·exitTransitionDidStart 退出场景并且开始过度动画时触发
·cleanup 场景对象被清除
lua中的require机制 http://blog.chinaunix.net/uid-552961-id-2736410.html
大型手游登录流程:
http://www.it165.net/pro/html/201509/53435.html
touch事件一定要在touchBegan中返回true,否则后面的事件会监听不到