Cocos2d-x 3.2制作三消游戏《万圣大作战》1:开始界面&创建精灵
三消游戏是一类将三个相同元素点击合成即可消除的游戏。今天,我们以《万圣大作战》这款时下受众多玩家喜爱的三消游戏为例,进行一次实例学习。
1. 准备工作
前期的环境配置步骤,可参考有关Cocos2d-x 3.0在WIN7 + VS2012平台搭建的知识,该知识在3.0及以上版本基本通用,至少在3.2版本中没有问题。
建立项目
第一步,调整分辨率。在AppDelegate.cpp文件中的applicationDidFinishLaunching函数里进行如下操作:
bool AppDelegate::applicationDidFinishLaunching() {
// 初始化导演
auto director = Director::getInstance();
auto glview = director->getOpenGLView();
if (!glview) {
glview = GLView::create("My Game");
director->setOpenGLView(glview);
glview->setFrameSize(320, 480);
}
glview->setDesignResolutionSize(480, 800, ResolutionPolicy::EXACT_FIT);
// 开启FPS显示
director->setDisplayStats(true);
// 设置帧率,若不调用此函数,默认值为1.0 / 60
director->setAnimationInterval(1.0 / 60);
// 创建一个场景,它是一个自动释放对象
auto scene = HelloWorld::createScene();
// 运行场景
director->runWithScene(scene);
return true;
}
2. 界面的制作
制作开始界面
新建一个类WelcomeScene。
WelcomeScene.h文件
#ifndef __WELCOME_SCENE_H__
#define __WELCOME_SCENE_H__
#include "cocos2d.h"
class WelcomeScene : public cocos2d::Layer {
public:
static cocos2d::Scene* createScene();
virtual bool init();
void menuStartCallback(Ref* pSender);
CREATE_FUNC(WelcomeScene);
};
#endif // __WELCOME_SCENE_H__
在这中间,需要先创建一个GameDefine.h头文件,用于存放一些关于游戏的宏定义,本次用于存放画布的宽高,后续还会存放其他定义。
GameDefine.h文件
#ifndef _Inkmoo_Elimination_h_
#define _Inkmoo_Elimination_h_
// 定义屏幕宽高,这与所做的图片有关
#define GAME_SCREEN_WIDTH 480
#define GAME_SCREEN_HEIGHT 800
#endif
现在,我们就可以在其他文件中使用这些宏定义了。
WelcomeScene.cpp文件
#include "WelcomeScene.h"
#include "GameDefine.h"
USING_NS_CC;
Scene* WelcomeScene::createScene() {
auto scene = Scene::create();
auto layer = WelcomeScene::create();
scene->addChild(layer);
return scene;
}
// 欢迎界面初始化函数
bool WelcomeScene::init() {
// 先初始化父类,不成功则返回false
if (!Layer::init()) {
return false;
}
// 添加背景图片
auto sprite = Sprite::create("scene_sta.png");
sprite->setPosition(Point(GAME_SCREEN_WIDTH / 2, GAME_SCREEN_HEIGHT / 2));
this->addChild(sprite);
// 添加开始按钮
auto startItem = MenuItemImage::create(
"btn_start01.png",
"btn_start02.png",
CC_CALLBACK_1(WelcomeScene::menuStartCallback, this)
);
startItem->setPosition(Vec2(GAME_SCREEN_WIDTH / 2, GAME_SCREEN_HEIGHT / 6));
auto menu = Menu::create(startItem, NULL);
menu->setPosition(Vec2::ZERO);
this->addChild(menu);
return true;
}
void WelcomeScene::menuStartCallback(Ref* pSender) {
// 跳转到游戏界面
}
制作游戏界面
GameScene.h文件
#ifndef __GAME_SCENE_H__
#define __GAME_SCENE_H__
#include "cocos2d.h"
class GameScene : public cocos2d::Layer {
public:
static cocos2d::Scene* createScene();
virtual bool init();
// 返回欢迎界面函数
void menuBackCallback(Ref* pSender);
CREATE_FUNC(GameScene);
};
#endif // __GAME_SCENE_H__
GameScene.cpp文件
#include "GameScene.h"
#include "GameDefine.h"
#include "WelcomeScene.h"
USING_NS_CC;
Scene* GameScene::createScene() {
auto scene = Scene::create();
auto layer = GameScene::create();
scene->addChild(layer);
return scene;
}
// 游戏界面初始化函数
bool GameScene::init() {
// 先初始化父类,不成功则返回false
if (!Layer::init()) {
return false;
}
// 添加背景图片
auto sprite = Sprite::create("scene_bg.png");
sprite->setPosition(Point(GAME_SCREEN_WIDTH / 2, GAME_SCREEN_HEIGHT / 2));
this->addChild(sprite, -1);
// 添加返回按钮
auto backItem = MenuItemImage::create(
"btn_back01.png",
"btn_back02.png",
CC_CALLBACK_1(GameScene::menuBackCallback, this)
);
backItem->setPosition(Vec2(GAME_SCREEN_WIDTH - backItem->getContentSize().width / 2, backItem->getContentSize().height / 2));
auto menu = Menu::create(backItem, NULL);
menu->setPosition(Vec2::ZERO);
this->addChild(menu);
return true;
}
// 返回函数,跳转到欢迎界面
void GameScene::menuBackCallback(Ref* pSender) {
auto scene = WelcomeScene::createScene();
CCDirector::sharedDirector()->replaceScene(scene);
}
需要注意的是,要修改之前欢迎界面的menuStartCallback函数:
void WelcomeScene::menuStartCallback(Ref* pSender) {
// 跳转到游戏界面
auto scene = GameScene::createScene();
CCDirector::sharedDirector()->replaceScene(scene);
}
现在,我们可以运行程序,在欢迎界面点击“开始”进入游戏界面,在游戏界面点击“返回主菜单”回到欢迎界面。
3. 精灵相关
前面的内容都是准备工作,接下来,我们要添加相应的精灵。这些精灵的素材存放在一张png图片里,可使用TexturePacker进行压缩(如果不会使用,请参考《Cocos2d-x 3.x使用plist和png制作动画》)。
三消游戏主要涉及精灵的创建、移动和消除操作。这些精灵在游戏界面的存储方式类似于二维表格,因此需要一个单独的类来管理精灵。
SpriteShape.h文件
#include "cocos2d.h"
#include "GameDefine.h"
USING_NS_CC;
class SpriteShape : public Sprite {
public:
static SpriteShape* create(int row, int col);
CC_SYNTHESIZE(int, m_row, Row);
CC_SYNTHESIZE(int, m_col, Col);
CC_SYNTHESIZE(int, m_imgIndex, ImgIndex);
};
create函数用于根据传入的行列值,在相应位置创建精灵。CC_SYNTHESIZE宏相当于自动生成两个函数,以CC_SYNTHESIZE(int, m_row, Row)为例,它会定义一个int类型的保护型变量m_row,并定义一个setRow函数和一个getRow函数,用于对m_row进行操作。
SpriteShape.cpp文件
#include "SpriteShape.h"
SpriteShape* SpriteShape::create(int row, int col) {
SpriteShape* spr = new SpriteShape();
spr->m_row = row;
spr->m_col = col;
spr->m_imgIndex = rand() % TOTAL_SPRITE;
spr->initWithSpriteFrameName(spriteNormal[spr->m_imgIndex]);
spr->autorelease();
return spr;
}
该函数的实现步骤为:先通过传参定位精灵的位置,然后获取一个随机数,该随机数的范围要在精灵种类数内,最后根据随机数获取对应的图片。
GameDefine.h文件补充
// 定义每个精灵大小与边框大小
#define SPRITE_WIDTH 48
#define BOADER_WIDTH 2
// 游戏精灵行数和列数
#define ROWS 8
#define COLS 8
// 精灵种类总数
#define TOTAL_SPRITE 6
// 普通的精灵
static const char* spriteNormal[TOTAL_SPRITE] = {
"icon1.png",
"icon2.png",
"icon3.png",
"icon4.png",
"icon5.png",
"icon6.png"
};
在游戏界面显示精灵
游戏界面类似于一个大的二维表格,我们需要先创建这个表格,然后定义一个初始化地图函数来初始化表格。
GameScene.cpp文件补充
// 初始化地图
void GameScene::initMap() {
for (int r = 0; r < ROWS; ++r) {
for (int c = 0; c < COLS; ++c) {
createSprite(r, c);
}
}
}
// 创建精灵
void GameScene::createSprite(int row, int col) {
// 先创建一个精灵
SpriteShape* spr = SpriteShape::create(row, col);
Point endPosition = positionOfItem(row, col);
spr->setPosition(endPosition);
// 加入到spriteSheet中,等待绘制
spriteSheet->addChild(spr);
// 数组相应位置,置上精灵对象
map[row][col] = spr;
}
// 根据行列,获取坐标值
Point GameScene::positionOfItem(int row, int col) {
float x = mapLBX + (SPRITE_WIDTH + BOADER_WIDTH) * col + SPRITE_WIDTH / 2;
float y = mapLBY + (SPRITE_WIDTH + BOADER_WIDTH) * row + SPRITE_WIDTH / 2;
return Point(x, y);
}
现在运行程序,精灵就会出现在游戏界面中。
4. 额外改进
目前实现的效果有些过于平面,我们可以添加一个2.1D的下落动作。具体做法是在创建精灵时,将其放置在原来位置上方一定距离处,然后通过一定速度下落到原来位置,这可以通过添加一个动作来实现。
GameScene.cpp文件修改
// 创建精灵
void GameScene::createSprite(int row, int col) {
// 先创建一个精灵
SpriteShape* spr = SpriteShape::create(row, col);
// 创建下落动画
Point endPosition = positionOfItem(row, col);
Point startPosition = Point(endPosition.x, endPosition.y + GAME_SCREEN_HEIGHT / 2);
spr->setPosition(startPosition);
float speed = startPosition.y / (1.5 * GAME_SCREEN_HEIGHT);
spr->runAction(MoveTo::create(speed, endPosition));
// 加入到spriteSheet中,等待绘制
spriteSheet->addChild(spr);
// 数组相应位置,置上精灵对象
map[row][col] = spr;
}
现在可以运行程序,体验改进后的效果。