Cocos2dx制作2048(1.搭建主框架)

来源:互联网 发布:熊本熊mac壁纸 编辑:程序博客网 时间:2024/06/15 07:40

Cocos2dx制作2048


上图是我们最终全部实现完成的效果图,APK就先不放出来了,上次做的移植的时候声音播放不了,移植播放声音的代码老是有问题


这次我们首先来做移植,交叉编译


我们新建一个工程,把多余的代码全删咯


在实现上下左右滑动的主体框架


好吧,开始。   还记得我们在学习的过程中触屏事件吗??


CCLayer已经继承了CCTouchDelegate


我们这次用单点触摸,头文件如下

#ifndef __HELLOWORLD_SCENE_H__#define __HELLOWORLD_SCENE_H__#include "cocos2d.h"class HelloWorld : public cocos2d::CCLayer{public:    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone    virtual bool init();      // there's no 'id' in cpp, so we recommend returning the class instance pointer    static cocos2d::CCScene* scene();        // implement the "static node()" method manually    CREATE_FUNC(HelloWorld);public:virtual void onEnter();virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);    virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);//上下左右滑动时调用bool doTop();bool doDown();bool doReight();bool doLeft();};#endif // __HELLOWORLD_SCENE_H__


源文件

#include "HelloWorldScene.h"USING_NS_CC;CCScene* HelloWorld::scene(){// 'scene' is an autorelease objectCCScene *scene = CCScene::create();// 'layer' is an autorelease objectHelloWorld *layer = HelloWorld::create();// add layer as a child to scenescene->addChild(layer);// return the scenereturn scene;}// on "init" you need to initialize your instancebool HelloWorld::init(){//////////////////////////////// 1. super init firstif ( !CCLayer::init() ){return false;}CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();return true;}void HelloWorld::onEnter(){}bool HelloWorld::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent){return true;}void HelloWorld::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent){}bool HelloWorld::doTop(){CCLOG("doTop Runing");return true;}bool HelloWorld::doDown(){CCLOG("doTop Runing");return true;}bool HelloWorld::doReight(){CCLOG("doTop Runing");return true;}bool HelloWorld::doLeft(){CCLOG("doTop Runing");return true;}

编译一下,看看有么有错误..


呃!错误还蛮多的,


看第六个错误,没有找到重载的成员函数,搞笑吧!明明就有,我们是继承了CCLayer的啊 


这个问题刚开始的时候纠结了我们N久,后面才发现,原来是我么有写命名空间   晕死


我们在头文件中加上


using namespace cocos2d;


在编译,    没错误了    ,这个问题很容易就范的     大家注意一下就行了


OK,我们首先需要解决的是不是怎么能让窗体接收触屏事件??


首先,来完成这个步骤:


不记得怎么写,或者忘记触屏事件的机制了,那么可以返回去看看学习笔记,这就是写博客的好处,用键盘敲总比用笔在纸上记好吧!


反正我是不想在纸上写字,太累!(说句题外话,也希望大家多谢谢博客,不求别然看,就当做笔记。忘记的东西查找起来也方便)


1.完成单点触摸

完成触摸事件第一步是什么??注册事件,这里CCLayer已经为我们提供了一个方法的,在学习过程中我们实现过多点触屏,其实这个也是一样的步骤

这里,我们在onEnter中注册

void HelloWorld::onEnter(){CCLayer::onEnter();this->setTouchEnabled(true);}

触屏开始的时候我们随便调用一个方法看看有没有输出:

bool HelloWorld::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent){doTop();return true;}

运行,

不管怎么点好像都没有输出什么日志,

那我们来跟踪一下看看是否启用触屏事件成功了,(就是,该事件是不是加入到队列中去了)



我们可以看出来,它确实执行了,但是addStandardDelegate 是增加多点到事件队列中的,我们捕捉的是单点,所以你懂的。

亲,这个问题怎么破??

有N多种破法

可以这样
void HelloWorld::onEnter(){CCLayer::onEnter();this->setTouchMode(ccTouchesMode::kCCTouchesOneByOne);this->setTouchEnabled(true);}
也可以这样

void HelloWorld::onEnter(){/*CCLayer::onEnter();this->setTouchMode(ccTouchesMode::kCCTouchesOneByOne);this->setTouchEnabled(true);*/ CCTouchDispatcher* pDispatcher = CCDirector::sharedDirector()->getTouchDispatcher(); pDispatcher->addTargetedDelegate(this, 1, true);}

当然,我们还是用第一种,后面那种我们还得自己移除 

标记一下,单点触摸这个东东,当时也纠结了我很久,最终折磨死我了才找着原因,突然觉得,没有实战的学习都是屁啊!BUG不可怕,怕的是找不到问题所在。这个问题我记忆犹新,估计老了我也不会忘记


2.判断往哪个方向移动


好了,现在我们来完成触点的计算来判断是往哪个方向移动,我们在头文件中增加四个成员变量

