Cocos2d_x

Cocos2d_x

用cocos2dx开发的游戏,玩一段时间就会手机发热,哪位大神知道怎么解决吗?

移动开发atool 回复了问题 • 2 人关注 • 1 个回复 • 3194 次浏览 • 2016-06-09 11:10 • 来自相关话题

Cocos2d-x Lua/Javascript脚本代码加密实现

游戏开发atool 发表了文章 • 0 个评论 • 628 次浏览 • 2016-04-22 14:15 • 来自相关话题

在游戏开发中,脚本作为一种资源文件,就像图片视频一样,被引擎所引用,使用脚本做游戏的好处就在于可以在线patch更新,特别对于苹果App Store审核期很长的情况。

如果不对脚本进行加密,不怀好意的人松松解压出脚本文件,给你瞬间复制一个游戏出来。

1.异或加密解密

最简单的一种加密方式,虽然简单,但是也比较实用。但是防破解方面确实一般,如果你有其他严格的仿破解需求,可以将这部分加密算法换成你自己的复杂算法,不过保证解密效率。下面是采用C++简单实现的对文件进行加密之后保存到原文件中(注意对原始未加密文件进行备份)
#include "stdafx.h"
#include<iostream>
#include<ctime>
#include<fstream>
using namespace std;
void Makecode(char *pstr,int *pkey);
void Cutecode(char *pstr,int *pkey);
void encode_file(char *f);
int _tmain(int argc, _TCHAR* argv[])
{
encode_file("e:/src/ResultScene.lua");
/*
encode_file("e:/src/ReadyScene.lua");
encode_file("e:/src/GameScene.lua");
encode_file("e:/src/PutHeadScene.lua");
encode_file("e:/src/TutorialsScene.lua");
encode_file("e:/src/WordsCategoryScene.lua");
encode_file("e:/src/common/DictHelper.lua");
encode_file("e:/src/common/LJ.lua");
encode_file("e:/src/common/DQueue.lua");
encode_file("e:/src/common/UIHelper.lua");
*/
int c;
cin>>c;
return 0;
}
void encode_file(char *f)
{
FILE *fp = NULL;
fopen_s(&fp, f,"rb");
fseek(fp,0,SEEK_END); //定位到文件末
int nFileLen = ftell(fp); //文件长度
cout << "file len = " << nFileLen << endl;
fseek(fp, 0, SEEK_SET);
char *fileContent = NULL;
fileContent = (char *) malloc ((nFileLen + 1) * sizeof(char));//增加一位
memset(fileContent, 0, nFileLen + 1);
fileContent[nFileLen] = '';//最后一位置为结束位
fread_s(fileContent,nFileLen, 1, nFileLen, fp);
//fread(buf,nFileLen, 1, fp);
//cout<<"解密前:"<<fileContent<<endl;
fclose(fp);
cout<<"文件:"<<f<<endl;
cout<<"解密前文件大小:"<<strlen(fileContent)<<endl;
int key[]={1, 2, 6, 1, 2, 6};//加密字符
char *p=fileContent;
cout<<"====="<<endl;
Makecode(fileContent,key);//加密
//cout<<"加密后:"<<p<<endl;
cout<<"加密后文件大小:"<<strlen(fileContent)<<endl;
FILE *stream = NULL;
fopen_s(&stream, f,"wb");
if (stream == NULL) /* open file TEST.$$$ */
{
fprintf(stderr, "Cannot open output file.
");
}
else {
fwrite(p, nFileLen, 1, stream); /* 写的struct文件*/
fclose(stream); /*关闭文件*/
}
cout<<"====="<<endl;
Cutecode(fileContent,key);//解密
//cout<<"解密后:"<<fileContent<<endl;
}
//单个字符异或运算
char MakecodeChar(char c,int key){
return c=c^key;
}
//单个字符解密
char CutcodeChar(char c,int key){
return c^key;
}
//加密
void Makecode(char *pstr,int *pkey){
int len=strlen(pstr);//获取长度
for(int i=0;i<len;i++)
*(pstr+i)=MakecodeChar(*(pstr+i),pkey[i%5]);
}
//解密
void Cutecode(char *pstr,int *pkey){
int len=strlen(pstr);
for(int i=0;i<len;i++)
*(pstr+i)=CutcodeChar(*(pstr+i),pkey[i%5]);
}2.修改Cocos2d-x引擎中加载lua脚本文件(或者js文件)的入口,在加载的时候对其进行解密。可能不同版本引擎有不同的入口文件,在Cocos2d-x3.0中,对应的是文件Cocos2dxLuaLoader.cpp文件中的int cocos2dx_lua_loader(lua_State *L)方法,对其进行修改成如下:
#include "Cocos2dxLuaLoader.h"
#include <string>
#include <algorithm>
#include<iostream>
using namespace cocos2d;
extern "C"
{
//单个字符异或运算
char MakecodeChar(char c,int key){
return c=c^key;
}
//单个字符解密
char CutcodeChar(char c,int key){
return c^key;
}
//加密
void Makecode(char *pstr,int *pkey){
int len=strlen(pstr);//获取长度
for(int i=0;i<len;i++)
*(pstr+i)=MakecodeChar(*(pstr+i),pkey[i%5]);
}
//解密
void Cutecode(char *pstr,int *pkey){
int len=strlen(pstr);
for(int i=0;i<len;i++)
*(pstr+i)=CutcodeChar(*(pstr+i),pkey[i%5]);
}
int cocos2dx_lua_loader(lua_State *L)
{
std::string filename(luaL_checkstring(L, 1));
size_t pos = filename.rfind(".lua");
if (pos != std::string::npos)
{
filename = filename.substr(0, pos);
}

pos = filename.find_first_of(".");
while (pos != std::string::npos)
{
filename.replace(pos, 1, "/");
pos = filename.find_first_of(".");
}
filename.append(".lua");

Data data = FileUtils::getInstance()->getDataFromFile(filename);

if (!data.isNull())
{

//====code decode start==================================
log("===encode filename:%s===", filename.c_str());
//如果filename == 'main.lua',则解密
char *fileContent = (char*)data.getBytes();
int key[]={1, 2, 6, 1, 2, 6};//加密字符
char *fileContentDecoded = NULL;
if (strcmp(filename.c_str(),"ReadyScene.lua")==0 ||
strcmp(filename.c_str(),"GameScene.lua")==0 ||
strcmp(filename.c_str(),"PutHeadScene.lua")==0 ||
strcmp(filename.c_str(),"TutorialsScene.lua")==0 ||
strcmp(filename.c_str(),"WordsCategoryScene.lua")==0 ||
strcmp(filename.c_str(),"DictHelper.lua")==0 ||
strcmp(filename.c_str(),"LJ.lua")==0 ||
strcmp(filename.c_str(),"ResultScene.lua")==0 ||
strcmp(filename.c_str(),"DQueue.lua")==0 ||
strcmp(filename.c_str(),"UIHelper.lua")==0 ) {
if (data.getSize() < strlen(fileContent)) {
fileContentDecoded = (char *) malloc ((data.getSize() + 1) * sizeof(char));//增加一位
memset(fileContentDecoded, 0, data.getSize() + 1);
fileContentDecoded[data.getSize()] = '';//最后一位置为结束位
strncpy(fileContentDecoded,fileContent,data.getSize());
fileContent = NULL;
}
else {
fileContentDecoded = fileContent;
}
Cutecode(fileContentDecoded,key);//解密
}
else {
fileContentDecoded = fileContent;
}
//====code decode end==================================

if (luaL_loadbuffer(L, fileContentDecoded, data.getSize(), filename.c_str()) != 0)
{
luaL_error(L, "error loading module %s from file %s :
%s",
lua_tostring(L, 1), filename.c_str(), lua_tostring(L, -1));
}
}
else
{
log("can not get file data of %s", filename.c_str());
}
return 1;
}
}注意加密解密的key保证一致。

代码注释应该挺完善的,不进行解释了,Enjoy~ 查看全部
在游戏开发中,脚本作为一种资源文件,就像图片视频一样,被引擎所引用,使用脚本做游戏的好处就在于可以在线patch更新,特别对于苹果App Store审核期很长的情况。

如果不对脚本进行加密,不怀好意的人松松解压出脚本文件,给你瞬间复制一个游戏出来。

1.异或加密解密

最简单的一种加密方式,虽然简单,但是也比较实用。但是防破解方面确实一般,如果你有其他严格的仿破解需求,可以将这部分加密算法换成你自己的复杂算法,不过保证解密效率。下面是采用C++简单实现的对文件进行加密之后保存到原文件中(注意对原始未加密文件进行备份)
#include "stdafx.h"
#include<iostream>
#include<ctime>
#include<fstream>
using namespace std;
void Makecode(char *pstr,int *pkey);
void Cutecode(char *pstr,int *pkey);
void encode_file(char *f);
int _tmain(int argc, _TCHAR* argv[])
{
encode_file("e:/src/ResultScene.lua");
/*
encode_file("e:/src/ReadyScene.lua");
encode_file("e:/src/GameScene.lua");
encode_file("e:/src/PutHeadScene.lua");
encode_file("e:/src/TutorialsScene.lua");
encode_file("e:/src/WordsCategoryScene.lua");
encode_file("e:/src/common/DictHelper.lua");
encode_file("e:/src/common/LJ.lua");
encode_file("e:/src/common/DQueue.lua");
encode_file("e:/src/common/UIHelper.lua");
*/
int c;
cin>>c;
return 0;
}
void encode_file(char *f)
{
FILE *fp = NULL;
fopen_s(&fp, f,"rb");
fseek(fp,0,SEEK_END); //定位到文件末
int nFileLen = ftell(fp); //文件长度
cout << "file len = " << nFileLen << endl;
fseek(fp, 0, SEEK_SET);
char *fileContent = NULL;
fileContent = (char *) malloc ((nFileLen + 1) * sizeof(char));//增加一位
memset(fileContent, 0, nFileLen + 1);
fileContent[nFileLen] = '';//最后一位置为结束位
fread_s(fileContent,nFileLen, 1, nFileLen, fp);
//fread(buf,nFileLen, 1, fp);
//cout<<"解密前:"<<fileContent<<endl;
fclose(fp);
cout<<"文件:"<<f<<endl;
cout<<"解密前文件大小:"<<strlen(fileContent)<<endl;
int key[]={1, 2, 6, 1, 2, 6};//加密字符
char *p=fileContent;
cout<<"====="<<endl;
Makecode(fileContent,key);//加密
//cout<<"加密后:"<<p<<endl;
cout<<"加密后文件大小:"<<strlen(fileContent)<<endl;
FILE *stream = NULL;
fopen_s(&stream, f,"wb");
if (stream == NULL) /* open file TEST.$$$ */
{
fprintf(stderr, "Cannot open output file.
");
}
else {
fwrite(p, nFileLen, 1, stream); /* 写的struct文件*/
fclose(stream); /*关闭文件*/
}
cout<<"====="<<endl;
Cutecode(fileContent,key);//解密
//cout<<"解密后:"<<fileContent<<endl;
}
//单个字符异或运算
char MakecodeChar(char c,int key){
return c=c^key;
}
//单个字符解密
char CutcodeChar(char c,int key){
return c^key;
}
//加密
void Makecode(char *pstr,int *pkey){
int len=strlen(pstr);//获取长度
for(int i=0;i<len;i++)
*(pstr+i)=MakecodeChar(*(pstr+i),pkey[i%5]);
}
//解密
void Cutecode(char *pstr,int *pkey){
int len=strlen(pstr);
for(int i=0;i<len;i++)
*(pstr+i)=CutcodeChar(*(pstr+i),pkey[i%5]);
}
2.修改Cocos2d-x引擎中加载lua脚本文件(或者js文件)的入口,在加载的时候对其进行解密。可能不同版本引擎有不同的入口文件,在Cocos2d-x3.0中,对应的是文件Cocos2dxLuaLoader.cpp文件中的int cocos2dx_lua_loader(lua_State *L)方法,对其进行修改成如下:
#include "Cocos2dxLuaLoader.h"
#include <string>
#include <algorithm>
#include<iostream>
using namespace cocos2d;
extern "C"
{
//单个字符异或运算
char MakecodeChar(char c,int key){
return c=c^key;
}
//单个字符解密
char CutcodeChar(char c,int key){
return c^key;
}
//加密
void Makecode(char *pstr,int *pkey){
int len=strlen(pstr);//获取长度
for(int i=0;i<len;i++)
*(pstr+i)=MakecodeChar(*(pstr+i),pkey[i%5]);
}
//解密
void Cutecode(char *pstr,int *pkey){
int len=strlen(pstr);
for(int i=0;i<len;i++)
*(pstr+i)=CutcodeChar(*(pstr+i),pkey[i%5]);
}
int cocos2dx_lua_loader(lua_State *L)
{
std::string filename(luaL_checkstring(L, 1));
size_t pos = filename.rfind(".lua");
if (pos != std::string::npos)
{
filename = filename.substr(0, pos);
}

pos = filename.find_first_of(".");
while (pos != std::string::npos)
{
filename.replace(pos, 1, "/");
pos = filename.find_first_of(".");
}
filename.append(".lua");

Data data = FileUtils::getInstance()->getDataFromFile(filename);

if (!data.isNull())
{

//====code decode start==================================
log("===encode filename:%s===", filename.c_str());
//如果filename == 'main.lua',则解密
char *fileContent = (char*)data.getBytes();
int key[]={1, 2, 6, 1, 2, 6};//加密字符
char *fileContentDecoded = NULL;
if (strcmp(filename.c_str(),"ReadyScene.lua")==0 ||
strcmp(filename.c_str(),"GameScene.lua")==0 ||
strcmp(filename.c_str(),"PutHeadScene.lua")==0 ||
strcmp(filename.c_str(),"TutorialsScene.lua")==0 ||
strcmp(filename.c_str(),"WordsCategoryScene.lua")==0 ||
strcmp(filename.c_str(),"DictHelper.lua")==0 ||
strcmp(filename.c_str(),"LJ.lua")==0 ||
strcmp(filename.c_str(),"ResultScene.lua")==0 ||
strcmp(filename.c_str(),"DQueue.lua")==0 ||
strcmp(filename.c_str(),"UIHelper.lua")==0 ) {
if (data.getSize() < strlen(fileContent)) {
fileContentDecoded = (char *) malloc ((data.getSize() + 1) * sizeof(char));//增加一位
memset(fileContentDecoded, 0, data.getSize() + 1);
fileContentDecoded[data.getSize()] = '';//最后一位置为结束位
strncpy(fileContentDecoded,fileContent,data.getSize());
fileContent = NULL;
}
else {
fileContentDecoded = fileContent;
}
Cutecode(fileContentDecoded,key);//解密
}
else {
fileContentDecoded = fileContent;
}
//====code decode end==================================

if (luaL_loadbuffer(L, fileContentDecoded, data.getSize(), filename.c_str()) != 0)
{
luaL_error(L, "error loading module %s from file %s :
%s",
lua_tostring(L, 1), filename.c_str(), lua_tostring(L, -1));
}
}
else
{
log("can not get file data of %s", filename.c_str());
}
return 1;
}
}
注意加密解密的key保证一致。

代码注释应该挺完善的,不进行解释了,Enjoy~

cocos2d-x中使用FMOD音效引擎基本知识介绍

游戏开发atool 发表了文章 • 0 个评论 • 2060 次浏览 • 2016-04-22 13:23 • 来自相关话题

大致研究了2.5天的Fmod音效引擎,从对音效没有什么概念到有一点点理解。fmod是一个很不错的音效引擎,从它的API demo运行效果可以感受到引擎音效非常好,它提供了很简单的API来控制音效的3D播放特性。

一、FMOD引擎API版本介绍

fmod引擎api因为其版本的原因,分成两种:

1. 对应FMOD Designer版本的API,FMOD Designer为旧版本引擎,导出文件为fev和fsb,fev定义为音效的播放规则,音乐索引(大致可以这么理解)等;fsb主要是音乐文件的打包,目前音效组使用的FMOD Designer做音效开发。

2. 对应FMOD Studio版本的API,FMOD Studio是新版本引擎,导出文件为.bank文件,其中包含有播放规则,音乐索引,音乐文件(新版本将旧版本中的两个导出文件变成一个,提供了一个很好的特性:可以播放apk中的音效文件)。

二、在cocos2d-x中FMOD API调用方式

同样有两种途径:

1. 使用FMOD提供的android api和ios api分别开发播放接口,然后再lua中调用。

    1.1 优点在于难点少,相比方法2简单。

    1.2 缺点在于需要做两套代码,工作量大,另外一个致命的问题是:音效延迟播放(因为LUA调用Java只能是静态方法,所以在Java采用线程扫描状态的方式,存在一定的播放延迟),个人觉得对于音效来说不能忍,人的视觉几乎无法区分1/60s内的变换,但是听觉就不一样了。点击一个按钮,在20ms内响应完全没有问题,但是如果声音在20ms后播放就存在很大的问题了。

2. 使用FMOD的cpp接口,首先在cocos2d-x的底层平台写好cpp的播放代码接口,然后采用tolua++导出lua可以使用的内库,然后编写lua调用的接口,最后可以在cocos2d-x + lua上进行播放。

    1.1 优点在于跨平台,一次解决可以适用于android和ios,同时对于以后的项目也可以直接使用,非常有必要做这个工作。

    1.2 缺点在于难点多,漏洞多,涉及到cocos2d-x底层接口开发,以及cpp和lua之间的接口开发,这些之前都没有做过,难度比较大,另外,涉及到cpp底层代码,容易造成一些难以解决的漏洞。

三、FMOD Designer VS FMOD Studio

两个版本一个旧,一个新,大致说说他们最致命的问题:

1. FMOD Designer公司音效人员在使用,这是其优点,但是FMOD Designer版本的缺点很明显就是在android平台无法播放apk中的音效,这意味着和PC游戏一样,安装工程或者第一次运行的时候需要解压apk中的音效文件到应用目录中,并且在以后的每次运行过程中必须检测音效文件是否存在,如果不存在或者缺失,需要将音效重写解压出来。这不仅增加游戏的另一份工作量,也减少了游戏的运行效率。(一般的手机清理软件都会造成app,目录被删除)

2. FMOD Studio新版本很好的一个特性就是可以直接读取apk中音效文件(网络上关于FMOD资源不多,这一点还是发邮件和官方沟通得知的);但是FMOD Studio并没有被公司音效使用。

四、FMOD适用环境

FMOD具有很简单的API操作,并提供不简单的3D音效特性,然而在cocos2d-x中使用FMOD引擎需要做引擎文件的解析操作,会增加一定的工作量,因此建议在游戏存在3D特性的情况下使用,例如:音效距离、音效方向、音效源移动等情况使用;而在一般的UI界面操作中不要使用fmod,而是使用普通的wav,mp3,ogg等cocos2d-x可以解析的音效即可。 查看全部
大致研究了2.5天的Fmod音效引擎,从对音效没有什么概念到有一点点理解。fmod是一个很不错的音效引擎,从它的API demo运行效果可以感受到引擎音效非常好,它提供了很简单的API来控制音效的3D播放特性。

一、FMOD引擎API版本介绍

fmod引擎api因为其版本的原因,分成两种:

1. 对应FMOD Designer版本的API,FMOD Designer为旧版本引擎,导出文件为fev和fsb,fev定义为音效的播放规则,音乐索引(大致可以这么理解)等;fsb主要是音乐文件的打包,目前音效组使用的FMOD Designer做音效开发。

2. 对应FMOD Studio版本的API,FMOD Studio是新版本引擎,导出文件为.bank文件,其中包含有播放规则,音乐索引,音乐文件(新版本将旧版本中的两个导出文件变成一个,提供了一个很好的特性:可以播放apk中的音效文件)。

二、在cocos2d-x中FMOD API调用方式

同样有两种途径:

1. 使用FMOD提供的android api和ios api分别开发播放接口,然后再lua中调用。

    1.1 优点在于难点少,相比方法2简单。

    1.2 缺点在于需要做两套代码,工作量大,另外一个致命的问题是:音效延迟播放(因为LUA调用Java只能是静态方法,所以在Java采用线程扫描状态的方式,存在一定的播放延迟),个人觉得对于音效来说不能忍,人的视觉几乎无法区分1/60s内的变换,但是听觉就不一样了。点击一个按钮,在20ms内响应完全没有问题,但是如果声音在20ms后播放就存在很大的问题了。

2. 使用FMOD的cpp接口,首先在cocos2d-x的底层平台写好cpp的播放代码接口,然后采用tolua++导出lua可以使用的内库,然后编写lua调用的接口,最后可以在cocos2d-x + lua上进行播放。

    1.1 优点在于跨平台,一次解决可以适用于android和ios,同时对于以后的项目也可以直接使用,非常有必要做这个工作。

    1.2 缺点在于难点多,漏洞多,涉及到cocos2d-x底层接口开发,以及cpp和lua之间的接口开发,这些之前都没有做过,难度比较大,另外,涉及到cpp底层代码,容易造成一些难以解决的漏洞。

三、FMOD Designer VS FMOD Studio

两个版本一个旧,一个新,大致说说他们最致命的问题:

1. FMOD Designer公司音效人员在使用,这是其优点,但是FMOD Designer版本的缺点很明显就是在android平台无法播放apk中的音效,这意味着和PC游戏一样,安装工程或者第一次运行的时候需要解压apk中的音效文件到应用目录中,并且在以后的每次运行过程中必须检测音效文件是否存在,如果不存在或者缺失,需要将音效重写解压出来。这不仅增加游戏的另一份工作量,也减少了游戏的运行效率。(一般的手机清理软件都会造成app,目录被删除)

2. FMOD Studio新版本很好的一个特性就是可以直接读取apk中音效文件(网络上关于FMOD资源不多,这一点还是发邮件和官方沟通得知的);但是FMOD Studio并没有被公司音效使用。

四、FMOD适用环境

FMOD具有很简单的API操作,并提供不简单的3D音效特性,然而在cocos2d-x中使用FMOD引擎需要做引擎文件的解析操作,会增加一定的工作量,因此建议在游戏存在3D特性的情况下使用,例如:音效距离、音效方向、音效源移动等情况使用;而在一般的UI界面操作中不要使用fmod,而是使用普通的wav,mp3,ogg等cocos2d-x可以解析的音效即可。

Cocos2d-x 横屏竖屏异常uncaught exception“UIApplicationInvalidInterfaceOrientation”

游戏开发atool 发表了文章 • 0 个评论 • 822 次浏览 • 2016-04-22 13:18 • 来自相关话题

在Cocos2d-x横屏游戏中集成社会化分享的时候,会出现异常

*** Terminating app due to uncaught exception 'UIApplicationInvalidInterfaceOrientation', reason: 'Supported orientations has no common orientation with the application, and shouldAutorotate is returning YES'

大致意思是cocos2d-x游戏设置的可支持屏幕方式找不到需要的方向。这是因为游戏中设置的是只支持横屏方式,但是在RootViewController中shouldAutorotate返回的又是YES,恰好分享的时候弹出的授权页面时竖屏的,所以弹出框自动旋转到竖屏,确又找不到可以支持的竖屏方向,所以抛出异常,程序也卡死了,解决办法如下,仅仅针对于Cocos2d-x代码,其他APP如果出现类似问题,可以参考:

1.AppController.mm加入方法
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
return UIInterfaceOrientationMaskAll;
}
else {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
}2.RootViewController.mm 加入方法
//For ios6, use supportedInterfaceOrientations & shouldAutorotate instead
- (NSUInteger) supportedInterfaceOrientations{
#ifdef __IPHONE_6_0
return UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskLandscapeLeft;//方向也可以仅定义为横屏中的一个方向
#endif
}如此就可以了,反正我是解决了~兼容性已测,不存在问题!Enjoy~ 查看全部
在Cocos2d-x横屏游戏中集成社会化分享的时候,会出现异常

*** Terminating app due to uncaught exception 'UIApplicationInvalidInterfaceOrientation', reason: 'Supported orientations has no common orientation with the application, and shouldAutorotate is returning YES'

大致意思是cocos2d-x游戏设置的可支持屏幕方式找不到需要的方向。这是因为游戏中设置的是只支持横屏方式,但是在RootViewController中shouldAutorotate返回的又是YES,恰好分享的时候弹出的授权页面时竖屏的,所以弹出框自动旋转到竖屏,确又找不到可以支持的竖屏方向,所以抛出异常,程序也卡死了,解决办法如下,仅仅针对于Cocos2d-x代码,其他APP如果出现类似问题,可以参考:

1.AppController.mm加入方法
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
return UIInterfaceOrientationMaskAll;
}
else {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
}
2.RootViewController.mm 加入方法
//For ios6, use supportedInterfaceOrientations & shouldAutorotate instead
- (NSUInteger) supportedInterfaceOrientations{
#ifdef __IPHONE_6_0
return UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskLandscapeLeft;//方向也可以仅定义为横屏中的一个方向
#endif
}
如此就可以了,反正我是解决了~兼容性已测,不存在问题!Enjoy~

