cocos2dx塔防源码
‘壹’ cocos2dx 3.10 事件机制
cocos2dx的事件机制里存在三类: Event、EventListener、EventDispatcher
先理解一下它们之间的关系
当我们按下按钮时(Event),会触发一个特定的事件(EventListener相当于回调函数),而这个特定的事件又存储在EventDispatcher里,可能按下这个按钮会触发多个事件,而事件的先后就是靠EventDispatcher来决定的。
Event的相关类
当出现来自鼠标,键盘,触屏,摇杆等输入源的输入时,这个事实称之为事件
引擎无时无刻都在感受事件。
Event
可以看出Event主要包含三个变量,一个是事件类型_type(也就是定义的枚举类型:触摸、键盘等),isStopped判断事件是否停止,只要事件停止,其相关的Listener都要停止callback调用。
EventTouch
它对应于四种触摸操作,不同的EventCode可以告诉Listener来调用不同的callback。
EventCustom
它是用户自定义事件,userData记录用户自定义数据,另一个eventName是用户给事件取的别名
上面的源码都有英文注释,我就不多解释了,我只说一个最重要的_isRegistered,它判断事件有没有被注册,如果没有被注册就不会触发。(如何注册事件?将事件加入dispatcher)
在讲它之前,我们先了解一下它的一个重要变量。
sceneGraphListeners: 一个事件(比如说触摸事件),需要按照一定的响应序列,依次对这些Node进行事件响应,所以该类型的事件都会绑定一个与此相关联的node,并且 响应顺序是与node在scene下的zorder相关的 。该类型下的事件优先级统一为0。(与渲染树有关)
fixedListeners: 优先级根据 fixedPriority 的数值从小往大排序、
只要出现了删除,修改,添加监听器的时候,监听器列表需要重新排序,都需要设置相应的 DirtyFlag 操作。但是 Cocos-2dx v3.10 里面的 updateListeners 函数有删除监听器的操作,然而并没有设置相应的 DirtyFlag 操作。
会抛出下面的异常
Gt0Index() 方法其实就是获取到当前监听器中 fixedPriority == 0 的监听器在监听器向量中的位置,它 只有在给 Listener 排序的时候会设置,但是如果更新了对应 ListenerID 的向量(EventListenerVector),但是没有重新排序,就会出现 _gt0Index 未及时更新的情况 ,导致抛出这个异常。
引用:
Cocos2dx游戏引擎(3.x)----新的事件分发机制
cocos2dx之event事件(一)
cocos2dx之event事件(三):事件分发器EventDispatcher
Cocos2dx-v3.10 事件分发机制源码解析
‘贰’ cocos2dx 3.x版本中导入tiled地图如何导入对象层中对象的自定义信息(源码+注释)
步骤如下:
1. cocos2d-x 中使用类 TMXTiledMap 创建瓦片地图
2. 使用 TMXTiledMap 中的 getObjectGroup 接口取得对象层
3. 使用对象层的 getObject 接口获取对象信息,对象信息是一个 ValueMap 实例
4. 从 ValueMap 中取出数据
测试地图如下所示:
‘叁’ cocos2dx-3.6的luajit怎么了
cocos2d-x中luajit的使用
新版本的cocos2d-x使用了luajit来替代原始的lua,好处一是可以极大的提高运行速度(android下可以开jit,运行速度提高10~60倍,ios下不可以开jit,运行速度也可以提高2~3倍)。 二是luajit编译的字节码现阶段来说无法反编译,也就是说无法破解。 这里对luajit进行详细的说明。
1、基本使用。这个很简单,不用修改任何代码,与lua5.1完全兼容。 对应的头文件和库要替换成luajit的(与lua命名相同)
2、发布时编译成字节码。
这个需要luajit.exe的执行文件。 编译方法(windows): 在(http://luajit.org/download.html)下载源代码,使用vs的命令行工具,执行msvc.bat进行编译。 我最开始使用cygwin直接执行make结果出了很多编译错误和诡异的问题。 其实直接使用批处理才是正确的方式。
编译完成后,要注意luajit.exe和源代码src/jit文件夹要同时并且匹配使用。否则运行时会出现 "unknown luaJIT command or jit.* moles not installed"的错误。
编译成字节码的命令如下: luajit -b 原始文件 输出文件
更多详细说明可以直接执行 luajit -b来获取。 这里还要注意,输出文件最好保持.lua的扩展名,否则require文件的时候会提示找不到文件。除非require里面使用的完整名字。
我在编译字节码时还碰到了一个问题,就是无论编译什么文件都提示这个 "luajit '=' expected near '<eof>'" ,后来换了luajit的版本后就没有出现了。可能跟我一开始手欠改了luajit源代码有关。
3、编译luajit的静态库文件(for android)
编译字节码所用的执行文件和我们开发程序时使用的静态库文件要保持版本一致。 windows版本所需要的文件在编译执行文件时就已经生成。
‘肆’ cocos2dx怎么遍历资源文件夹里的文件
第一步在:在ZipFile添加方法,因为_dataThread是个私有的,尽量不改变源码的情况下,添加一个get方法是最好的
这个getAllFile可以返回所有的文件目录
std::vector<std::string>ZipFile::getAllFile(){
std::vector<std::string> vec;
ZipFilePrivate::FileListContainer::iterator it1;
for(it1=_dataThread->fileList.begin();it1!=_dataThread->fileList.end();++it1) {
vec.push_back(it1->first.c_str());
}
return vec;
}
第二步:使用getAllFile的返回值做遍历,这里直接帖出iOS和Android的同时遍历吧,同时搜索png和jpg的图片,可以用于加载资源,记得导入头文件
#include "support/zip_support/ZipUtils.h"
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
#include <dirent.h>
#include <sys/stat.h>
#else
#include "platform/CCCommon.h"
#include "support/zip_support/unzip.h"
#include "jni/Java_org_cocos2dx_lib_Cocos2dxHelper.h"
#endif
void ResourceLoadingLayer::getAllFile(std::string folderPath,int depth, std::vector<std::string> *list, std::string head){
#if CC_PLATFORM_IOS == CC_TARGET_PLATFORM
DIR *dp;
structdirent *entry;
structstat statbuf;
if((dp =opendir(folderPath.c_str())) ==NULL) {
fprintf(stderr,"cannot open directory: %s\n", folderPath.c_str());
return;
}
chdir(folderPath.c_str());
while((entry =readdir(dp)) != NULL) {
lstat(entry->d_name,&statbuf);
if(S_ISDIR(statbuf.st_mode)) {
if(strcmp(".",entry->d_name) == 0 ||
strcmp("..",entry->d_name) ==0)
continue;
getAllFile(entry->d_name,depth+4,list,head+entry->d_name);
} else {
if (head.length() ==0) {
string name = entry->d_name;
if (name.length()>3 && name.rfind(".") > 0 && (name.substr(name.rfind(".")+1,3) == "jpg" || name.substr(name.rfind(".")+1,3) == "png")) {
list->push_back(entry->d_name);
}
} else {
string filename = head+"/" +entry->d_name;
if (filename.length()>3 && filename.rfind(".") > 0 && (filename.substr(filename.rfind(".")+1,3) == "jpg" || filename.substr(filename.rfind(".")+1,3) == "png")) {
list->push_back(filename);
}
}
}
}
chdir("..");
closedir(dp);
#else
ZipFile* pFile = new ZipFile(getApkPath(),"assets/");
vector<string> vec = pFile->getAllFile();
for (int i=0; i<vec.size(); i++) {
string file = vec.at(i);
if (file.compare("assets/")) {
file = file.substr(7,file.length());
}
if(file.substr(0,folderPath.length()) == folderPath ){
string filename = file.substr(file.rfind("/")+1,file.length());
if (filename.length()>3 && filename.rfind(".") >0 && (filename.substr(filename.rfind(".")+1,3) =="jpg" || filename.substr(filename.rfind(".")+1,3) =="png") {
list->push_back(filename);
}
}
}
#endif
}
第三步,使用:
首先得拿到资源文件夹的完整路径,方法有很多,只举其一:
在HelloWorld的工程下的资源根目录有一张HelloWorld.png图片,我们可以直接获取它在程序中的完整路径,即
string fullpath = CCFileUtils::sharedFileUtils()->fullPathForFilename("HelloWorld.png");
所以 string resPath = fullpath.substr(0,fullpath.rfind("/")+1);
得到了完整的资源路径后,
vector<string> vec;
getAllFile(resPath, 0, &vec, "");
这样就大功告成了,vec会保存所有的png或jpg的资源,会带head名的哦,比如说bg/welcome.jpg
上面是遍历所有的文件夹,如果单独遍历资源文件下的某个目录,即是
getAllFile(resPath+"xxx",0,&vec,""); xxx 为资源根目录下的子目录,这样就可以分别加载某个目录了