前面是节介绍了Cocos2dx的相关知识,也实现了相关场景,这一节设计的游戏的具体实现啦,我们看一下新增的类,主要有小球类ball,定义类define,全局方法类GlobalManage,主场景类GameScene
这一节完成后大家就可以初步进行游戏啦,前介绍过的相关功能在本章节中都有体现哦,这章节主要就上代码吧。
下面我们看下文件列表,可以看到红框中新增的文件,下面介绍文件的具体实现。
1、相关定义
#pragma once
#include "cocos2d.h"
USING_NS_CC;
using namespace std;
/*******************************************************************************
* 全局相关
********************************************************************************/
//屏幕大小
#define WINSIZE (Director::getInstance()->getWinSize())
//可视区域
#define VISIBLE_SIZE (Director::getInstance()->getVisibleSize())
//可视区域起点坐标
#define VISIBLE_ORIGIN_SIZE (Director::getInstance()-getVisibleOrigin())
//重写to_string
#if CC_TARGET_PLATFORM == CC_PLATFORM_MAC || CC_TARGET_PLATFORM == CC_PLATFORM_IOS || CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID
template<typename T>
string to_string(const T& t) {
ostringstream os;
os << t;
return os.str();
}
#endif
2、小球对象
#pragma once
#include "cocos2d.h"
USING_NS_CC;
class Ball : public Sprite {
public:
Ball();
~Ball();
//创建小球
static Ball *create(int num = 0);
public:
Label *numTTF;
};
#include "Ball.h"
#include "Defines.h"
Ball::Ball() {
}
Ball::~Ball() {
}
//创建数字小球
Ball *Ball::create(int num) {
Ball *ball = new Ball();
ball->initWithFile("scene/ball_1.png");
if(num != 0) {
ball->numTTF = Label::createWithCharMap("fonts/label/label_ball.png", 14, 20, '0');
ball->numTTF->setString(to_string(num));
ball->numTTF->setPosition(ball->getContentSize() / 2);
ball->addChild(ball->numTTF);
}
else {
ball->setTexture("scene/ball_0.png");
}
return ball;
}
3.主场景
#pragma once
#include "cocos2d.h"
#include "cocos-ext.h"
#include "Ball.h"
USING_NS_CC;
extern LanguageType type;
class GameScene : public Layer{
public:
GameScene();
~GameScene();
//新建场景
static Scene* createScene();
//create()方法
CREATE_FUNC(GameScene);
//初始化
virtual bool init();
//触摸开始方法
bool onTouchBegan(Touch* touch, Event* event);
//触摸移动方法
void onTouchMoved(Touch* touch, Event* event);
//触摸结束方法
void onTouchEnded(Touch* touch, Event* event);
//刷新游戏
void update(float dt);
public:
void onKeyReleased(EventKeyboard::KeyCode keycode, Event* event);
public:
//绘制场景
void drawScene();
//初始化玩家小球
void initUserBall(int num);
//绘制遮罩圆(以Y轴为0角度)(参数:绘制的坐标,开始角度,终止角度,内部圆半径,外部圆半径,绘制的颜色)
void drawCoverCircle(Vec2 &point, int startAngle, int endAngle, int radiusSmall, int radiusBig, Color4F &color);
//将玩家小球加入旋转
void addUserBallToCircle(Ball *ball);
//检测小球是否碰撞
void checkIsBallCollision(Ball *userBall, Ball *circleBall);
//获得旋转动作
ActionInterval *getCircleAction(float speed);
//创建失败层
void createFailedLayer();
//创建胜利层
void createSuccessLayer();
//绘制飞行小球
void createFlyBall();
public:
//游戏暂停按钮
void onPauseBtnPressed(Ref* pSender);
//点击显示辅助线
void onAuxiliaryLineBtnPressed(Ref* pSender);
//帮助按钮
void onHelpBtnPressed(Ref* pSender);
private:
//旋转速度(度/秒)
float speed;
//关卡用户小球个数
int userBallNum;
//中心圈
Sprite *circle;
//旋转动作
ActionInterval *rotate;
//所有小球列表
std::vector<Ball *> ballList;
//玩家小球列表
std::vector<Ball *> userBallList;
//飞行小球
Sprite *flyBall;
float flyBallX;
float flyBallY;
private:
bool isBallCollision;
bool isCanTouch;
bool isFlyBallCollision;
};
#include "GameScene.h"
#include "GlobalManage.h"
#include "GameDataManage.h"
#include "GameMenuScene.h"
#include "Defines.h"
GameScene::GameScene() :speed(0), userBallNum(0), rotate(NULL), isBallCollision(false), isCanTouch(false){
}
GameScene::~GameScene() {
}
//新建场景
Scene *GameScene::createScene()
{
Scene *scene = Scene::create();
Layer *layer = GameScene::create();
scene->addChild(layer);
return scene;
}
//初始化
bool GameScene::init() {
if(!Layer::init()) {
return false;
}
ballList.clear();
speed = GameDataManage::getInstance()->rotateSpeed;
rotate = getCircleAction(speed);
//绘制场景
drawScene();
//绘制玩家小球
userBallNum = GameDataManage::getInstance()->userBallNum;
initUserBall(userBallNum);
//创建一个触摸监听
auto touchListener = EventListenerTouchOneByOne::create();
//向下传递触摸事件
touchListener->setSwallowTouches(false);
touchListener->onTouchBegan = CC_CALLBACK_2(GameScene::onTouchBegan, this);
touchListener->onTouchMoved = CC_CALLBACK_2(GameScene::onTouchMoved, this);
touchListener->onTouchEnded = CC_CALLBACK_2(GameScene::onTouchEnded, this);
touchListener->onTouchCancelled = CC_CALLBACK_2(GameScene::onTouchCancelled, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(touchListener, this);
//注册捕捉监听
auto listenerkeyPad = EventListenerKeyboard::create();
listenerkeyPad->onKeyReleased = CC_CALLBACK_2(GameScene::onKeyReleased, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listenerkeyPad, this);
scheduleUpdate();
return true;
}
//触摸开始方法
bool GameScene::onTouchBegan(Touch* touch, Event* event) {
if(!isCanTouch) {
return false;
}
if(isBallCollision) {
return false;
}
if(userBallList.size() > 0) {
userBallList.at(0)->runAction(Sequence::create(
MoveTo::create(0.2f, Point(360, 620)),
//CallFunc::create(CC_CALLBACK_0(GameScene::addUserBallToCircle, this, userBallList.at(0))),
NULL));
userBallList.at(0)->runAction(Sequence::create(
CallFunc::create(CC_CALLBACK_0(GameScene::addUserBallToCircle, this, userBallList.at(0))),
NULL));
}
return true;
}
//触摸移动方法
void GameScene::onTouchMoved(Touch* touch, Event* event) {
}
//触摸结束方法
void GameScene::onTouchEnded(Touch* touch, Event* event) {
}
void GameScene::onKeyReleased(EventKeyboard::KeyCode keycode, Event* event) {
if (keycode == EventKeyboard::KeyCode::KEY_ESCAPE) {
Director::getInstance()->replaceScene(GameMenuScene::createScene());
} else if (keycode == EventKeyboard::KeyCode::KEY_MENU) {
}
}
//刷新游戏
void GameScene::update(float dt) {
//刷新玩家小球位置
auto max = userBallList.size() >= 4 ? 4 : userBallList.size();
for(unsigned int i = 0; i < max; i++) {
auto ball = userBallList.at(i);
if(!ball) {
continue;
}
ball->setPosition(360, 300 - 42 * i);
ball->setVisible(true);
}
//检测是否碰撞,如果碰撞,游戏结束
if(isBallCollision) {
circle->stopAction(rotate);
unscheduleUpdate();
}
if(!isBallCollision) {
if(userBallNum == 0) {
unscheduleUpdate();
}
}
}
//绘制场景
void GameScene::drawScene() {
//绘制游戏背景
auto bg = Sprite::create("scene/bg.jpg");
bg->setPosition(WINSIZE / 2);
this->addChild(bg);
//关卡
auto level = Sprite::create("scene/level.png");
level->setPosition(WINSIZE.width / 2, WINSIZE.height - 83);
this->addChild(level);
auto levelTTF = Label::createWithCharMap("fonts/label/label_level_1.png", 31, 42, '0');
levelTTF->setString(StringUtils::format("%d", GlobalManage::getInstance()->currentLevel));
levelTTF->setPosition(level->getContentSize() / 2);
level->addChild(levelTTF);
//投影
auto shadow = Sprite::create("scene/shadow.png");
shadow->setPosition(WINSIZE.width / 2, WINSIZE.height / 2 - 500);
this->addChild(shadow, 1);
shadow->runAction(MoveBy::create(0.3f, Point(0, 630)));
//绘制中心圈
std::string circleName;
circleName = StringUtils::format("scene/circle_%d.png", GlobalManage::getInstance()->currentLevel % 3);
circle = Sprite::create(circleName);
circle->setPosition(WINSIZE.width / 2, WINSIZE.height / 2 - 500);
this->addChild(circle, 1);
circle->runAction(rotate);
circle->runAction(Sequence::create(
MoveBy::create(0.3f, Point(0, 700)),
CallFunc::create([&](){
isCanTouch = true;}),
NULL));
//绘制关卡障碍物小球
auto obsNum = GameDataManage::getInstance()->obsBallNum;
for(int i = 0; i < obsNum; i++) {
auto ball = Ball::create();
auto pos = GlobalManage::getInstance()->getCirclePoint(obsNum, i, circle->getContentSize() / 2, Point(circle->getContentSize().width / 2, circle->getContentSize().height / 2 + 250.0f));
ball->setPosition(pos.x, pos.y);
circle->addChild(ball);
ballList.push_back(ball);
//创建DrawNode,然后后加入到Layer层中
DrawNode* drawNode = DrawNode::create();
circle->addChild(drawNode, -1);
//drawNode->drawSegment(circle->getContentSize() / 2, ball->getPosition(), 1, Color4F(57.0f / 255.0f, 60.0f / 255.0f, 77.0f / 255.0f, 1));
drawNode->drawSegment(circle->getContentSize() / 2, ball->getPosition(), 1, Color4F(142.0f / 255.0f, 72.0f / 255.0f, 12.0f / 255.0f, 1));
}
//绘制点连接线
DrawNode* drawDot = DrawNode::create();
this->addChild(drawDot, 10, "drawdot");
drawDot->drawDot(Vec2(WINSIZE.width / 2, 340), 5, Color4F(142.0f / 255.0f, 72.0f / 255.0f, 12.0f / 255.0f, 1));
drawDot->drawDot(Vec2(WINSIZE.width / 2, 380), 5, Color4F(142.0f / 255.0f, 72.0f / 255.0f, 12.0f / 255.0f, 1));
drawDot->drawDot(Vec2(WINSIZE.width / 2, 420), 5, Color4F(142.0f / 255.0f, 72.0f / 255.0f, 12.0f / 255.0f, 1));
drawDot->drawDot(Vec2(WINSIZE.width / 2, 460), 5, Color4F(142.0f / 255.0f, 72.0f / 255.0f, 12.0f / 255.0f, 1));
drawDot->drawDot(Vec2(WINSIZE.width / 2, 500), 5, Color4F(142.0f / 255.0f, 72.0f / 255.0f, 12.0f / 255.0f, 1));
drawDot->drawDot(Vec2(WINSIZE.width / 2, 540), 5, Color4F(142.0f / 255.0f, 72.0f / 255.0f, 12.0f / 255.0f, 1));
drawDot->drawDot(Vec2(WINSIZE.width / 2, 580), 5, Color4F(142.0f / 255.0f, 72.0f / 255.0f, 12.0f / 255.0f, 1));
//drawDot->drawDot(Vec2(WINSIZE.width / 2, 620), 5, Color4F(142.0f / 255.0f, 72.0f / 255.0f, 12.0f / 255.0f, 1));
drawDot->setVisible(false);
//暂停按钮
auto pause = MenuItemImage::create(
"scene/pause.png",
"scene/pause.png",
CC_CALLBACK_1(GameScene::onPauseBtnPressed, this));
pause->setPosition(80, WINSIZE.height - 80);
//辅助圆按钮
auto auxiliary = MenuItemImage::create(
"scene/auxiliary.png",
"scene/auxiliary.png",
CC_CALLBACK_1(GameScene::onAuxiliaryLineBtnPressed, this));
auxiliary->setPosition(640, WINSIZE.height - 80);
//帮助按钮
auto help = MenuItemImage::create(
"scene/help.png",
"scene/help.png",
CC_CALLBACK_1(GameScene::onHelpBtnPressed, this));
help->setPosition(80, WINSIZE.height - 200);
auto menu = Menu::create(pause, auxiliary, help, NULL);
menu->setPosition(Point::ZERO);
this->addChild(menu);
}
//绘制遮罩圆(以Y轴为0角度)(参数:绘制的坐标,开始角度,终止角度,内部圆半径,外部圆半径,绘制的颜色)
void GameScene::drawCoverCircle(Vec2 &point, int startAngle, int endAngle, int radiusSmall, int radiusBig, Color4F &color) {
}
//获得旋转动作
ActionInterval *GameScene::getCircleAction(float speed) {
auto action = RepeatForever::create(RotateBy::create(1.0f, speed));
return action;
}
//初始化玩家小球
void GameScene::initUserBall(int num) {
for(int i = 0; i < num; i++) {
auto ball = Ball::create(num - i);
ball->setPosition(360, 300 - 42 * i);
ball->setVisible(false);
this->addChild(ball);
userBallList.push_back(ball);
}
}
//将玩家小球加入旋转
void GameScene::addUserBallToCircle(Ball *ball) {
//创建一个元素
auto newBall = Ball::create(atoi(ball->numTTF->getString().c_str()));
newBall->setPosition(circle->convertToNodeSpace(Point(360, 590)));
circle->addChild(newBall);
//创建DrawNode,然后后加入到Layer层中
DrawNode* drawNode = DrawNode::create();
circle->addChild(drawNode, -1);
//drawNode->drawSegment(circle->getContentSize() / 2, newBall->getPosition(), 1, Color4F(57.0f / 255.0f, 60.0f / 255.0f, 77.0f / 255.0f, 1));
drawNode->drawSegment(circle->getContentSize() / 2, newBall->getPosition(), 1, Color4F(142.0f / 255.0f, 72.0f / 255.0f, 12.0f / 255.0f, 1));
for(unsigned int i = 0; i < ballList.size(); i++) {
checkIsBallCollision(newBall, ballList.at(i));
}
ballList.push_back(newBall);
//清空
ball->removeFromParentAndCleanup(true);
userBallNum--;
//删除第一个元素
userBallList.erase(userBallList.begin(), userBallList.begin()+1);
}
//检测小球是否碰撞
void GameScene::checkIsBallCollision(Ball *userBall, Ball *circleBall) {
if(GlobalManage::getInstance()->getTwoPointDistance(userBall->getPosition(), circleBall->getPosition()) < 40) {
isBallCollision = true;
return;
}
}
//创建失败层
void GameScene::createFailedLayer() {
}
//创建胜利层
void GameScene::createSuccessLayer() {
}
//游戏暂停按钮
void GameScene::onPauseBtnPressed(Ref* pSender) {
}
//点击显示辅助线
void GameScene::onAuxiliaryLineBtnPressed(Ref* pSender) {
}
//帮助按钮
void GameScene::onHelpBtnPressed(Ref* pSender) {
}
//绘制飞行小球
void GameScene::createFlyBall() {
flyBall = Ball::create();
flyBall->setPosition(Vec2(-20, 300));
this->addChild(flyBall);
flyBallX = flyBall->getPosition().x;
flyBallY = flyBall->getPosition().y;
}
4.一些全局参数
#pragma once
#include "cocos2d.h"
USING_NS_CC;
using namespace std;
typedef struct {
float x;
float y;
}CirclePoint;
class GlobalManage {
public:
GlobalManage();
~GlobalManage();
//全局单例
static GlobalManage *singleInstance;
//返回全局单例
static GlobalManage *getInstance();
public:
//圆内接多边形顶点
CirclePoint getCirclePoint(int n, int i, Point circleCenter, Point point);
//判断两点的距离
float getTwoPointDistance(Point pos_1, Point pos_2);
//绘制半圆
void drawSolidSector(const Vec2 &orign,const Vec2 &beginVec, const float radius1, const float radius2, const float radian, const int segments, const cocos2d::Color4F &color);
public:
//当前关卡
int currentLevel;
public:
//是否播放音乐
bool isPlayMusic;
//是否播放音效
bool isPlayEffect;
};
#include "GlobalManage.h"
#include "GBK2UTF.h"
#define PI 3.1415926
USING_NS_CC;
//创建全局单例
GlobalManage* GlobalManage::singleInstance = NULL;
GlobalManage* GlobalManage::getInstance()
{
if(singleInstance == NULL)
{
singleInstance = new GlobalManage();
}
return singleInstance;
}
GlobalManage::GlobalManage()
: currentLevel(1)
, isPlayMusic(true)
, isPlayEffect(true)
{
}
//圆内接多边形顶点
CirclePoint GlobalManage::getCirclePoint(int n, int i, Point circleCenter, Point point) {
float a = 2 * 3.14159265 / n;
float b = atan2(point.y - circleCenter.y, point.x - circleCenter.x);
auto radius = sqrt((point.y - circleCenter.y) * (point.y - circleCenter.y) + (point.x - circleCenter.x) * (point.x - circleCenter.x));
CirclePoint pos;
pos.y = radius * sin(a * i + b) + circleCenter.y;
pos.x = radius * cos(a * i + b) + circleCenter.x;
return pos;
}
//判断两点的距离
float GlobalManage::getTwoPointDistance(Point pos_1, Point pos_2) {
auto distance = pos_1.getDistance(pos_2);
return distance;
}
到这里,我们游戏的主逻辑就实现了,大家已经可以点击小球进行玩耍了,整个游戏的主体玩法已经实现了,下面是不是要打开脑洞,想象如何让整个游戏更有趣呢?
下一章节将会一起实现游戏的结算界面和游戏音效,后面还会介绍如何增加趣味性哦。