Cocos2d-x android使用onKeyDown监听返回键实现二次返回退出

游戏开发atool 发表了文章 • 0 个评论 • 2453 次浏览 • 2016-04-22 13:16 • 来自相关话题

一般的游戏或者软件,都会在android版本上做退出程序的功能,一般的实现方式有两种:

1.点击返回按键,弹出确认是否退出;

2.点击返回,toast提示再次点击退出程序。

这两种方式实现都需要android上监听用户按下了android手机上的返回键,监听到了之后执行相应的操作。

通过搜索,很容易知道可以实现activity类的方法
public boolean onKeyDown(final int pKeyCode, final KeyEvent pKeyEvent)实现对用户按键的监听,但是将代码加入到cocos2d-x生成的Java代码中的AppActivity中,发现根本不起作用,没法监听到用户的按键操作,找官方api文档,发现:

public boolean onKeyDown (int keyCode, KeyEvent event)

Since: API Level 1

Called when a key was pressed down and not handled by any of the views inside of the activity. So, for example, key presses while the cursor is inside a TextView will not trigger the event (unless it is a navigation to another object) because TextView handles its own key presses.

If the focused view didn't want this event, this method is called.

这段文字我需要强调的是红色标记部分,翻译的意思是:当用户按下一个按键的时候调用,但是前提是这个事件没有被其他的任何views监听并处理。

