前面是節介紹了Cocos2dx的相關知識,也實現了相關場景,這一節設計的遊戲的具體實現啦,我們看一下新增的類,主要有小球類ball,定義類define,全局方法類GlobalManage,主場景類GameScene
這一節完成後大家就可以初步進行遊戲啦,前介紹過的相關功能在本章節中都有體現哦,這章節主要就上代碼吧。
下面我們看下文件列表,可以看到紅框中新增的文件,下面介紹文件的具體實現。
大家將第二場景的跳轉轉向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;
}
到這裏,我們遊戲的主邏輯就實現了,大家已經可以點擊小球進行玩耍了,整個遊戲的主體玩法已經實現了,下面是不是要打開腦洞,想象如何讓整個遊戲更有趣呢?
下一章節將會一起實現遊戲的結算界面和遊戲音效,後面還會介紹如何增加趣味性哦。