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;
}

到这里,我们游戏的主逻辑就实现了,大家已经可以点击小球进行玩耍了,整个游戏的主体玩法已经实现了,下面是不是要打开脑洞,想象如何让整个游戏更有趣呢?

下一章节将会一起实现游戏的结算界面和游戏音效,后面还会介绍如何增加趣味性哦。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值