因此不难得知,在cocos2d-x游戏中,在实现的onKeyDown方法监听不到返回键,是因为这个返回键事件已经被其他的onKeyDown处理掉了,具体是谁呢?看cocos2d-x的android版本代码(framework/scocos2d-x/cocos/2d/platform/android/java/src/org/cocos2dx/lib/Cocos2dx/GLSurfaceView.java)。其中实现了onKeyDown方法:
@Override
public boolean onKeyDown(final int pKeyCode, final KeyEvent pKeyEvent) {
switch (pKeyCode) {
case KeyEvent.KEYCODE_BACK:

case KeyEvent.KEYCODE_MENU:
this.queueEvent(new Runnable() {
@Override
public void run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleKeyDown(pKeyCode);
}
});
return true;
default:
return super.onKeyDown(pKeyCode, pKeyEvent);
}
}这个里面,按键KeyEvent.KEYCODE_BACK被监听了,只要在这里不作处理即可(return false),改成如下代码:
@Override
public boolean onKeyDown(final int pKeyCode, final KeyEvent pKeyEvent) {
switch (pKeyCode) {
case KeyEvent.KEYCODE_BACK:
return false;
case KeyEvent.KEYCODE_MENU:
this.queueEvent(new Runnable() {
@Override
public void run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleKeyDown(pKeyCode);
}
});
return true;
default:
return super.onKeyDown(pKeyCode, pKeyEvent);
}
}这样在你自己的cocos2d-x游戏Activity中就可以监听返回键了,在AppActivity中重写onKeyDown方法,如下:
private long mkeyTime = 0;
public boolean onKeyDown(int keyCode, KeyEvent event) {
//二次返回退出
if (keyCode == KeyEvent.KEYCODE_BACK) {
if ((System.currentTimeMillis() - mkeyTime) > 2000) {
mkeyTime = System.currentTimeMillis();
Toast.makeText(this, "再按一次退出游戏", Toast.LENGTH_LONG).show();
} else {
finish();
System.exit(0);
}
return false;
}
return super.onKeyDown(keyCode, event);
}然后运行游戏, 点击返回键试试,有没有Toast?Enjoy~ 查看全部
一般的游戏或者软件,都会在android版本上做退出程序的功能,一般的实现方式有两种:

1.点击返回按键,弹出确认是否退出;

2.点击返回,toast提示再次点击退出程序。

这两种方式实现都需要android上监听用户按下了android手机上的返回键,监听到了之后执行相应的操作。

通过搜索,很容易知道可以实现activity类的方法
public boolean onKeyDown(final int pKeyCode, final KeyEvent pKeyEvent)
实现对用户按键的监听,但是将代码加入到cocos2d-x生成的Java代码中的AppActivity中,发现根本不起作用,没法监听到用户的按键操作,找官方api文档,发现:

public boolean onKeyDown (int keyCode, KeyEvent event)

Since: API Level 1

Called when a key was pressed down and not handled by any of the views inside of the activity. So, for example, key presses while the cursor is inside a TextView will not trigger the event (unless it is a navigation to another object) because TextView handles its own key presses.

If the focused view didn't want this event, this method is called.

这段文字我需要强调的是红色标记部分,翻译的意思是:当用户按下一个按键的时候调用,但是前提是这个事件没有被其他的任何views监听并处理。

因此不难得知,在cocos2d-x游戏中,在实现的onKeyDown方法监听不到返回键,是因为这个返回键事件已经被其他的onKeyDown处理掉了,具体是谁呢?看cocos2d-x的android版本代码(framework/scocos2d-x/cocos/2d/platform/android/java/src/org/cocos2dx/lib/Cocos2dx/GLSurfaceView.java)。其中实现了onKeyDown方法:
@Override
public boolean onKeyDown(final int pKeyCode, final KeyEvent pKeyEvent) {
switch (pKeyCode) {
case KeyEvent.KEYCODE_BACK:

case KeyEvent.KEYCODE_MENU:
this.queueEvent(new Runnable() {
@Override
public void run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleKeyDown(pKeyCode);
}
});
return true;
default:
return super.onKeyDown(pKeyCode, pKeyEvent);
}
}
这个里面,按键KeyEvent.KEYCODE_BACK被监听了,只要在这里不作处理即可(return false),改成如下代码:
@Override
public boolean onKeyDown(final int pKeyCode, final KeyEvent pKeyEvent) {
switch (pKeyCode) {
case KeyEvent.KEYCODE_BACK:
return false;
case KeyEvent.KEYCODE_MENU:
this.queueEvent(new Runnable() {
@Override
public void run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleKeyDown(pKeyCode);
}
});
return true;
default:
return super.onKeyDown(pKeyCode, pKeyEvent);
}
}
这样在你自己的cocos2d-x游戏Activity中就可以监听返回键了,在AppActivity中重写onKeyDown方法,如下:
private long mkeyTime = 0;
public boolean onKeyDown(int keyCode, KeyEvent event) {
//二次返回退出
if (keyCode == KeyEvent.KEYCODE_BACK) {
if ((System.currentTimeMillis() - mkeyTime) > 2000) {
mkeyTime = System.currentTimeMillis();
Toast.makeText(this, "再按一次退出游戏", Toast.LENGTH_LONG).show();
} else {
finish();
System.exit(0);
}
return false;
}
return super.onKeyDown(keyCode, event);
}
然后运行游戏, 点击返回键试试,有没有Toast?Enjoy~