private://启点的X坐标,Y坐标//起点到终点X的距离,Y的距离int m_StartX,m_StartY,m_RangeX,m_RangeY;

在写个构造函数初始化一下吧

HelloWorld::HelloWorld():m_StartX(0),m_StartY(0),m_RangeX(0),m_RangeY(0){}

记得在头文件写声明哦

呃!我们在触屏开始时记录下起点的坐标

bool HelloWorld::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent){m_StartX=pTouch->getLocation().x;m_StartY=pTouch->getLocation().y;return true;}

这里,用的是getLocation(), 注意看该方法是实现 然后和   getLocationInView比较一下我们之前也讲过坐标系转换的吧??

OK,起点记住了,我们在触摸结束的时候的算算距离了,然后再根据当中距离的正负数来判断是往哪个方向滑屏


void HelloWorld::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent){CCPoint point=pTouch->getLocation();m_RangeX=m_StartX-point.x;m_RangeY=m_StartY-point.y;}

为什么这样写呢??我们来理解一下


这幅图我们是向右上角移动的,

那么此时我们的 m_RangeX=-50,m_RangeY=-70

假设我们是往左上角移动呢 那么m_RangeX是正数m_RangeY是负数如果是左下角呢?自己想吧

呃!我们现在的首要任务是判断它到底是上下移动呢还是左右移动,因为2048的规则只能是往四个方向移动的,不肯往左上角移动吧

怎么破??比两个范围的绝对值,那个大就往哪移动

