首先先感谢Legendof1991的博客让我想到做一个2048
http://blog.youkuaiyun.com/Legendof1991/article/category/2194455
游戏界面比较挫,还望海涵。
cocos2d-x版本为cocos2d-x-3.2alpha0 使用vs2012进行开发
首先使用cocos new 一个项目
HelloWorldScene.h
#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__
#include "cocos2d.h"
class HelloWorld : public cocos2d::Layer
{
public:
// there's no 'id' in cpp, so we recommend returning the class instance pointer
static cocos2d::Scene* createScene();
// Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
virtual bool init();
// a selector callback
void menuCloseCallback(cocos2d::Ref* pSender);
// implement the "static create()" method manually
CREATE_FUNC(HelloWorld);
private:
void initCardTable();
cocos2d::Vec2 _startPosition;
void CreateInitCardNumber();
void onLeft();
void onRight();
void onUp();
void onDown();
void checkEnd();
void initScore();
void updateScore(int score);
void ReStartGame();
cocos2d::Label* _labelScore;
cocos2d::Label* _labelBestScore;
int _score;
int _bestScore;
bool _isReStart;
};
#endif // __HELLOWORLD_SCENE_H__
HelloWorldScene.cpp
#include "HelloWorldScene.h"
#include "CardSprite.h"
USING_NS_CC;
Size visibleSize;
Vec2 origin;
CardSprite* cardTable[4][4];
Scene* HelloWorld::createScene()
{
// 'scene' is an autorelease object
auto scene = Scene::create();
// 'layer' is an autorelease object
auto 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 ( !Layer::init() )
{
return false;
}
visibleSize = Director::getInstance()->getVisibleSize();
origin = Director::getInstance()->getVisibleOrigin();
//初始化表格
initCardTable();
//编写事件监听
auto listen=EventListenerTouchOneByOne::create();
listen->onTouchBegan=[this](Touch* myTouch, Event* myEvent)->bool
{
if(_isReStart)
return false;
this->_startPosition= myTouch->getLocation();
return true;
};
listen->onTouchEnded=[this](Touch* myTouch, Event* myEvent)
{
//得到方向向量
Vec2 dir=myTouch->getLocation()-_startPosition;
//得到弧度数
float radians= ccpToAngle(dir);
//得到角度数
float angel=CC_RADIANS_TO_DEGREES(radians);
//log("%f",dir.length());
if(dir.length()<10)
{
}
else
{
//log("%f",angel);
//CreateInitCardNumber();
//注意角度是-180到180
if(angel>=-45&&angel<45)
{
//log("right");
onRight();
}
else if(angel>=45&&angel<135)
{
//log("up");
onUp();
}
else if((angel>=135&&angel<=180)||(angel<-135))
{
// log("left");
onLeft();
}
else
{
// log("down");
onDown();
}
checkEnd();
}
};
//注册事件监听
Director::getInstance()->getEventDispatcher()->addEventListenerWithSceneGraphPriority(listen,this);
//分值
this->_labelScore=Label::create("","Arial",visibleSize.width/24);
this->_labelBestScore=Label::create("","Arial",visibleSize.width/24);
this->addChild(_labelScore);
this->addChild(_labelBestScore);
initScore();
return true;
}
void HelloWorld::menuCloseCallback(Ref* pSender)
{
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WP8) || (CC_TARGET_PLATFORM == CC_PLATFORM_WINRT)
MessageBox("You pressed the close button. Windows Store Apps do not implement a close button.","Alert");
return;
#endif
Director::getInstance()->end();
#if (CC_TARGET_PLATFORM == CC_PLATFORM_IOS)
exit(0);
#endif
}
//初始化全为0
void HelloWorld::initCardTable()
{
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
{
if(cardTable[i][j]==NULL)
{
//if(cardTable[i][j]!=NULL)
//{
// delete cardTable[i][j];
// }
CardSprite *myCard=CardSprite::createWithArgs(0,i,j,visibleSize.width/5,visibleSize.height/6);
cardTable[i][j]=myCard;
//log("%f %f",myCard->getPositionX(),myCard->getPositionY());
this->addChild(myCard);
}
else
{
cardTable[i][j]->setCardNumber(0);
}
}
//生成两个不为0的
CreateInitCardNumber();
CreateInitCardNumber();
_isReStart=false;
}
//初始化的卡片数字
void HelloWorld::CreateInitCardNumber()
{
std::srand(time(NULL));
int x=std::rand()%4;
int y=std::rand()%4;
while(cardTable[x][y]->getCardNumber()!=0)
{
x=std::rand()%4;
y=std::rand()%4;
}
//2或4
cardTable[x][y]->setCardNumber(rand()%4==0?4:2);
}
//往左滑动 下面三个类似
void HelloWorld::onLeft()
{
//是否造成移动
bool isMove=false;
//关心的是每一横行
for(int y=0;y<4;y++)
{
//最左侧开始计算
for(int x=0;x<4;x++)
{
for(int x1=x+1;x1<4;x1++)
{
//当当前格为0 右面不为0 右边赋值给左面 右面为0
if(cardTable[x][y]->getCardNumber()==0&&cardTable[x1][y]->getCardNumber()!=0)
{
cardTable[x][y]->setCardNumber(cardTable[x1][y]->getCardNumber());
cardTable[x1][y]->setCardNumber(0);
isMove=true;
}
//当左右相等且不为0 左值加倍 右值为0
else if(cardTable[x][y]->getCardNumber()==cardTable[x1][y]->getCardNumber()&&cardTable[x][y]->getCardNumber()!=0)
{
updateScore(cardTable[x][y]->getCardNumber());
cardTable[x][y]->doubleNumber();
cardTable[x1][y]->setCardNumber(0);
isMove=true;
//当前格不再计算
break;
}
//当左右格不等 右格不为0 当前格不再计算
else if(cardTable[x][y]->getCardNumber()!=cardTable[x1][y]->getCardNumber()&&cardTable[x1][y]->getCardNumber()!=0)
{
break;
}
}
}
}
//发生移动时添加新的一个初始格子
if(isMove)
this->CreateInitCardNumber();
}
void HelloWorld::onRight()
{
bool isMove=false;
for(int y=0;y<4;y++)
{
for(int x=3;x>=0;x--)
{
for(int x1=x-1;x1>=0;x1--)
{
if(cardTable[x][y]->getCardNumber()==0&&cardTable[x1][y]->getCardNumber()!=0)
{
cardTable[x][y]->setCardNumber(cardTable[x1][y]->getCardNumber());
cardTable[x1][y]->setCardNumber(0);
isMove=true;
}
else if(cardTable[x][y]->getCardNumber()==cardTable[x1][y]->getCardNumber()&&cardTable[x][y]->getCardNumber()!=0)
{
updateScore(cardTable[x][y]->getCardNumber());
cardTable[x][y]->doubleNumber();
cardTable[x1][y]->setCardNumber(0);
isMove=true;
break;
}
else if(cardTable[x][y]->getCardNumber()!=cardTable[x1][y]->getCardNumber()&&cardTable[x1][y]->getCardNumber()!=0)
{
break;
}
}
}
}
if(isMove)
this->CreateInitCardNumber();
}
void HelloWorld::onUp()
{
bool isMove=false;
for(int x=0;x<4;x++)
{
for(int y=3;y>=0;y--)
{
for(int y1=y-1;y1>=0;y1--)
{
if(cardTable[x][y]->getCardNumber()==0&&cardTable[x][y1]->getCardNumber()!=0)
{
cardTable[x][y]->setCardNumber(cardTable[x][y1]->getCardNumber());
cardTable[x][y1]->setCardNumber(0);
isMove=true;
}
else if(cardTable[x][y]->getCardNumber()==cardTable[x][y1]->getCardNumber()&&cardTable[x][y]->getCardNumber()!=0)
{
updateScore(cardTable[x][y]->getCardNumber());
cardTable[x][y]->doubleNumber();
cardTable[x][y1]->setCardNumber(0);
isMove=true;
break;
}
else if(cardTable[x][y]->getCardNumber()!=cardTable[x][y1]->getCardNumber()&&cardTable[x][y1]->getCardNumber()!=0)
{
break;
}
}
}
}
if(isMove)
this->CreateInitCardNumber();
}
void HelloWorld::onDown()
{
bool isMove=false;
for(int x=0;x<4;x++)
{
for(int y=0;y<4;y++)
{
for(int y1=y+1;y1<4;y1++)
{
if(cardTable[x][y]->getCardNumber()==0&&cardTable[x][y1]->getCardNumber()!=0)
{
cardTable[x][y]->setCardNumber(cardTable[x][y1]->getCardNumber());
cardTable[x][y1]->setCardNumber(0);
isMove=true;
}
else if(cardTable[x][y]->getCardNumber()==cardTable[x][y1]->getCardNumber()&&cardTable[x][y]->getCardNumber()!=0)
{
updateScore(cardTable[x][y]->getCardNumber());
cardTable[x][y]->doubleNumber();
cardTable[x][y1]->setCardNumber(0);
isMove=true;
break;
}
else if(cardTable[x][y]->getCardNumber()!=cardTable[x][y1]->getCardNumber()&&cardTable[x][y1]->getCardNumber()!=0)
{
break;
}
}
}
}
if(isMove)
this->CreateInitCardNumber();
}
//检测是否可消除
void HelloWorld::checkEnd()
{
int count=0;
bool isEnd=true;
for(int i=0;i<4;i++)
for(int j=0;j<4;j++)
{
if(cardTable[i][j]->getCardNumber()!=0)
count++;
//下面是判断是否有可消除的格子 只要有便不结束游戏
if(j!=3&&i!=3)
{
if(cardTable[i][j]->getCardNumber()==cardTable[i+1][j]->getCardNumber()||cardTable[i][j]->getCardNumber()==cardTable[i][j+1]->getCardNumber())
isEnd=false;
}
else if(i==3&&j==3)
{
}
else if(i==3)
{
if(cardTable[i][j]->getCardNumber()==cardTable[i][j+1]->getCardNumber())
isEnd=false;
}
else if(j==3)
{
if(cardTable[i][j]->getCardNumber()==cardTable[i+1][j]->getCardNumber())
isEnd=false;
}
}
//没有填满 可以继续
if(count<16)
{
//log("no");
return;
}
if(isEnd)
{
log("Yes");
//重置游戏
_isReStart=true;
ReStartGame();
return;
}
}
//初始化分数
void HelloWorld::initScore()
{
_score=0;
//this->_labelScore=Label::create("Score: 0","Arial",20);
this->_labelScore->setString(String::createWithFormat("Score: %d",_score)->getCString());
this->_labelScore->setPosition(visibleSize.width/2,visibleSize.height-visibleSize.height/12);
//读取分数
_bestScore= UserDefault::getInstance()->getIntegerForKey("BestScore",0);
//this->_labelBestScore=Label::create(String::createWithFormat("Best Score: %d",_bestScore)->getCString(),"Arial",20);
this->_labelBestScore->setString(String::createWithFormat("Score: %d",_bestScore)->getCString());
this->_labelBestScore->setPosition(visibleSize.width*0.8,visibleSize.height-visibleSize.height/12);
this->_labelBestScore->setColor(Color3B::YELLOW);
}
//更新分数
void HelloWorld::updateScore(int score)
{
_score+=score;
this->_labelScore->setString(String::createWithFormat("Score: %d",_score)->getCString());
if(_score>_bestScore)
this->_labelBestScore->setString(String::createWithFormat("Score: %d",_score)->getCString());
}
//重置游戏
void HelloWorld::ReStartGame()
{
if(_score>_bestScore)
UserDefault::getInstance()->setIntegerForKey("BestScore",_score);
//Director::getInstance()->replaceScene(HelloWorld::createScene());
initScore();
initCardTable();
}
#ifndef __CardSprite__
#define __CardSprite__
#include"cocos2d.h"
class CardSprite:public cocos2d::Sprite
{
public:
static CardSprite* cardTable[4][4];
static CardSprite* createWithArgs(int number,int posX,int posY,float weight,float Height);
int getCardNumber();
void setCardNumber(int number);
void doubleNumber();
cocos2d::Label* getLabel()
{
return labelNumber;
}
private:
int _cardNumber;
bool initWithArgs(int number,int posX,int posY,float weight,float Height);
cocos2d::Label* labelNumber;
cocos2d::LayerColor* layerBgColor;
CREATE_FUNC(CardSprite);
};
#endif
CardSprite.cpp
#include"CardSprite.h"
USING_NS_CC;
using namespace std;
//设置数值
void CardSprite::setCardNumber(int number)
{
if(number>0)
{
//设置颜色
switch (number)
{
case 2:
labelNumber->setColor(Color3B::WHITE);
break;
case 4:
labelNumber->setColor(Color3B(0xcc,0x99,0x00));
break;
case 8:
labelNumber->setColor(Color3B::BLUE);
break;
case 16:
labelNumber->setColor(Color3B::YELLOW);
break;
case 32:
labelNumber->setColor(Color3B::GREEN);
break;
case 64:
labelNumber->setColor(Color3B::BLACK);
break;
case 128:
labelNumber->setColor(Color3B(0xff,0x00,0x33));
break;
case 256:
labelNumber->setColor(Color3B(0x33,0xcc,0xff));
break;
case 512:
labelNumber->setColor(Color3B(0xff,0x99,0xcc));
break;
case 1024:
labelNumber->setColor(Color3B(0x77,0x00,0x00));
break;
case 2048:
labelNumber->setColor(Color3B(0xff,0xff,0x66));
break;
default:
labelNumber->setColor(Color3B(0x00,0x88,0x00));
break;
}
//设置大小 应该根据屏幕设置
labelNumber->setSystemFontSize(50);
if(number>10)
labelNumber->setSystemFontSize(48);
if(number>100)
labelNumber->setSystemFontSize(45);
if(number>1000)
labelNumber->setSystemFontSize(42);
if(_cardNumber==0)
{
//原值为0直接淡入
FadeIn *fadeIn=FadeIn::create(0.2);
Sequence *sequence=Sequence::create(CallFunc::create([this,number]()->void{this->labelNumber->setString(String::createWithFormat("%d",number)->getCString());}),fadeIn,NULL);
labelNumber->runAction(sequence);
}
else
{
//原值不为0 先淡出 更新数值 淡入加旋转
FadeOut *fadeout=FadeOut::create(0.1);
FadeIn *fadeIn=FadeIn::create(0.2);
RotateBy *rotateBy=RotateBy::create(0.2,Vec3(0,0,360));
Spawn *spawn=Spawn::create(fadeIn,rotateBy,NULL);
Sequence *sequence=Sequence::create(fadeout, CallFunc::create([this,number]()->void{this->labelNumber->setString(String::createWithFormat("%d",number)->getCString());}),spawn,NULL);
//labelNumber->setString(String::createWithFormat("%d",number)->getCString());
labelNumber->runAction(sequence);
}
//auto fadeIn=fadeout->reverse();
}
else
{
//淡出
labelNumber->setString("");
FadeOut *fadeout=FadeOut::create(0.1);
labelNumber->runAction(fadeout);
}
_cardNumber=number;
}
//。。。不想说
int CardSprite::getCardNumber()
{
return _cardNumber;
}
//仿得Sprite写的 不要问我为什么
CardSprite* CardSprite::createWithArgs(int number,int posX,int posY,float weight,float Height)
{
CardSprite* cs=new CardSprite();
if(cs&&cs->initWithArgs(number,posX, posY,weight,Height))
{
cs->autorelease();
return cs;
}
CC_SAFE_DELETE(cs);
return NULL;
}
//真正的初始化
bool CardSprite::initWithArgs(int number,int posX,int posY,float weight,float Height)
{
if(Sprite::init())
{
//设置背景
layerBgColor=LayerColor::create(Color4B::GRAY,weight*0.9,Height*0.9);
//还是左下角比较舒服 下面的是忽视锚点 不过习惯设为0
layerBgColor->setAnchorPoint(ccp(0,0));
layerBgColor->ignoreAnchorPointForPosition(true);
layerBgColor->setPosition(0.05*weight,0.05*Height);
this->addChild(layerBgColor);
labelNumber=Label::create("", "Arial",50);
labelNumber->setPosition(0.5*weight,0.5*Height);
this->setCardNumber(number);
this->addChild(labelNumber);
this->setAnchorPoint(ccp(0,0));
this->setPosition(posX*weight+weight*0.5,posY*Height+Height*0.5);
//log("%f %f",posX*weight,posY*Height);
//设置大小
this->setContentSize(CCSizeMake(weight,Height));
return true;
}
else
{
return false;
}
}
//。。。不想说
void CardSprite::doubleNumber()
{
setCardNumber(_cardNumber*2);
}
AppDelegate.h
#ifndef _APP_DELEGATE_H_
#define _APP_DELEGATE_H_
#include "cocos2d.h"
/**
@brief The cocos2d Application.
The reason for implement as private inheritance is to hide some interface call by Director.
*/
class AppDelegate : private cocos2d::Application
{
public:
AppDelegate();
virtual ~AppDelegate();
/**
@brief Implement Director and Scene init code here.
@return true Initialize success, app continue.
@return false Initialize failed, app terminate.
*/
virtual bool applicationDidFinishLaunching();
/**
@brief The function be called when the application enter background
@param the pointer of the application
*/
virtual void applicationDidEnterBackground();
/**
@brief The function be called when the application enter foreground
@param the pointer of the application
*/
virtual void applicationWillEnterForeground();
};
#endif // _APP_DELEGATE_H_
AppDelegate.cpp
#include "AppDelegate.h"
#include "HelloWorldScene.h"
USING_NS_CC;
AppDelegate::AppDelegate() {
}
AppDelegate::~AppDelegate()
{
}
bool AppDelegate::applicationDidFinishLaunching() {
// initialize director
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
if(!glview) {
glview = GLView::create("My Game");
//设置分辨率
glview->setFrameSize(480,320);
director->setOpenGLView(glview);
}
// turn on display FPS
director->setDisplayStats(false);
// set FPS. the default value is 1.0/60 if you don't call this
director->setAnimationInterval(1.0 / 60);
// create a scene. it's an autorelease object
auto scene = HelloWorld::createScene();
// run
director->runWithScene(scene);
return true;
}
// This function will be called when the app is inactive. When comes a phone call,it's be invoked too
void AppDelegate::applicationDidEnterBackground() {
Director::getInstance()->stopAnimation();
// if you use SimpleAudioEngine, it must be pause
// SimpleAudioEngine::getInstance()->pauseBackgroundMusic();
}
// this function will be called when the app is active again
void AppDelegate::applicationWillEnterForeground() {
Director::getInstance()->startAnimation();
// if you use SimpleAudioEngine, it must resume here
// SimpleAudioEngine::getInstance()->resumeBackgroundMusic();
}
逻辑很简单 触摸开始记录一个位置 在结束时计算出一个向量,求出角度,判断滑动方向,调用相应方法。初始化一个卡片时,判断游戏是否可以继续进行,不可以的条件为16个格子全不为0且相邻的格子数值都不相等。 代码全发出来了,想用直接拿走。
发布android时在AndroidManifest.xml文件中,设置screenOrientation="landscape" 为横屏, screenOrientation="portrait"为竖屏。
前段时间在看Unity3D,c#的lamda用的很舒服,现在cocos2d-x的c++中也开始使用lamda了,比原来的函数指针用的舒服很多。
[capture](parameters)->return_type {body}
[捕获参数列表](参数列表)->返回类型{函数体}
[] 不截取任何变量
[&} 截取外部作用域中所有变量,并作为引用在函数体中使用
[=] 截取外部作用域中所有变量,并拷贝一份在函数体中使用
[=, &foo] 截取外部作用域中所有变量,并拷贝一份在函数体中使用,但是对foo变量使用引用 [bar] 截取bar变量并且拷贝一份在函数体重使用,同时不截取其他变量
[this] 截取当前类中的this指针。如果已经使用了&或者=就默认添加此选项。截取this的目的是可以在lamda中使用当前类的成员函数和成员变量。
如果不爱复制粘贴
http://download.youkuaiyun.com/detail/qw6194425/7576511 自己去下吧