xcode编译cocos2d-x 3.0及以上版本支持arm64位

游戏开发atool 发表了文章 • 0 个评论 • 2501 次浏览 • 2016-04-22 13:05 • 来自相关话题

在使用cocos2d-x 3.0rc lua版本完成游戏过程中,真机存在一个问题:

1. 使用iphone4s真机调试,可以正常运行通过;

2. 使用iphone4s以上版本真机调试的时候,不能够正常编译,出现的的错误是cc命名空间下的很多方法找不到,具体都是cocos2d-x的代码找不到。

虽然直接使用iphone4s连接手机,achieve出来的ipa包也可以在所有ios设备上运行,但是提交appstore的时候,就会出现错误:ERROR ITMS-90086:"missing 64-bit support. beginning on february 1, 2015, new iOS apps submitted to the app store must be include 64-bit support and be built with the ios8 SDK......"。




大致意思是app store从2015年2月1号开始,不再接受不支持64位的app上线。

解决办法如下:

1.将所有的cocos2d-x xcode项目的project和target中的building-setting设置项中的architectures、supported platforms、validarchitectures,另外非常重要的一个配置是build active architecture only全部设置为No。下图所示:




需要修改p2,cocos2d_lua_bindings.xcodeproj, cocos2d_libs.xcodeproj三个项目中的building-setting。如下图所示:




修改之后,就会发现之前出现的“cc命名空间下的很多方法找不到”的错误都消失了,出现的都是关于图片读取的问题,这个问题解决见步骤2;

2.因为cocos2d-x3.0rc版本没有将图片相关的64位库加入,引入相关的图片读取解析的64位库;如下图所示:




具体就是上述中_arm64.a结尾的库。

上述问题解决了,但是又出现lua里面的方法找不到的错误,解决办法见步骤3;

3.由于cocos2d-x3.0rc使用的是luajit,但是只引入了libluagit.a库,这个库是32位的,所以无法编译64位,于是找到一个liblua.a的库,引入lua.a到项目即可。如下图:




三步完成,问题全部解决,打包,重签,测试,没有任何问题。

Enjoy~
  查看全部
在使用cocos2d-x 3.0rc lua版本完成游戏过程中,真机存在一个问题:

1. 使用iphone4s真机调试,可以正常运行通过;

2. 使用iphone4s以上版本真机调试的时候,不能够正常编译,出现的的错误是cc命名空间下的很多方法找不到,具体都是cocos2d-x的代码找不到。

虽然直接使用iphone4s连接手机,achieve出来的ipa包也可以在所有ios设备上运行,但是提交appstore的时候,就会出现错误:ERROR ITMS-90086:"missing 64-bit support. beginning on february 1, 2015, new iOS apps submitted to the app store must be include 64-bit support and be built with the ios8 SDK......"。
111.png

大致意思是app store从2015年2月1号开始,不再接受不支持64位的app上线。

解决办法如下:

1.将所有的cocos2d-x xcode项目的project和target中的building-setting设置项中的architectures、supported platforms、validarchitectures,另外非常重要的一个配置是build active architecture only全部设置为No。下图所示:
222.png

需要修改p2,cocos2d_lua_bindings.xcodeproj, cocos2d_libs.xcodeproj三个项目中的building-setting。如下图所示:
333.png

修改之后,就会发现之前出现的“cc命名空间下的很多方法找不到”的错误都消失了,出现的都是关于图片读取的问题,这个问题解决见步骤2;

2.因为cocos2d-x3.0rc版本没有将图片相关的64位库加入,引入相关的图片读取解析的64位库;如下图所示:
444.png

具体就是上述中_arm64.a结尾的库。

上述问题解决了,但是又出现lua里面的方法找不到的错误,解决办法见步骤3;

3.由于cocos2d-x3.0rc使用的是luajit,但是只引入了libluagit.a库,这个库是32位的,所以无法编译64位,于是找到一个liblua.a的库,引入lua.a到项目即可。如下图:
555.png

三步完成,问题全部解决,打包,重签,测试,没有任何问题。

Enjoy~
 

Cocos2d-x 3.0修改Android平台帧率fps - 解决游戏运行手机发热发烫问题

游戏开发atool 发表了文章 • 2 个评论 • 2468 次浏览 • 2016-04-22 13:01 • 来自相关话题

使用Cocos2d-x 3.0开发游戏之后,发现游戏在android手机上发热非常严重,在魅族2上,几乎担心手机会爆炸了~~~采取的一个措施就是降低帧率,因为游戏对于帧率要求不是非常高。

做过cocos2d开发的同学应该都知道在win32平台修改帧率的方式非常简单,就是在AppDelegate.cpp文件中修改:
director->setAnimationInterval(1.0 / 40);但是这种修改方式在导出android安卓apk到真机测试的时候,发现左下角的调试信息还是现实60~65帧,完全不受影响,网上搜索之后,发小安卓的修改需要修改cocos2dx-x生成的java代码中修改,具体在文件:Cocos2dxRenderer.java

在代码中可以看到以下的属性设置和重写的方法:
private static long sAnimationInterval = (long) (1.0 / 60 * Cocos2dxRenderer.NANOSECONDSPERSECOND);
public void onDrawFrame(final GL10 gl) {}如果要修改android平台的帧率,可以通过修改这些代码来改进,具体的操作方法如下:

1.修改帧率将60改成40
private static long sAnimationInterval = (long) (1.0 / 40 * Cocos2dxRenderer.NANOSECONDSPERSECOND);
2.增加一个属性变量
private long renderingElapsedTime = 0;3.重写渲染方法onDrawFrame
@Override
public void onDrawFrame(final GL10 gl) {
try {
if (renderingElapsedTime * NANOSECONDSPERMICROSECOND < Cocos2dxRenderer.sAnimationInterval) {
Thread.sleep((Cocos2dxRenderer.sAnimationInterval - renderingElapsedTime * NANOSECONDSPERMICROSECOND) / NANOSECONDSPERMICROSECOND);
}
} catch (InterruptedException e) {
e.printStackTrace();
}

// Get the timestamp when rendering started
long renderingStartedTimestamp = System.currentTimeMillis();

// should render a frame when onDrawFrame() is called or there is a
// "ghost"
Cocos2dxRenderer.nativeRender();

// Calculate the elapsed time during rendering
renderingElapsedTime = (System.currentTimeMillis() - renderingStartedTimestamp);
}代码中将渲染消耗的时间算进去,所以得到的帧率应该来说非常准确了。

注意,Cocos2dxRenderer中的onDrawFrame官方有实现好的帧率算法,但是被注释掉了,注释文本说存在一定的bug,帧率不精确,实际上大部分情况都可已正常使用,所以最好不要采用了~

这么做了之后,游戏的帧率在38~41左右,发热的问题也基本解决了。

最后,如果你要更好,更精确的帧率算法,也可以留言回复... 查看全部
使用Cocos2d-x 3.0开发游戏之后,发现游戏在android手机上发热非常严重,在魅族2上,几乎担心手机会爆炸了~~~采取的一个措施就是降低帧率,因为游戏对于帧率要求不是非常高。

做过cocos2d开发的同学应该都知道在win32平台修改帧率的方式非常简单,就是在AppDelegate.cpp文件中修改:
director->setAnimationInterval(1.0 / 40);
但是这种修改方式在导出android安卓apk到真机测试的时候,发现左下角的调试信息还是现实60~65帧,完全不受影响,网上搜索之后,发小安卓的修改需要修改cocos2dx-x生成的java代码中修改,具体在文件:Cocos2dxRenderer.java

在代码中可以看到以下的属性设置和重写的方法:
private static long sAnimationInterval = (long) (1.0 / 60 * Cocos2dxRenderer.NANOSECONDSPERSECOND);
public void onDrawFrame(final GL10 gl) {}
如果要修改android平台的帧率,可以通过修改这些代码来改进,具体的操作方法如下:

1.修改帧率将60改成40
private static long sAnimationInterval = (long) (1.0 / 40 * Cocos2dxRenderer.NANOSECONDSPERSECOND);
2.增加一个属性变量
private long renderingElapsedTime = 0;
3.重写渲染方法onDrawFrame
@Override
public void onDrawFrame(final GL10 gl) {
try {
if (renderingElapsedTime * NANOSECONDSPERMICROSECOND < Cocos2dxRenderer.sAnimationInterval) {
Thread.sleep((Cocos2dxRenderer.sAnimationInterval - renderingElapsedTime * NANOSECONDSPERMICROSECOND) / NANOSECONDSPERMICROSECOND);
}
} catch (InterruptedException e) {
e.printStackTrace();
}

// Get the timestamp when rendering started
long renderingStartedTimestamp = System.currentTimeMillis();

// should render a frame when onDrawFrame() is called or there is a
// "ghost"
Cocos2dxRenderer.nativeRender();

// Calculate the elapsed time during rendering
renderingElapsedTime = (System.currentTimeMillis() - renderingStartedTimestamp);
}
代码中将渲染消耗的时间算进去,所以得到的帧率应该来说非常准确了。

注意,Cocos2dxRenderer中的onDrawFrame官方有实现好的帧率算法,但是被注释掉了,注释文本说存在一定的bug,帧率不精确,实际上大部分情况都可已正常使用,所以最好不要采用了~

这么做了之后,游戏的帧率在38~41左右,发热的问题也基本解决了。

最后,如果你要更好,更精确的帧率算法,也可以留言回复...

用cocos2dx开发的游戏,玩一段时间就会手机发热,哪位大神知道怎么解决吗?