if (abs(m_RangeX)>abs(m_RangeY)){//X大于Y左右移动}else{//否则上下移动}

abs是C语言中的库函数,里面的实现看不到,

现在知道是上下了还是左右了,接下来就判断具体的了

如果是左右的话,那么就得判断   m_RangeX 是正数还是负数了负数是向右正数是向左

判断上下其实也是一个道理

void HelloWorld::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent){CCPoint point=pTouch->getLocation();m_RangeX=m_StartX-point.x;m_RangeY=m_StartY-point.y;if (abs(m_RangeX)>abs(m_RangeY)){//X大于Y左右移动if (m_RangeX>5){//正数向左doLeft();}else  if(m_RangeX<-5){//负数向右doReight();}}else{//否则上下移动if (m_RangeY>5){//正数向下doDown();}else  if(m_RangeY<-5){//负数向上doTop();}}}

至于这里为什么不是0而是5和-5呢???

主要是因为,我不想手指点在屏幕上不动,它也执行。

比如:我想向左移动,当手指触屏后,我又反悔了,还没想好具体向哪滑动,而这时如果不留个范围在5~-5之间的话,那么你的手指只能不松开了,等你想好了再说吧!呵呵,

不然你一松开就会执行代码,虽然你也不知道是往哪移动但那不是我们想要的不是吗??


写好了就来测试一下吧??

呃!我说怎么全是doTop Runing呢?粗心了,大家应该能找到原因吧??

我们在试试效果,光点击鼠标,不移动鼠标是什么都么有的


3.移植Android(搭建交叉编译环境)

为什么要现在移植呢??主要是因为,现在代码还少,移植不成功可以重来,

我原先做的2048,最后才移植,结果声音这个东东到Eclipse中报错,

那时候代码又多了,重来太麻烦。

我们现在移植好之后,就可以不要动了,代码在VS中写。然后再Eclipse中实时运行,直接在手机上看效果岂不快哉??

移植主要是声音的问题,那么我们首先随便先搞个声音作为背景播放起来再说

播放声音我们之前没接触过,这里顺带学习学习

头文件加入

#include "SimpleAudioEngine.h"using namespace CocosDenshion;

SimpleAudioEngine简单的音频文件听说现在最新版的都能播放视频了



这里,我就随便下载了一首歌作为背景了,2048是么有背景音乐的,我们主要是为了移植的时候能成功的播放声音。

我们在init中来上这么一段

SimpleAudioEngine::sharedEngine()->playBackgroundMusic("Sound\1.mp3");

编译,运行,我这没有错误,公司的台式机, 听不到声音要是笔记本应该此时就能听到了

最终先贴上完整的代码在来做移植吧
#ifndef __HELLOWORLD_SCENE_H__#define __HELLOWORLD_SCENE_H__#include "cocos2d.h"#include "SimpleAudioEngine.h"using namespace CocosDenshion;using namespace cocos2d;class HelloWorld : public cocos2d::CCLayer{public:HelloWorld();    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone    virtual bool init();      // there's no 'id' in cpp, so we recommend returning the class instance pointer    static cocos2d::CCScene* scene();        // implement the "static node()" method manually    CREATE_FUNC(HelloWorld);public:virtual void onEnter();virtual bool ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent);    virtual void ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent);//上下左右滑动时调用bool doTop();bool doDown();bool doReight();bool doLeft();private://启点的X坐标,Y坐标//起点到终点X的距离,Y的距离int m_StartX,m_StartY,m_RangeX,m_RangeY;};#endif // __HELLOWORLD_SCENE_H__

#include "HelloWorldScene.h"USING_NS_CC;HelloWorld::HelloWorld():m_StartX(0),m_StartY(0),m_RangeX(0),m_RangeY(0){}CCScene* HelloWorld::scene(){// 'scene' is an autorelease objectCCScene *scene = CCScene::create();// 'layer' is an autorelease objectHelloWorld *layer = HelloWorld::create();// add layer as a child to scenescene->addChild(layer);// return the scenereturn scene;}// on "init" you need to initialize your instancebool HelloWorld::init(){//////////////////////////////// 1. super init firstif ( !CCLayer::init() ){return false;}CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();CCPoint origin = CCDirector::sharedDirector()->getVisibleOrigin();SimpleAudioEngine::sharedEngine()->playBackgroundMusic("Sound/1.mp3",true);return true;}void HelloWorld::onEnter(){CCLayer::onEnter();this->setTouchMode(ccTouchesMode::kCCTouchesOneByOne);this->setTouchEnabled(true);}bool HelloWorld::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent){m_StartX=pTouch->getLocation().x;m_StartY=pTouch->getLocation().y;return true;}void HelloWorld::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent){CCPoint point=pTouch->getLocation();m_RangeX=m_StartX-point.x;m_RangeY=m_StartY-point.y;if (abs(m_RangeX)>abs(m_RangeY)){//X大于Y左右移动if (m_RangeX>5){//正数向左doLeft();}else  if(m_RangeX<-5){//负数向右doReight();}}else{//否则上下移动if (m_RangeY>5){//正数向下doDown();}else  if(m_RangeY<-5){//负数向上doTop();}}}bool HelloWorld::doTop(){CCLOG("doTop Runing");return true;}bool HelloWorld::doDown(){CCLOG("doDown Runing");return true;}bool HelloWorld::doReight(){CCLOG("doReight Runing");return true;}bool HelloWorld::doLeft(){CCLOG("doLeft Runing");return true;}

OK,打开Eclipse

1.导入工程

肿么导入我就不细说了,记住,移植过程中千万不要打开源码看,不然就出问题了,我试过N次的

这里上一张图片,我E盘的东东


红色框住的是NDK   移植Android要用到的
Cocos2D-XTool这个目录存了一个cocos2d-x-2.2.3.zip python2_jb51.rar

都是开发要用到的东西

2.Copy org

从Cocos2dx中Copyorg到你自己的andorid项目中

E:\Cocos2D-XTool\cocos2d-x-2.2.3\cocos2dx\platform\android\java\src下的org

Copy到

E:\Cocos2D-XTool\cocos2d-x-2.2.3\projects\Test20140623\proj.android\src


3.复制资源

将Resources中所有项目中用到的资源复制到Andorid项目的assets文件夹中


还是那句话,src目录有个红色的X,别打开看源码,不然就出问题了,什么声音啊  CCLayerColor都出错

这应该是平台的问题,听说在nbantu系统上移植不会有这问题


4.修改Properties

嗯,我们在Eclipse工程上右击,选择Properties

4.1配置C/C++ Build


4.2配置Environment

 新增如下

COCOS2DX

E:\Cocos2D-XTool\cocos2d-x-2.2.3

NDK_ROOT

E:\android-ndk-r9d

NDK_MODULR_PATH(这里有两个目录,:一个是Cocos2dx的根目录一个是Cocos2dx目录下的android目录下的神马鸟东西两个目录用分号隔开)
E:\Cocos2D-XTool\cocos2d-x-2.2.3;E:\Cocos2D-XTool\cocos2d-x-2.2.3\cocos2dx\platform\third_party\android\prebuilt 


4.3配置Linked Resources

4.4build project


出错了


这时候你看到错误就行了,这是因为JNI编译C++代码 ,总会有问题的,不能按照我们C++的写法来

ok,百度了白天,GOOGLE又打不开,这公司的破网络,终于在stackoverflow上找到原因了

我们把this->setTouchMode(ccTouchesMode::kCCTouchesOneByOne);

改为:this->setTouchMode(kCCTouchesOneByOne);

在运行,成功了,手机上面声音也可以播放了


需要注意的是,在移植的时候不要管EClipse中红色的错误,

编译出错就到VS中改代码,反正不要直接在EClipse中修改、不然很多问题的


貌似,在VS中又运行不了,把播放背景音乐的代码注释掉就可以



网上说是我C盘的system32中advrcntr3.dll丢失了,

我也不去解决这问题了,在win32上我们就把这代码注释掉吧,移植的时候再放开




OK。今天就到这来,总结一下一些经常犯的错误

1.CCTouch注意要写命名空间

2.单点触摸要设置setTouchMode

3.播放声音如果有文件夹   千万别把Sound/1.mp3写成Sound\1.mp3斜杠别写反咯

4.使用枚举时不要使用枚举类型::枚举名直接使用枚举名不然JNI编译会出错

0 0