我一共添加了四个类分别为:
(1)游戏启动后的初始界面类SplashScene; 这个界面是游戏启动后的第一个界面。
这个类在AppDelegate::applicationDidFinishLaunching()会被调用
bool AppDelegate::applicationDidFinishLaunching() {
// initialize director
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
if(!glview) {
glview = GLView::create("2048");
glview->setFrameSize(500, 600);
director->setOpenGLView(glview);
}
// turn on display FPS
director->setDisplayStats(true);
// 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 = Splash::createScene();
// run
director->runWithScene(scene);
return true;
}
其中通过Splash::createScene()创建一个场景,然后通过director->runWithScene(scene)运行此场景。
Splash应继承自Layer类,且拥有四个成员函数:bool init()用来初始化场景;static Splash*createScene()用来创建一个场景;CREATE_FUNC(Splash);使Splash拥有一个create()方法来创建一个Splash的对象(类型为Layer类);void jameToGame(float t)用来跳转到GameScene场景中;
#include"cocos2d.h"
#include<iostream>
USING_NS_CC;
class Splash :public Layer
{
public:
virtual bool init();
CREATE_FUNC(Splash);
static Scene*createScene();
void jumpToGame(float t);
};
所有类的头文件中应包含"cocos2d.h"的头文件,并且使用cocos2d的命名空间:USING_NS_CC;接着是函数的实现
init函数中应该显示游戏的标题 制作单位等相关信息
#include"SplashScene.h"
#include"GameScene.h"
#include"SimpleAudioEngine.h"
using namespace CocosDenshion;
USING_NS_CC;
bool Splash::init()
{
if (!Layer::init())
{
return false;
}
//加载音乐
SimpleAudioEngine::getInstance()->preloadEffect("1second.wav");
SimpleAudioEngine::getInstance()->preloadEffect("2.wav");
Size visibleSize = Director::getInstance()->getVisibleSize();
Vec2 origin = Director::getInstance()->getVisibleOrigin();
//显示游戏名称
auto label = Label::createWithBMFont("fonts/futura-48.fnt", "2048");
label->setPosition(Vec2(origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 2));
this->addChild(label,1);
label->setScale(1.5);
//显示制作单位
auto label2 = Label::createWithBMFont("fonts/futura-48.fnt", "made by -cug-ZK");
label2->setPosition(Point(label2->getContentSize().width/2, visibleSize.height / 4));
this->addChild(label2,1);
label2->setScale(0.8);
//计划任务三秒钟之后进入游戏场景
this->scheduleOnce(schedule_selector(Splash::jumpToGame), 3);
return true;
}
Scene* Splash::createScene()
{
auto scene = Scene::create();
auto layer = Splash::create();
scene->addChild(layer);
return scene;
}
void Splash::jumpToGame(float t)
{
auto scene = Game::createScene();
Director::getInstance()->replaceScene(TransitionProgressOutIn::create(0.5, scene));
}
加载音乐应该包含#include"SimpleAudioEngine" 使用命名空间using namespace CocosDenshion;
(2)游戏场景类GameScene类;游戏的主场景;
首先添加一个头文件用来定义游戏相关信息
#define GAME_TILED_WIDTH 100 //格子的宽
#define GAME_TILED_HEIGHT 100 //格子的高
#define GAME_TILED_BOARD_WIDTH 4 //间隔的宽度
#define GAME_ROWS 4 //行数
#define GAME_COLS 4 //列数
enum class E_MOVE_DIR //移动的方向
{
UP,
DOWN,
LEFT,
RIGHT
};
接着是GameScene.h的类容:
#include"cocos2d.h"
#include<iostream>
#include"movedTiled.h"
#include"GameDefine.h"
#include"SimpleAudioEngine.h"
USING_NS_CC;
class Game :public Layer
{
private:
bool m_startMove;//是否开始移动
int m_x, m_y;//开始触摸的点
public :
virtual bool init();
static Scene*createScene();
CREATE_FUNC(Game);
E_MOVE_DIR dir;
int map[GAME_ROWS][GAME_COLS];
Vector<movedTiled*> m_allTiled;//保存所有块
void moveAllTiled(E_MOVE_DIR dir);//核心游戏逻辑
void newMovedTiled();
void moveUp();
void moveDown();
void moveLeft();
void moveRight();
LayerColor* color_back;//背景
int m_score;//分数
};
GameScene.cpp的类容
#include"GameScene.h"
#include"GameOver.h"
using namespace CocosDenshion;
bool Game::init()
{
if (!Layer::init())
{
return false;
}
//初始化游戏标题
Size visibleSize = Director::getInstance()->getVisibleSize();
Point origin = Director::getInstance()->getVisibleOrigin();
auto labelGame = Label::createWithBMFont("fonts/futura-48.fnt", "2048");
labelGame->setPosition(Point(labelGame->getContentSize().width/2, visibleSize.height - labelGame->getContentSize().height));
this->addChild(labelGame, 1);
//labelGame->setScale(0.5);
//初始化游戏分数
m_score = 0;
auto score = Label::createWithBMFont("fonts/futura-48.fnt", StringUtils::format("%d", this->m_score));
score->setTag(102);
score->setPosition(Point(visibleSize.width / 2, visibleSize.height - score->getContentSize().height));
this->addChild(score);
score->setScale(0.6);
//初始化游戏网格
color_back = LayerColor::create(Color4B(161, 134, 190, 255), GAME_TILED_WIDTH*GAME_COLS + GAME_TILED_BOARD_WIDTH*(GAME_COLS + 1),
GAME_TILED_HEIGHT*GAME_ROWS + GAME_TILED_BOARD_WIDTH*(GAME_ROWS + 1));
color_back->ignoreAnchorPointForPosition(false);
color_back->setAnchorPoint(Vec2(0.5, 0.5));
color_back->setPosition(Point(origin.x + visibleSize.width / 2, origin.y + visibleSize.height / 2));
this->addChild(color_back, 1);
//初始化网格的每一块
for (int row = 0; row < GAME_COLS; row++)
{
for (int col = 0; col < GAME_COLS; col++)
{
auto layerTiled = LayerColor::create(Color4B(104, 104, 104, 255), GAME_TILED_WIDTH, GAME_TILED_HEIGHT);
//layerTiled->ignoreAnchorPointForPosition(fa)
layerTiled->setPosition(Point(col*GAME_TILED_WIDTH + (col + 1)*GAME_TILED_BOARD_WIDTH, row*GAME_TILED_HEIGHT + (row + 1)*GAME_TILED_BOARD_WIDTH));
color_back->addChild(layerTiled);
}
}
//初始化逻辑网格数组
for (int i = 0; i < GAME_ROWS; i++)
{
for (int j = 0; j < GAME_COLS; j++)
{
map[i][j] = 0;//表示空白
}
}
//初始化数字块
newMovedTiled();
//触摸处理
auto event = EventListenerTouchOneByOne::create();
event->onTouchBegan = [&](Touch *tou, Event*eve){
m_x = tou->getLocation().x;
m_y = tou->getLocation().y;
m_startMove = true;
return true;
};
event->onTouchMoved = [&](Touch*tou, Event*eve){
int x = tou->getLocation().x;
int y = tou->getLocation().y;
if (m_startMove&&(abs(x - m_x) > 10 || abs(y - m_y) > 10))
{
m_startMove = false;
E_MOVE_DIR dir;
if (abs(x - m_x) > abs(y - m_y))
{
if (x > m_x)
{
dir = E_MOVE_DIR::RIGHT;
}
else
dir = E_MOVE_DIR::LEFT;
}
else
{
if (y > m_y)
{
dir = E_MOVE_DIR::UP;
}
else
dir = E_MOVE_DIR::DOWN;
}
moveAllTiled(dir);//移动所有的元素块
}
//return true;
};
//event->onTouchEnded;
Director::getInstance()->getEventDispatcher()->
addEventListenerWithSceneGraphPriority(event, this);
//游戏分数
return true;
}
void Game::newMovedTiled()//产生新块
{
auto tiled = movedTiled::create();
int freeCount = 16 - m_allTiled.size();
if (freeCount == 0)
{
return;
}
srand(time(0));
int num = rand() % freeCount+1;
int count = 0;
bool find = false;
int row, col;
for (row = 0; row < GAME_COLS; row++)
{
for (col = 0; col < GAME_COLS; col++)
{
if (map[row][col]==0)
{
count++;
if (count == num)
{
find = true;
break;
}
}
}
if (find)
{
color_back->addChild(tiled);
tiled->showAt(row, col);
m_allTiled.pushBack(tiled);
map[row][col] = m_allTiled.getIndex(tiled) + 1;
break;
}
}
}
void Game::moveUp() //向上移动
{
for (int col = 0; col < GAME_COLS; col++)
{
for (int row = 1; row <GAME_ROWS; row++)
{
if (map[row][col] != 0)
{
bool flag = false;
for (int row1 = row; row1 >0; row1--)
{
if (map[row1 - 1][col] == 0 && map[row1][col] != 0)
{
map[row1 - 1][col] = map[row1][col];
map[row1][col] = 0;
m_allTiled.at(map[row1 - 1][col] - 1)->moveTo(row1 - 1, col);
}
else if (map[row1 - 1][col] && map[row1][col]&&!flag)
{
flag = true;
int num1 = m_allTiled.at(map[row1 - 1][col] - 1)->m_number;
int num2 = m_allTiled.at(map[row1][col] - 1)->m_number;
if (num1 == num2)
{
m_score += num1 * 2;
m_allTiled.at(map[row1 - 1][col] - 1)->doubleNumber();
m_allTiled.at(map[row1][col] - 1)->removeFromParent();
m_allTiled.erase(map[row1][col] - 1);
for (int i = 0; i < GAME_COLS; i++)
{
for (int j = 0; j < GAME_COLS; j++)
{
if (map[i][j]>map[row1][col])
{
map[i][j]--;
}
}
}
map[row1][col] = 0;
}
}
}
}
}
}
}
void Game::moveDown()//向下移动
{
for (int col = 0; col < GAME_COLS; col++)
{
for (int row = GAME_COLS-2; row >=0; row--)
{
if (map[row][col] != 0)
{
bool flag = false;
for (int row1 = row; row1 <GAME_ROWS-1; row1++)
{
if (map[row1 + 1][col] == 0 && map[row1][col] != 0)
{
map[row1 + 1][col] = map[row1][col];
map[row1][col] = 0;
m_allTiled.at(map[row1 + 1][col] - 1)->moveTo(row1 + 1, col);
}
else if (map[row1][col] && map[row1 + 1][col]&&!flag)
{
flag = true;
int num1 = m_allTiled.at(map[row1][col]-1)->m_number;
int num2 = m_allTiled.at(map[row1 + 1][col]-1)->m_number;
if (num1 == num2)
{
m_score += num1 * 2;
m_allTiled.at(map[row1 + 1][col] - 1)->doubleNumber();
m_allTiled.at(map[row1][col] - 1)->removeFromParent();
m_allTiled.erase(map[row1][col] - 1);
for (int i = 0; i < GAME_ROWS; i++)
{
for (int j = 0; j < GAME_COLS; j++)
{
if (map[i][j]>map[row1][col])
{
map[i][j]--;
}
}
}
map[row1][col] = 0;
}
}
}
}
}
}
}
void Game::moveLeft()//向左移动
{
for (int row = 0; row < GAME_COLS; row++)
{
for (int col = 1; col <GAME_ROWS; col++)
{
if (map[row][col] != 0)
{
bool flag = false;
for (int col1 = col; col1 >0; col1--)
{
if (map[row][col1-1] == 0 && map[row][col1] != 0)
{
map[row][col1-1] = map[row][col1];
map[row][col1] = 0;
m_allTiled.at(map[row][col1 - 1] - 1)->moveTo(row, col1 - 1);
}
else if (map[row][col1-1] && map[row][col1]&&!flag)
{
flag = true;
int num1 = m_allTiled.at(map[row][col1-1] - 1)->m_number;
int num2 = m_allTiled.at(map[row][col1] - 1)->m_number;
if (num1 == num2)
{
m_score += num1 * 2;
m_allTiled.at(map[row][col1-1] - 1)->doubleNumber();
m_allTiled.at(map[row][col1] - 1)->removeFromParent();
m_allTiled.erase(map[row][col1] - 1);
for (int i = 0; i < GAME_COLS; i++)
{
for (int j = 0; j < GAME_COLS; j++)
{
if (map[i][j]>map[row][col1])
{
map[i][j]--;
}
}
}
map[row][col1] = 0;
}
}
}
}
}
}
}
void Game::moveRight()//向右移动
{
for (int row = 0; row < GAME_COLS; row++)
{
for (int col = GAME_COLS-2; col >=0; col--)
{
if (map[row][col] != 0)
{
bool flag = false;
for (int col1 = col; col1 <GAME_COLS-1; col1++)
{
if (map[row][col1+1] == 0 && map[row][col1] != 0)
{
map[row][col1+1] = map[row][col1];
map[row][col1] = 0;
m_allTiled.at(map[row][col1+1] - 1)->moveTo(row, col1+1);
}
else if (map[row][col1+1] && map[row][col1]&&!flag)
{
flag = true;
int num1 = m_allTiled.at(map[row][col1+1] - 1)->m_number;
int num2 = m_allTiled.at(map[row][col1] - 1)->m_number;
if (num1 == num2)
{
m_score += num1 * 2;
m_allTiled.at(map[row][col1+1] - 1)->doubleNumber();
m_allTiled.at(map[row][col1] - 1)->removeFromParent();
m_allTiled.erase(map[row][col1] - 1);
for (int i = 0; i < GAME_COLS; i++)
{
for (int j = 0; j < GAME_COLS; j++)
{
if (map[i][j]>map[row][col1])
{
map[i][j]--;
}
}
}
map[row][col1] = 0;
}
}
}
}
}
}
}
void Game::moveAllTiled(E_MOVE_DIR dir)//核心游戏逻辑实现
{
//移动所有块,消除
switch (dir)
{
case E_MOVE_DIR::UP:moveUp();
break;
case E_MOVE_DIR::DOWN:moveDown();
break;
case E_MOVE_DIR::LEFT:moveLeft();
break;
case E_MOVE_DIR::RIGHT:moveRight();
break;
default:break;
}
//播放音乐
SimpleAudioEngine::getInstance()->playEffect("1second.wav");
//产生新块
Label* score = (Label*)this->getChildByTag(102);
//分数变化
score->setString(StringUtils::format("%d", this->m_score));
newMovedTiled();
//判定输赢
bool lose = true;
if (m_allTiled.size() == 16)
{
for (int i = 0; i < GAME_COLS; i++)
{
for (int j = 0; j < GAME_COLS; j++)
{
int num1 = m_allTiled.at(map[i][j] - 1)->m_number;
if (i + 1 < GAME_ROWS)//判断向下
{
int num2 = m_allTiled.at(map[i+1][j] - 1)->m_number;
if (num1 == num2)
{
lose = false;
break;
}
}
if (i - 1 >=0)//判断向上
{
int num2 = m_allTiled.at(map[i - 1][j] - 1)->m_number;
if (num1 == num2)
{
lose = false;
break;
}
}
if (j - 1 >=0)//判断向左
{
int num2 = m_allTiled.at(map[i][j-1] - 1)->m_number;
if (num1 == num2)
{
lose = false;
break;
}
}
if (j + 1 < GAME_ROWS)//判断向右
{
int num2 = m_allTiled.at(map[i][j+1] - 1)->m_number;
if (num1 == num2)
{
lose = false;
break;
}
}
}
if (!lose)
{
break;
}
}
if (lose)
{
auto scene = GameOver::createScene();
Director::getInstance()->replaceScene(TransitionFadeDown::create(0.5, scene));
}
}
}
Scene*Game::createScene()
{
auto scene = Scene::create();
auto layer = Game::create();
scene->addChild(layer);
return scene;
}
(3)格子类movedTiled类.
movedTiled.h
#pragma once
#include<iostream>
#include "cocos2d.h"
USING_NS_CC;
class movedTiled :public Node
{
public:
movedTiled();
~movedTiled();
bool init();
int m_row;
int m_col;
int m_number;
CREATE_FUNC(movedTiled);
void showAt(int r, int c);//在r行c列产生一个新块
void moveTo(int r, int c);//将一个块移动到r行c列(有无动画的区别)
void doubleNumber();
};
moveTiled.cpp
#include "movedTiled.h"
#include"GameDefine.h"
#include"SimpleAudioEngine.h"
using namespace CocosDenshion;
movedTiled::movedTiled()
{
}
movedTiled::~movedTiled()
{
}
bool movedTiled::init()
{
if (!Node::init())
{
return false;
}
auto bk = LayerColor::create(Color4B(200, 200, 200, 255), GAME_TILED_WIDTH, GAME_TILED_HEIGHT);
bk->setTag(100);
this->addChild(bk);
int n = rand() % 10;
this->m_number = n > 0 ? 2 : 4;
auto label = Label::createWithBMFont("fonts/bitmapFontChinese.fnt",StringUtils::format("%d",this->m_number));
label->setTag(101);
bk->addChild(label);
if (this->m_number == 4)
{
bk->setColor(Color3B(255, 182, 193));
}
label->setColor(Color3B(200, 0, 255));
label->setPosition(Point(bk->getContentSize().width / 2, bk->getContentSize().height / 2));
label->setScale(0.8);
return true;
}
void movedTiled::showAt(int r,int c)
{
moveTo(r, c);
auto bk = this->getChildByTag(100);
bk->runAction(Sequence::create(ScaleTo::create(0.2, 0.8), ScaleTo::create(0.2, 1.2), ScaleTo::create(0.2, 1),NULL));
}
void movedTiled::moveTo(int r, int c)
{
this->m_row = r;
this->m_col = c;
this->setPosition(c*GAME_TILED_WIDTH + (c + 1)*GAME_TILED_BOARD_WIDTH, (3 - r)*GAME_TILED_WIDTH + (4 - r)*GAME_TILED_BOARD_WIDTH);
}
void movedTiled::doubleNumber()
{
this->m_number = this->m_number * 2;
auto bk=this->getChildByTag(100);
Label* label = (Label*)bk->getChildByTag(101);
label->setBMFontFilePath("fonts/bitmapFontChinese.fnt");
label->setString(StringUtils::format("%d", this->m_number));
SimpleAudioEngine::getInstance()->playEffect("2.wav");
bk->runAction(Sequence::create(ScaleTo::create(0.2, 0.8), ScaleTo::create(0.2, 1.2), ScaleTo::create(0.2, 1), NULL));
switch (this->m_number)
{
case 4:
bk->setColor(Color3B(255, 182, 193));
break;
case 8:
bk->setColor(Color3B(255, 0, 255));
break;
case 16:
bk->setColor(Color3B(138, 43,226));
break;
case 32:
bk->setColor(Color3B(65, 105, 225));
break;
case 64:
bk->setColor(Color3B(30, 144, 255));
break;
case 128:
bk->setColor(Color3B(127, 255, 0));
break;
case 256:
bk->setColor(Color3B(255, 215, 0));
break;
case 512:
bk->setColor(Color3B(210, 105, 30));
break;
case 1024:
bk->setColor(Color3B(255, 69, 0));
break;
case 2048:
bk->setColor(Color3B(188, 143, 143));
break;
default:
break;
}
}
(4)游戏结束类GameOver;
GameOver.h
#include"cocos2d.h"
USING_NS_CC;
class GameOver :public Layer
{
public:
bool init();
CREATE_FUNC(GameOver);
static Scene* createScene();
void menuCallBack(Ref *pObject);
};
GameOver.cpp
#include"GameOver.h"
#include"GameScene.h"
bool GameOver::init()
{
if (!Layer::init())
{
return false;
}
//显示游戏结束
Size viewSize = Director::getInstance()->getVisibleSize();
auto label = Label::createWithBMFont("fonts/futura-48.fnt", "GameOver");
label->setPosition(Point(viewSize.width / 2, viewSize.height / 2));
label->setScale(1.5);
this->addChild(label);
auto label1 = Label::createWithBMFont("fonts/futura-48.fnt", "Restart Game");
auto labelItem = MenuItemLabel::create(label1, CC_CALLBACK_1(GameOver::menuCallBack, this));
labelItem->setPosition(Point(viewSize.width / 2, viewSize.height / 4));
auto menu = Menu::createWithItem(labelItem);
menu->setPosition(Point::ZERO);
this->addChild(menu);
return true;
}
void GameOver::menuCallBack(Ref*pObject)
{
auto scene = Game::createScene();
Director::getInstance()->replaceScene(TransitionFadeDown::create(0.2, scene));
}
Scene* GameOver::createScene()
{
Scene*scene = Scene::create();
Layer *layer = GameOver::create();
scene->addChild(layer);
return scene;
}