回复

移动开发atool 回复了问题 • 2 人关注 • 1 个回复 • 3194 次浏览 • 2016-06-09 11:10 • 来自相关话题

Cocos2d-x Lua/Javascript脚本代码加密实现

游戏开发atool 发表了文章 • 0 个评论 • 628 次浏览 • 2016-04-22 14:15 • 来自相关话题

在游戏开发中,脚本作为一种资源文件,就像图片视频一样,被引擎所引用,使用脚本做游戏的好处就在于可以在线patch更新,特别对于苹果App Store审核期很长的情况。

如果不对脚本进行加密,不怀好意的人松松解压出脚本文件,给你瞬间复制一个游戏出来。

1.异或加密解密

最简单的一种加密方式,虽然简单,但是也比较实用。但是防破解方面确实一般,如果你有其他严格的仿破解需求,可以将这部分加密算法换成你自己的复杂算法,不过保证解密效率。下面是采用C++简单实现的对文件进行加密之后保存到原文件中(注意对原始未加密文件进行备份)
#include "stdafx.h"
#include<iostream>
#include<ctime>
#include<fstream>
using namespace std;
void Makecode(char *pstr,int *pkey);
void Cutecode(char *pstr,int *pkey);
void encode_file(char *f);
int _tmain(int argc, _TCHAR* argv[])
{
encode_file("e:/src/ResultScene.lua");
/*
encode_file("e:/src/ReadyScene.lua");
encode_file("e:/src/GameScene.lua");
encode_file("e:/src/PutHeadScene.lua");
encode_file("e:/src/TutorialsScene.lua");
encode_file("e:/src/WordsCategoryScene.lua");
encode_file("e:/src/common/DictHelper.lua");
encode_file("e:/src/common/LJ.lua");
encode_file("e:/src/common/DQueue.lua");
encode_file("e:/src/common/UIHelper.lua");
*/
int c;
cin>>c;
return 0;
}
void encode_file(char *f)
{
FILE *fp = NULL;
fopen_s(&fp, f,"rb");
fseek(fp,0,SEEK_END); //定位到文件末
int nFileLen = ftell(fp); //文件长度
cout << "file len = " << nFileLen << endl;
fseek(fp, 0, SEEK_SET);
char *fileContent = NULL;
fileContent = (char *) malloc ((nFileLen + 1) * sizeof(char));//增加一位
memset(fileContent, 0, nFileLen + 1);
fileContent[nFileLen] = '';//最后一位置为结束位
fread_s(fileContent,nFileLen, 1, nFileLen, fp);
//fread(buf,nFileLen, 1, fp);
//cout<<"解密前:"<<fileContent<<endl;
fclose(fp);
cout<<"文件:"<<f<<endl;
cout<<"解密前文件大小:"<<strlen(fileContent)<<endl;
int key[]={1, 2, 6, 1, 2, 6};//加密字符
char *p=fileContent;
cout<<"====="<<endl;
Makecode(fileContent,key);//加密
//cout<<"加密后:"<<p<<endl;
cout<<"加密后文件大小:"<<strlen(fileContent)<<endl;
FILE *stream = NULL;
fopen_s(&stream, f,"wb");
if (stream == NULL) /* open file TEST.$$$ */
{
fprintf(stderr, "Cannot open output file.
");
}
else {
fwrite(p, nFileLen, 1, stream); /* 写的struct文件*/
fclose(stream); /*关闭文件*/
}
cout<<"====="<<endl;
Cutecode(fileContent,key);//解密
//cout<<"解密后:"<<fileContent<<endl;
}
//单个字符异或运算
char MakecodeChar(char c,int key){
return c=c^key;
}
//单个字符解密
char CutcodeChar(char c,int key){
return c^key;
}
//加密
void Makecode(char *pstr,int *pkey){
int len=strlen(pstr);//获取长度
for(int i=0;i<len;i++)
*(pstr+i)=MakecodeChar(*(pstr+i),pkey[i%5]);
}
//解密
void Cutecode(char *pstr,int *pkey){
int len=strlen(pstr);
for(int i=0;i<len;i++)
*(pstr+i)=CutcodeChar(*(pstr+i),pkey[i%5]);
}2.修改Cocos2d-x引擎中加载lua脚本文件(或者js文件)的入口,在加载的时候对其进行解密。可能不同版本引擎有不同的入口文件,在Cocos2d-x3.0中,对应的是文件Cocos2dxLuaLoader.cpp文件中的int cocos2dx_lua_loader(lua_State *L)方法,对其进行修改成如下:
#include "Cocos2dxLuaLoader.h"
#include <string>
#include <algorithm>
#include<iostream>
using namespace cocos2d;
extern "C"
{
//单个字符异或运算
char MakecodeChar(char c,int key){
return c=c^key;
}
//单个字符解密
char CutcodeChar(char c,int key){
return c^key;
}
//加密
void Makecode(char *pstr,int *pkey){
int len=strlen(pstr);//获取长度
for(int i=0;i<len;i++)
*(pstr+i)=MakecodeChar(*(pstr+i),pkey[i%5]);
}
//解密
void Cutecode(char *pstr,int *pkey){
int len=strlen(pstr);
for(int i=0;i<len;i++)
*(pstr+i)=CutcodeChar(*(pstr+i),pkey[i%5]);
}
int cocos2dx_lua_loader(lua_State *L)
{
std::string filename(luaL_checkstring(L, 1));
size_t pos = filename.rfind(".lua");
if (pos != std::string::npos)
{
filename = filename.substr(0, pos);
}

pos = filename.find_first_of(".");
while (pos != std::string::npos)
{
filename.replace(pos, 1, "/");
pos = filename.find_first_of(".");
}
filename.append(".lua");

Data data = FileUtils::getInstance()->getDataFromFile(filename);

if (!data.isNull())
{

//====code decode start==================================
log("===encode filename:%s===", filename.c_str());
//如果filename == 'main.lua',则解密
char *fileContent = (char*)data.getBytes();
int key[]={1, 2, 6, 1, 2, 6};//加密字符
char *fileContentDecoded = NULL;
if (strcmp(filename.c_str(),"ReadyScene.lua")==0 ||
strcmp(filename.c_str(),"GameScene.lua")==0 ||
strcmp(filename.c_str(),"PutHeadScene.lua")==0 ||
strcmp(filename.c_str(),"TutorialsScene.lua")==0 ||
strcmp(filename.c_str(),"WordsCategoryScene.lua")==0 ||
strcmp(filename.c_str(),"DictHelper.lua")==0 ||
strcmp(filename.c_str(),"LJ.lua")==0 ||
strcmp(filename.c_str(),"ResultScene.lua")==0 ||
strcmp(filename.c_str(),"DQueue.lua")==0 ||
strcmp(filename.c_str(),"UIHelper.lua")==0 ) {
if (data.getSize() < strlen(fileContent)) {
fileContentDecoded = (char *) malloc ((data.getSize() + 1) * sizeof(char));//增加一位
memset(fileContentDecoded, 0, data.getSize() + 1);
fileContentDecoded[data.getSize()] = '';//最后一位置为结束位
strncpy(fileContentDecoded,fileContent,data.getSize());
fileContent = NULL;
}
else {
fileContentDecoded = fileContent;
}
Cutecode(fileContentDecoded,key);//解密
}
else {
fileContentDecoded = fileContent;
}
//====code decode end==================================

if (luaL_loadbuffer(L, fileContentDecoded, data.getSize(), filename.c_str()) != 0)
{
luaL_error(L, "error loading module %s from file %s :
%s",
lua_tostring(L, 1), filename.c_str(), lua_tostring(L, -1));
}
}
else
{
log("can not get file data of %s", filename.c_str());
}
return 1;
}
}注意加密解密的key保证一致。

代码注释应该挺完善的,不进行解释了,Enjoy~ 查看全部
在游戏开发中,脚本作为一种资源文件,就像图片视频一样,被引擎所引用,使用脚本做游戏的好处就在于可以在线patch更新,特别对于苹果App Store审核期很长的情况。

如果不对脚本进行加密,不怀好意的人松松解压出脚本文件,给你瞬间复制一个游戏出来。

1.异或加密解密

最简单的一种加密方式,虽然简单,但是也比较实用。但是防破解方面确实一般,如果你有其他严格的仿破解需求,可以将这部分加密算法换成你自己的复杂算法,不过保证解密效率。下面是采用C++简单实现的对文件进行加密之后保存到原文件中(注意对原始未加密文件进行备份)
#include "stdafx.h"
#include<iostream>
#include<ctime>
#include<fstream>
using namespace std;
void Makecode(char *pstr,int *pkey);
void Cutecode(char *pstr,int *pkey);
void encode_file(char *f);
int _tmain(int argc, _TCHAR* argv[])
{
encode_file("e:/src/ResultScene.lua");
/*
encode_file("e:/src/ReadyScene.lua");
encode_file("e:/src/GameScene.lua");
encode_file("e:/src/PutHeadScene.lua");
encode_file("e:/src/TutorialsScene.lua");
encode_file("e:/src/WordsCategoryScene.lua");
encode_file("e:/src/common/DictHelper.lua");
encode_file("e:/src/common/LJ.lua");
encode_file("e:/src/common/DQueue.lua");
encode_file("e:/src/common/UIHelper.lua");
*/
int c;
cin>>c;
return 0;
}
void encode_file(char *f)
{
FILE *fp = NULL;
fopen_s(&fp, f,"rb");
fseek(fp,0,SEEK_END); //定位到文件末
int nFileLen = ftell(fp); //文件长度
cout << "file len = " << nFileLen << endl;
fseek(fp, 0, SEEK_SET);
char *fileContent = NULL;
fileContent = (char *) malloc ((nFileLen + 1) * sizeof(char));//增加一位
memset(fileContent, 0, nFileLen + 1);
fileContent[nFileLen] = '';//最后一位置为结束位
fread_s(fileContent,nFileLen, 1, nFileLen, fp);
//fread(buf,nFileLen, 1, fp);
//cout<<"解密前:"<<fileContent<<endl;
fclose(fp);
cout<<"文件:"<<f<<endl;
cout<<"解密前文件大小:"<<strlen(fileContent)<<endl;
int key[]={1, 2, 6, 1, 2, 6};//加密字符
char *p=fileContent;
cout<<"====="<<endl;
Makecode(fileContent,key);//加密
//cout<<"加密后:"<<p<<endl;
cout<<"加密后文件大小:"<<strlen(fileContent)<<endl;
FILE *stream = NULL;
fopen_s(&stream, f,"wb");
if (stream == NULL) /* open file TEST.$$$ */
{
fprintf(stderr, "Cannot open output file.
");
}
else {
fwrite(p, nFileLen, 1, stream); /* 写的struct文件*/
fclose(stream); /*关闭文件*/
}
cout<<"====="<<endl;
Cutecode(fileContent,key);//解密
//cout<<"解密后:"<<fileContent<<endl;
}
//单个字符异或运算
char MakecodeChar(char c,int key){
return c=c^key;
}
//单个字符解密
char CutcodeChar(char c,int key){
return c^key;
}
//加密
void Makecode(char *pstr,int *pkey){
int len=strlen(pstr);//获取长度
for(int i=0;i<len;i++)
*(pstr+i)=MakecodeChar(*(pstr+i),pkey[i%5]);
}
//解密
void Cutecode(char *pstr,int *pkey){
int len=strlen(pstr);
for(int i=0;i<len;i++)
*(pstr+i)=CutcodeChar(*(pstr+i),pkey[i%5]);
}
2.修改Cocos2d-x引擎中加载lua脚本文件(或者js文件)的入口,在加载的时候对其进行解密。可能不同版本引擎有不同的入口文件,在Cocos2d-x3.0中,对应的是文件Cocos2dxLuaLoader.cpp文件中的int cocos2dx_lua_loader(lua_State *L)方法,对其进行修改成如下:
#include "Cocos2dxLuaLoader.h"
#include <string>
#include <algorithm>
#include<iostream>
using namespace cocos2d;
extern "C"
{
//单个字符异或运算
char MakecodeChar(char c,int key){
return c=c^key;
}
//单个字符解密
char CutcodeChar(char c,int key){
return c^key;
}
//加密
void Makecode(char *pstr,int *pkey){
int len=strlen(pstr);//获取长度
for(int i=0;i<len;i++)
*(pstr+i)=MakecodeChar(*(pstr+i),pkey[i%5]);
}
//解密
void Cutecode(char *pstr,int *pkey){
int len=strlen(pstr);
for(int i=0;i<len;i++)
*(pstr+i)=CutcodeChar(*(pstr+i),pkey[i%5]);
}
int cocos2dx_lua_loader(lua_State *L)
{
std::string filename(luaL_checkstring(L, 1));
size_t pos = filename.rfind(".lua");
if (pos != std::string::npos)
{
filename = filename.substr(0, pos);
}

pos = filename.find_first_of(".");
while (pos != std::string::npos)
{
filename.replace(pos, 1, "/");
pos = filename.find_first_of(".");
}
filename.append(".lua");

Data data = FileUtils::getInstance()->getDataFromFile(filename);

if (!data.isNull())
{

//====code decode start==================================
log("===encode filename:%s===", filename.c_str());
//如果filename == 'main.lua',则解密
char *fileContent = (char*)data.getBytes();
int key[]={1, 2, 6, 1, 2, 6};//加密字符
char *fileContentDecoded = NULL;
if (strcmp(filename.c_str(),"ReadyScene.lua")==0 ||
strcmp(filename.c_str(),"GameScene.lua")==0 ||
strcmp(filename.c_str(),"PutHeadScene.lua")==0 ||
strcmp(filename.c_str(),"TutorialsScene.lua")==0 ||
strcmp(filename.c_str(),"WordsCategoryScene.lua")==0 ||
strcmp(filename.c_str(),"DictHelper.lua")==0 ||
strcmp(filename.c_str(),"LJ.lua")==0 ||
strcmp(filename.c_str(),"ResultScene.lua")==0 ||
strcmp(filename.c_str(),"DQueue.lua")==0 ||
strcmp(filename.c_str(),"UIHelper.lua")==0 ) {
if (data.getSize() < strlen(fileContent)) {
fileContentDecoded = (char *) malloc ((data.getSize() + 1) * sizeof(char));//增加一位
memset(fileContentDecoded, 0, data.getSize() + 1);
fileContentDecoded[data.getSize()] = '';//最后一位置为结束位
strncpy(fileContentDecoded,fileContent,data.getSize());
fileContent = NULL;
}
else {
fileContentDecoded = fileContent;
}
Cutecode(fileContentDecoded,key);//解密
}
else {
fileContentDecoded = fileContent;
}
//====code decode end==================================

if (luaL_loadbuffer(L, fileContentDecoded, data.getSize(), filename.c_str()) != 0)
{
luaL_error(L, "error loading module %s from file %s :
%s",
lua_tostring(L, 1), filename.c_str(), lua_tostring(L, -1));
}
}
else
{
log("can not get file data of %s", filename.c_str());
}
return 1;
}
}
注意加密解密的key保证一致。

代码注释应该挺完善的,不进行解释了,Enjoy~

cocos2d-x中使用FMOD音效引擎基本知识介绍

游戏开发atool 发表了文章 • 0 个评论 • 2060 次浏览 • 2016-04-22 13:23 • 来自相关话题

大致研究了2.5天的Fmod音效引擎,从对音效没有什么概念到有一点点理解。fmod是一个很不错的音效引擎,从它的API demo运行效果可以感受到引擎音效非常好,它提供了很简单的API来控制音效的3D播放特性。

一、FMOD引擎API版本介绍

fmod引擎api因为其版本的原因,分成两种:

1. 对应FMOD Designer版本的API,FMOD Designer为旧版本引擎,导出文件为fev和fsb,fev定义为音效的播放规则,音乐索引(大致可以这么理解)等;fsb主要是音乐文件的打包,目前音效组使用的FMOD Designer做音效开发。

2. 对应FMOD Studio版本的API,FMOD Studio是新版本引擎,导出文件为.bank文件,其中包含有播放规则,音乐索引,音乐文件(新版本将旧版本中的两个导出文件变成一个,提供了一个很好的特性:可以播放apk中的音效文件)。

二、在cocos2d-x中FMOD API调用方式

同样有两种途径:

1. 使用FMOD提供的android api和ios api分别开发播放接口,然后再lua中调用。

    1.1 优点在于难点少,相比方法2简单。

    1.2 缺点在于需要做两套代码,工作量大,另外一个致命的问题是:音效延迟播放(因为LUA调用Java只能是静态方法,所以在Java采用线程扫描状态的方式,存在一定的播放延迟),个人觉得对于音效来说不能忍,人的视觉几乎无法区分1/60s内的变换,但是听觉就不一样了。点击一个按钮,在20ms内响应完全没有问题,但是如果声音在20ms后播放就存在很大的问题了。

2. 使用FMOD的cpp接口,首先在cocos2d-x的底层平台写好cpp的播放代码接口,然后采用tolua++导出lua可以使用的内库,然后编写lua调用的接口,最后可以在cocos2d-x + lua上进行播放。

    1.1 优点在于跨平台,一次解决可以适用于android和ios,同时对于以后的项目也可以直接使用,非常有必要做这个工作。

    1.2 缺点在于难点多,漏洞多,涉及到cocos2d-x底层接口开发,以及cpp和lua之间的接口开发,这些之前都没有做过,难度比较大,另外,涉及到cpp底层代码,容易造成一些难以解决的漏洞。

三、FMOD Designer VS FMOD Studio

两个版本一个旧,一个新,大致说说他们最致命的问题:

1. FMOD Designer公司音效人员在使用,这是其优点,但是FMOD Designer版本的缺点很明显就是在android平台无法播放apk中的音效,这意味着和PC游戏一样,安装工程或者第一次运行的时候需要解压apk中的音效文件到应用目录中,并且在以后的每次运行过程中必须检测音效文件是否存在,如果不存在或者缺失,需要将音效重写解压出来。这不仅增加游戏的另一份工作量,也减少了游戏的运行效率。(一般的手机清理软件都会造成app,目录被删除)

2. FMOD Studio新版本很好的一个特性就是可以直接读取apk中音效文件(网络上关于FMOD资源不多,这一点还是发邮件和官方沟通得知的);但是FMOD Studio并没有被公司音效使用。

四、FMOD适用环境

FMOD具有很简单的API操作,并提供不简单的3D音效特性,然而在cocos2d-x中使用FMOD引擎需要做引擎文件的解析操作,会增加一定的工作量,因此建议在游戏存在3D特性的情况下使用,例如:音效距离、音效方向、音效源移动等情况使用;而在一般的UI界面操作中不要使用fmod,而是使用普通的wav,mp3,ogg等cocos2d-x可以解析的音效即可。 查看全部
大致研究了2.5天的Fmod音效引擎,从对音效没有什么概念到有一点点理解。fmod是一个很不错的音效引擎,从它的API demo运行效果可以感受到引擎音效非常好,它提供了很简单的API来控制音效的3D播放特性。

一、FMOD引擎API版本介绍

fmod引擎api因为其版本的原因,分成两种:

1. 对应FMOD Designer版本的API,FMOD Designer为旧版本引擎,导出文件为fev和fsb,fev定义为音效的播放规则,音乐索引(大致可以这么理解)等;fsb主要是音乐文件的打包,目前音效组使用的FMOD Designer做音效开发。

2. 对应FMOD Studio版本的API,FMOD Studio是新版本引擎,导出文件为.bank文件,其中包含有播放规则,音乐索引,音乐文件(新版本将旧版本中的两个导出文件变成一个,提供了一个很好的特性:可以播放apk中的音效文件)。

二、在cocos2d-x中FMOD API调用方式

同样有两种途径:

1. 使用FMOD提供的android api和ios api分别开发播放接口,然后再lua中调用。

    1.1 优点在于难点少,相比方法2简单。

    1.2 缺点在于需要做两套代码,工作量大,另外一个致命的问题是:音效延迟播放(因为LUA调用Java只能是静态方法,所以在Java采用线程扫描状态的方式,存在一定的播放延迟),个人觉得对于音效来说不能忍,人的视觉几乎无法区分1/60s内的变换,但是听觉就不一样了。点击一个按钮,在20ms内响应完全没有问题,但是如果声音在20ms后播放就存在很大的问题了。

2. 使用FMOD的cpp接口,首先在cocos2d-x的底层平台写好cpp的播放代码接口,然后采用tolua++导出lua可以使用的内库,然后编写lua调用的接口,最后可以在cocos2d-x + lua上进行播放。

    1.1 优点在于跨平台,一次解决可以适用于android和ios,同时对于以后的项目也可以直接使用,非常有必要做这个工作。

    1.2 缺点在于难点多,漏洞多,涉及到cocos2d-x底层接口开发,以及cpp和lua之间的接口开发,这些之前都没有做过,难度比较大,另外,涉及到cpp底层代码,容易造成一些难以解决的漏洞。

三、FMOD Designer VS FMOD Studio

两个版本一个旧,一个新,大致说说他们最致命的问题:

1. FMOD Designer公司音效人员在使用,这是其优点,但是FMOD Designer版本的缺点很明显就是在android平台无法播放apk中的音效,这意味着和PC游戏一样,安装工程或者第一次运行的时候需要解压apk中的音效文件到应用目录中,并且在以后的每次运行过程中必须检测音效文件是否存在,如果不存在或者缺失,需要将音效重写解压出来。这不仅增加游戏的另一份工作量,也减少了游戏的运行效率。(一般的手机清理软件都会造成app,目录被删除)

2. FMOD Studio新版本很好的一个特性就是可以直接读取apk中音效文件(网络上关于FMOD资源不多,这一点还是发邮件和官方沟通得知的);但是FMOD Studio并没有被公司音效使用。

四、FMOD适用环境

FMOD具有很简单的API操作,并提供不简单的3D音效特性,然而在cocos2d-x中使用FMOD引擎需要做引擎文件的解析操作,会增加一定的工作量,因此建议在游戏存在3D特性的情况下使用,例如:音效距离、音效方向、音效源移动等情况使用;而在一般的UI界面操作中不要使用fmod,而是使用普通的wav,mp3,ogg等cocos2d-x可以解析的音效即可。

Cocos2d-x 横屏竖屏异常uncaught exception“UIApplicationInvalidInterfaceOrientation”

游戏开发atool 发表了文章 • 0 个评论 • 822 次浏览 • 2016-04-22 13:18 • 来自相关话题

在Cocos2d-x横屏游戏中集成社会化分享的时候,会出现异常

*** Terminating app due to uncaught exception 'UIApplicationInvalidInterfaceOrientation', reason: 'Supported orientations has no common orientation with the application, and shouldAutorotate is returning YES'

大致意思是cocos2d-x游戏设置的可支持屏幕方式找不到需要的方向。这是因为游戏中设置的是只支持横屏方式,但是在RootViewController中shouldAutorotate返回的又是YES,恰好分享的时候弹出的授权页面时竖屏的,所以弹出框自动旋转到竖屏,确又找不到可以支持的竖屏方向,所以抛出异常,程序也卡死了,解决办法如下,仅仅针对于Cocos2d-x代码,其他APP如果出现类似问题,可以参考:

1.AppController.mm加入方法
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
return UIInterfaceOrientationMaskAll;
}
else {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
}2.RootViewController.mm 加入方法
//For ios6, use supportedInterfaceOrientations & shouldAutorotate instead
- (NSUInteger) supportedInterfaceOrientations{
#ifdef __IPHONE_6_0
return UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskLandscapeLeft;//方向也可以仅定义为横屏中的一个方向
#endif
}如此就可以了,反正我是解决了~兼容性已测,不存在问题!Enjoy~ 查看全部
在Cocos2d-x横屏游戏中集成社会化分享的时候,会出现异常

*** Terminating app due to uncaught exception 'UIApplicationInvalidInterfaceOrientation', reason: 'Supported orientations has no common orientation with the application, and shouldAutorotate is returning YES'

大致意思是cocos2d-x游戏设置的可支持屏幕方式找不到需要的方向。这是因为游戏中设置的是只支持横屏方式,但是在RootViewController中shouldAutorotate返回的又是YES,恰好分享的时候弹出的授权页面时竖屏的,所以弹出框自动旋转到竖屏,确又找不到可以支持的竖屏方向,所以抛出异常,程序也卡死了,解决办法如下,仅仅针对于Cocos2d-x代码,其他APP如果出现类似问题,可以参考:

1.AppController.mm加入方法
-(NSUInteger)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
return UIInterfaceOrientationMaskAll;
}
else {
return UIInterfaceOrientationMaskAllButUpsideDown;
}
}
2.RootViewController.mm 加入方法
//For ios6, use supportedInterfaceOrientations & shouldAutorotate instead
- (NSUInteger) supportedInterfaceOrientations{
#ifdef __IPHONE_6_0
return UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskLandscapeLeft;//方向也可以仅定义为横屏中的一个方向
#endif
}
如此就可以了,反正我是解决了~兼容性已测,不存在问题!Enjoy~

