上图是我们最终全部实现完成的效果图,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 object
CCScene *scene = CCScene::create();
// 'layer' is an autorelease object
HelloWorld *layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//
// 1. super init first
if ( !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 object
CCScene *scene = CCScene::create();
// 'layer' is an autorelease object
HelloWorld *layer = HelloWorld::create();
// add layer as a child to scene
scene->addChild(layer);
// return the scene
return scene;
}
// on "init" you need to initialize your instance
bool HelloWorld::init()
{
//
// 1. super init first
if ( !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中Copy
org到你自己的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编译会出错