Cocos2dx遊戲教程(十一):“見縫插針”,主場景實現

前面是節介紹了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;
}

到這裏,我們遊戲的主邏輯就實現了,大家已經可以點擊小球進行玩耍了,整個遊戲的主體玩法已經實現了,下面是不是要打開腦洞,想象如何讓整個遊戲更有趣呢?

下一章節將會一起實現遊戲的結算界面和遊戲音效,後面還會介紹如何增加趣味性哦。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章