Cocos2d-x android使用onKeyDown监听返回键实现二次返回退出

游戏开发atool 发表了文章 • 0 个评论 • 2453 次浏览 • 2016-04-22 13:16 • 来自相关话题

一般的游戏或者软件,都会在android版本上做退出程序的功能,一般的实现方式有两种:

1.点击返回按键,弹出确认是否退出;

2.点击返回,toast提示再次点击退出程序。

这两种方式实现都需要android上监听用户按下了android手机上的返回键,监听到了之后执行相应的操作。

通过搜索,很容易知道可以实现activity类的方法
public boolean onKeyDown(final int pKeyCode, final KeyEvent pKeyEvent)实现对用户按键的监听,但是将代码加入到cocos2d-x生成的Java代码中的AppActivity中,发现根本不起作用,没法监听到用户的按键操作,找官方api文档,发现:

public boolean onKeyDown (int keyCode, KeyEvent event)

Since: API Level 1

Called when a key was pressed down and not handled by any of the views inside of the activity. So, for example, key presses while the cursor is inside a TextView will not trigger the event (unless it is a navigation to another object) because TextView handles its own key presses.

If the focused view didn't want this event, this method is called.

这段文字我需要强调的是红色标记部分,翻译的意思是:当用户按下一个按键的时候调用,但是前提是这个事件没有被其他的任何views监听并处理。

