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

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 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编译会出错

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值