因此不难得知,在cocos2d-x游戏中,在实现的onKeyDown方法监听不到返回键,是因为这个返回键事件已经被其他的onKeyDown处理掉了,具体是谁呢?看cocos2d-x的android版本代码(framework/scocos2d-x/cocos/2d/platform/android/java/src/org/cocos2dx/lib/Cocos2dx/GLSurfaceView.java)。其中实现了onKeyDown方法:
@Override
public boolean onKeyDown(final int pKeyCode, final KeyEvent pKeyEvent) {
switch (pKeyCode) {
case KeyEvent.KEYCODE_BACK:

case KeyEvent.KEYCODE_MENU:
this.queueEvent(new Runnable() {
@Override
public void run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleKeyDown(pKeyCode);
}
});
return true;
default:
return super.onKeyDown(pKeyCode, pKeyEvent);
}
}这个里面,按键KeyEvent.KEYCODE_BACK被监听了,只要在这里不作处理即可(return false),改成如下代码:
@Override
public boolean onKeyDown(final int pKeyCode, final KeyEvent pKeyEvent) {
switch (pKeyCode) {
case KeyEvent.KEYCODE_BACK:
return false;
case KeyEvent.KEYCODE_MENU:
this.queueEvent(new Runnable() {
@Override
public void run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleKeyDown(pKeyCode);
}
});
return true;
default:
return super.onKeyDown(pKeyCode, pKeyEvent);
}
}这样在你自己的cocos2d-x游戏Activity中就可以监听返回键了,在AppActivity中重写onKeyDown方法,如下:
private long mkeyTime = 0;
public boolean onKeyDown(int keyCode, KeyEvent event) {
//二次返回退出
if (keyCode == KeyEvent.KEYCODE_BACK) {
if ((System.currentTimeMillis() - mkeyTime) > 2000) {
mkeyTime = System.currentTimeMillis();
Toast.makeText(this, "再按一次退出游戏", Toast.LENGTH_LONG).show();
} else {
finish();
System.exit(0);
}
return false;
}
return super.onKeyDown(keyCode, event);
}然后运行游戏, 点击返回键试试,有没有Toast?Enjoy~ 查看全部
一般的游戏或者软件,都会在android版本上做退出程序的功能,一般的实现方式有两种:

1.点击返回按键,弹出确认是否退出;

2.点击返回,toast提示再次点击退出程序。

这两种方式实现都需要android上监听用户按下了android手机上的返回键,监听到了之后执行相应的操作。

通过搜索,很容易知道可以实现activity类的方法
public boolean onKeyDown(final int pKeyCode, final KeyEvent pKeyEvent)
实现对用户按键的监听,但是将代码加入到cocos2d-x生成的Java代码中的AppActivity中,发现根本不起作用,没法监听到用户的按键操作,找官方api文档,发现:

public boolean onKeyDown (int keyCode, KeyEvent event)

Since: API Level 1

Called when a key was pressed down and not handled by any of the views inside of the activity. So, for example, key presses while the cursor is inside a TextView will not trigger the event (unless it is a navigation to another object) because TextView handles its own key presses.

If the focused view didn't want this event, this method is called.

这段文字我需要强调的是红色标记部分,翻译的意思是:当用户按下一个按键的时候调用,但是前提是这个事件没有被其他的任何views监听并处理。

因此不难得知,在cocos2d-x游戏中,在实现的onKeyDown方法监听不到返回键,是因为这个返回键事件已经被其他的onKeyDown处理掉了,具体是谁呢?看cocos2d-x的android版本代码(framework/scocos2d-x/cocos/2d/platform/android/java/src/org/cocos2dx/lib/Cocos2dx/GLSurfaceView.java)。其中实现了onKeyDown方法:
@Override
public boolean onKeyDown(final int pKeyCode, final KeyEvent pKeyEvent) {
switch (pKeyCode) {
case KeyEvent.KEYCODE_BACK:

case KeyEvent.KEYCODE_MENU:
this.queueEvent(new Runnable() {
@Override
public void run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleKeyDown(pKeyCode);
}
});
return true;
default:
return super.onKeyDown(pKeyCode, pKeyEvent);
}
}
这个里面,按键KeyEvent.KEYCODE_BACK被监听了,只要在这里不作处理即可(return false),改成如下代码:
@Override
public boolean onKeyDown(final int pKeyCode, final KeyEvent pKeyEvent) {
switch (pKeyCode) {
case KeyEvent.KEYCODE_BACK:
return false;
case KeyEvent.KEYCODE_MENU:
this.queueEvent(new Runnable() {
@Override
public void run() {
Cocos2dxGLSurfaceView.this.mCocos2dxRenderer.handleKeyDown(pKeyCode);
}
});
return true;
default:
return super.onKeyDown(pKeyCode, pKeyEvent);
}
}
这样在你自己的cocos2d-x游戏Activity中就可以监听返回键了,在AppActivity中重写onKeyDown方法,如下:
private long mkeyTime = 0;
public boolean onKeyDown(int keyCode, KeyEvent event) {
//二次返回退出
if (keyCode == KeyEvent.KEYCODE_BACK) {
if ((System.currentTimeMillis() - mkeyTime) > 2000) {
mkeyTime = System.currentTimeMillis();
Toast.makeText(this, "再按一次退出游戏", Toast.LENGTH_LONG).show();
} else {
finish();
System.exit(0);
}
return false;
}
return super.onKeyDown(keyCode, event);
}
然后运行游戏, 点击返回键试试,有没有Toast?Enjoy~

xcode编译cocos2d-x 3.0及以上版本支持arm64位

游戏开发atool 发表了文章 • 0 个评论 • 2501 次浏览 • 2016-04-22 13:05 • 来自相关话题

在使用cocos2d-x 3.0rc lua版本完成游戏过程中,真机存在一个问题:

1. 使用iphone4s真机调试,可以正常运行通过;

2. 使用iphone4s以上版本真机调试的时候,不能够正常编译,出现的的错误是cc命名空间下的很多方法找不到,具体都是cocos2d-x的代码找不到。

虽然直接使用iphone4s连接手机,achieve出来的ipa包也可以在所有ios设备上运行,但是提交appstore的时候,就会出现错误:ERROR ITMS-90086:"missing 64-bit support. beginning on february 1, 2015, new iOS apps submitted to the app store must be include 64-bit support and be built with the ios8 SDK......"。




大致意思是app store从2015年2月1号开始,不再接受不支持64位的app上线。

解决办法如下:

1.将所有的cocos2d-x xcode项目的project和target中的building-setting设置项中的architectures、supported platforms、validarchitectures,另外非常重要的一个配置是build active architecture only全部设置为No。下图所示:




需要修改p2,cocos2d_lua_bindings.xcodeproj, cocos2d_libs.xcodeproj三个项目中的building-setting。如下图所示:




修改之后,就会发现之前出现的“cc命名空间下的很多方法找不到”的错误都消失了,出现的都是关于图片读取的问题,这个问题解决见步骤2;

2.因为cocos2d-x3.0rc版本没有将图片相关的64位库加入,引入相关的图片读取解析的64位库;如下图所示:




具体就是上述中_arm64.a结尾的库。

上述问题解决了,但是又出现lua里面的方法找不到的错误,解决办法见步骤3;

3.由于cocos2d-x3.0rc使用的是luajit,但是只引入了libluagit.a库,这个库是32位的,所以无法编译64位,于是找到一个liblua.a的库,引入lua.a到项目即可。如下图:




三步完成,问题全部解决,打包,重签,测试,没有任何问题。

Enjoy~
  查看全部
在使用cocos2d-x 3.0rc lua版本完成游戏过程中,真机存在一个问题:

1. 使用iphone4s真机调试,可以正常运行通过;

2. 使用iphone4s以上版本真机调试的时候,不能够正常编译,出现的的错误是cc命名空间下的很多方法找不到,具体都是cocos2d-x的代码找不到。

虽然直接使用iphone4s连接手机,achieve出来的ipa包也可以在所有ios设备上运行,但是提交appstore的时候,就会出现错误:ERROR ITMS-90086:"missing 64-bit support. beginning on february 1, 2015, new iOS apps submitted to the app store must be include 64-bit support and be built with the ios8 SDK......"。
111.png

大致意思是app store从2015年2月1号开始,不再接受不支持64位的app上线。

解决办法如下:

1.将所有的cocos2d-x xcode项目的project和target中的building-setting设置项中的architectures、supported platforms、validarchitectures,另外非常重要的一个配置是build active architecture only全部设置为No。下图所示:
222.png

需要修改p2,cocos2d_lua_bindings.xcodeproj, cocos2d_libs.xcodeproj三个项目中的building-setting。如下图所示:
333.png

修改之后,就会发现之前出现的“cc命名空间下的很多方法找不到”的错误都消失了,出现的都是关于图片读取的问题,这个问题解决见步骤2;

2.因为cocos2d-x3.0rc版本没有将图片相关的64位库加入,引入相关的图片读取解析的64位库;如下图所示:
444.png

具体就是上述中_arm64.a结尾的库。

上述问题解决了,但是又出现lua里面的方法找不到的错误,解决办法见步骤3;

3.由于cocos2d-x3.0rc使用的是luajit,但是只引入了libluagit.a库,这个库是32位的,所以无法编译64位,于是找到一个liblua.a的库,引入lua.a到项目即可。如下图:
555.png

三步完成,问题全部解决,打包,重签,测试,没有任何问题。

Enjoy~
 

Cocos2d-x 3.0修改Android平台帧率fps - 解决游戏运行手机发热发烫问题

游戏开发atool 发表了文章 • 2 个评论 • 2468 次浏览 • 2016-04-22 13:01 • 来自相关话题

使用Cocos2d-x 3.0开发游戏之后,发现游戏在android手机上发热非常严重,在魅族2上,几乎担心手机会爆炸了~~~采取的一个措施就是降低帧率,因为游戏对于帧率要求不是非常高。

做过cocos2d开发的同学应该都知道在win32平台修改帧率的方式非常简单,就是在AppDelegate.cpp文件中修改:
director->setAnimationInterval(1.0 / 40);但是这种修改方式在导出android安卓apk到真机测试的时候,发现左下角的调试信息还是现实60~65帧,完全不受影响,网上搜索之后,发小安卓的修改需要修改cocos2dx-x生成的java代码中修改,具体在文件:Cocos2dxRenderer.java

在代码中可以看到以下的属性设置和重写的方法:
private static long sAnimationInterval = (long) (1.0 / 60 * Cocos2dxRenderer.NANOSECONDSPERSECOND);
public void onDrawFrame(final GL10 gl) {}如果要修改android平台的帧率,可以通过修改这些代码来改进,具体的操作方法如下:

1.修改帧率将60改成40
private static long sAnimationInterval = (long) (1.0 / 40 * Cocos2dxRenderer.NANOSECONDSPERSECOND);
2.增加一个属性变量
private long renderingElapsedTime = 0;3.重写渲染方法onDrawFrame
@Override
public void onDrawFrame(final GL10 gl) {
try {
if (renderingElapsedTime * NANOSECONDSPERMICROSECOND < Cocos2dxRenderer.sAnimationInterval) {
Thread.sleep((Cocos2dxRenderer.sAnimationInterval - renderingElapsedTime * NANOSECONDSPERMICROSECOND) / NANOSECONDSPERMICROSECOND);
}
} catch (InterruptedException e) {
e.printStackTrace();
}

// Get the timestamp when rendering started
long renderingStartedTimestamp = System.currentTimeMillis();

// should render a frame when onDrawFrame() is called or there is a
// "ghost"
Cocos2dxRenderer.nativeRender();

// Calculate the elapsed time during rendering
renderingElapsedTime = (System.currentTimeMillis() - renderingStartedTimestamp);
}代码中将渲染消耗的时间算进去,所以得到的帧率应该来说非常准确了。

注意,Cocos2dxRenderer中的onDrawFrame官方有实现好的帧率算法,但是被注释掉了,注释文本说存在一定的bug,帧率不精确,实际上大部分情况都可已正常使用,所以最好不要采用了~

这么做了之后,游戏的帧率在38~41左右,发热的问题也基本解决了。

最后,如果你要更好,更精确的帧率算法,也可以留言回复... 查看全部
使用Cocos2d-x 3.0开发游戏之后,发现游戏在android手机上发热非常严重,在魅族2上,几乎担心手机会爆炸了~~~采取的一个措施就是降低帧率,因为游戏对于帧率要求不是非常高。

做过cocos2d开发的同学应该都知道在win32平台修改帧率的方式非常简单,就是在AppDelegate.cpp文件中修改:
director->setAnimationInterval(1.0 / 40);
但是这种修改方式在导出android安卓apk到真机测试的时候,发现左下角的调试信息还是现实60~65帧,完全不受影响,网上搜索之后,发小安卓的修改需要修改cocos2dx-x生成的java代码中修改,具体在文件:Cocos2dxRenderer.java

在代码中可以看到以下的属性设置和重写的方法:
private static long sAnimationInterval = (long) (1.0 / 60 * Cocos2dxRenderer.NANOSECONDSPERSECOND);
public void onDrawFrame(final GL10 gl) {}
如果要修改android平台的帧率,可以通过修改这些代码来改进,具体的操作方法如下:

1.修改帧率将60改成40
private static long sAnimationInterval = (long) (1.0 / 40 * Cocos2dxRenderer.NANOSECONDSPERSECOND);
2.增加一个属性变量
private long renderingElapsedTime = 0;
3.重写渲染方法onDrawFrame
@Override
public void onDrawFrame(final GL10 gl) {
try {
if (renderingElapsedTime * NANOSECONDSPERMICROSECOND < Cocos2dxRenderer.sAnimationInterval) {
Thread.sleep((Cocos2dxRenderer.sAnimationInterval - renderingElapsedTime * NANOSECONDSPERMICROSECOND) / NANOSECONDSPERMICROSECOND);
}
} catch (InterruptedException e) {
e.printStackTrace();
}

// Get the timestamp when rendering started
long renderingStartedTimestamp = System.currentTimeMillis();

// should render a frame when onDrawFrame() is called or there is a
// "ghost"
Cocos2dxRenderer.nativeRender();

// Calculate the elapsed time during rendering
renderingElapsedTime = (System.currentTimeMillis() - renderingStartedTimestamp);
}
代码中将渲染消耗的时间算进去,所以得到的帧率应该来说非常准确了。

注意,Cocos2dxRenderer中的onDrawFrame官方有实现好的帧率算法,但是被注释掉了,注释文本说存在一定的bug,帧率不精确,实际上大部分情况都可已正常使用,所以最好不要采用了~

这么做了之后,游戏的帧率在38~41左右,发热的问题也基本解决了。

最后,如果你要更好,更精确的帧率算法,也可以留言回复...