【Cocos2dx】跑酷游戏

前端之家收集整理的这篇文章主要介绍了【Cocos2dx】跑酷游戏前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

下面将用Cocos2dx完成一个跑酷游戏,跑酷游戏从头到尾包括美工完全可以一个人完成,就是比较耗费时间,只能达到能玩的程度而已。

做出来的跑酷游戏如下所示:


玩家能做的就只有一个动作,触摸屏幕,触摸屏幕之后,游戏的主角,就是黑色的方块,能够向上跳跃,再次触摸就能够二段跳,

而在屏幕右上方则有不停发射的箭矢,玩家控制的黑色方块被射中,则会掉10滴血,从1000血可以扣,扣到0则游戏自动重新开始。在屏幕的左上方与中上部有当前的血量显示,而右上角是分数,玩家能撑住,躲过箭矢,分数就会增加

左下与右下是必须提供的两个功能,一个是暂停游戏,一个是退出游戏,这些小游戏就不提供保存了……(其实,主要是笔者太菜,Cocos2dx的关卡功能与保存功能还有待研究,不会做的缘故。)

一、基本准备

好,游戏大致是这样的情况。在开始游戏之前,我们先要利用(cocos2d-x-2.2.6安装目录)\tools\project-creator下的create_project.py用python命令创建一个名为RunGame的工程。具体是用命令行进入到此文件夹,利用如下命令,新建工程

python create_project.py -project Rungame -package test.Rungame -language cpp

之后准备素材到RunGame的资源文件夹Resource中,上述游戏用到了如下的素材:


1、图片准备

除了各种自带的素材,下面说说每一张图片是如何自己用WIN7画图搞出来的。

首先是关于血条的1.png,就是一张1x1的图片,自己在画图的属性调出一张1x1的图片,之后保存即可。


kuang.png,之后是框,同时用于血条与按钮,具体是用画图的圆角矩形工具一拖就有了,属性设置为100x25像素


hp_full.png,最后是满血状态的血条,是在kuang.png上面加工,用刷子工具,涂上两涂就可以了。大小同上。


至于为什么要这样整,具体可以参考我之前的《【Cocos2dx】利用音量螺旋控件控制血量条》(点击打开链接

接着是背景backgroud.png,就是利用画图的三角形工具与直线工具,加文字工具弄出来的,唯一注意到的是要适配游戏的屏幕大小,在480x320的像素上创作。


player.png直接将属性设置为40x40,用黑色一填充就完事。


kuang_fan.png,是根据kuang.png用画图的反色工具,一整就出来了。


最后是,稍微有点复杂的是array.png,用画图的直线工具搞出来之后,还要通过photoshop将array.png白色的部分扣出来搞成透明,当然,不整也可以,只是在游戏运行的时候不美观而已。

2、strings.xml,具体如下,原理同《【Cocos2dx】中文乱码问题》(点击打开链接),主要防止乱码。

<dict>
    <key>fanhui</key>
    <string>返回</string>
    <key>xueliang</key>
    <string>血量:</string>
    <key>fenshu</key>
    <string>分数:</string>
    <key>zanting</key>
    <string>暂停</string>
    <key>tuichu</key>
    <string>退出</string>
</dict>

二、工程制作

之后就可以开始工程的制作了,整个工程的UML大致如下:


先提醒大家注意,新建的类一定要放在Classes这个文件夹,如果放在proj.win32就悲剧了,这个我在《【Cocos2dx】新建场景、场景的切换、设置启动场景与菜单的新建》(点击打开链接)中已经提到过了,不在赘述。

先来说两个处于次要地位的类。

首先是飘字类FlowWord,这个类完全与《【Cocos2dx】飘字特效与碰撞检测》(点击打开链接)原理一样,只是改了把字体的颜色从黄色改成红色而已。

FlowWord.h:

#include "cocos2d.h"

USING_NS_CC;  
  
class FlowWord:public CCNode{  
public:  
    void showWord(const char* text,CCPoint pos);//飘字方法,text为飘字的内容,pos为飘字的位置  
private:  
    CCLabelTTF* label;//类成员  
    void flowEnd();//飘字结束时的回调(处理)函数,主要用于删除自己      
};

FlowWord.cpp:
#include "FlowWord.h"

void FlowWord::showWord(const char* text,CCPoint position){//text为飘字的内容,pos为飘字的位置  
	/*初始化*/  
	label=CCLabelTTF::create(text,"Arial",18);//创建一个字体为Arial,字号为18,内容为text的CCLabelTTF,也就是标签文本  
	label->setColor(ccc3(255,0));//设置其颜色为红色
	label->setPosition(position);//设置其位置  
	this->addChild(label);//在场景上添加这个标签文本  
	/*三个动作,放大->移动->缩小*/     
	CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();//获取屏幕的尺寸、位置信息等       
	CCFiniteTimeAction* action1=CCScaleTo::create(0.2f,3.0f,3.0f);//0.2s内在x、y上方向皆放大为原尺寸的3倍  
	CCFiniteTimeAction* action2=CCMoveTo::create(0.3f,ccp(visibleSize.width/4,3*visibleSize.height/4));//在0.3s内,移动到坐标为(x=屏幕宽度的25%,y=屏幕高度的75%处)  
	CCFiniteTimeAction* action3 = CCScaleTo::create(0.2f,0.1f,0.1f);//之后在0.2s内在x、y上皆缩小为原尺寸的0.1倍  
	CCCallFunc* callFunc = CCCallFunc::create(this,callfunc_selector(FlowWord::flowEnd));//声明一个回调(处理)函数,为FlowWord类中的flowEnd()  
	CCFiniteTimeAction* action = CCSequence::create(action1,action2,action3,callFunc,NULL);//以上的所有动作组成动作序列action  
	/*对label实行action这个动作*/  
	label->runAction(action);  
}  

void FlowWord::flowEnd(){//动作结束,从父节点中删除自身  
	label->setVisible(false);//先隐藏显示  
	label->removeFromParentAndCleanup(true);//再删除  
}  

之后是暂停场景PauseScene,这个原理也在《【Cocos2dx】利用导演类、场景类完成重新开始游戏、暂停游戏、关闭游戏功能》( 点击打开链接)讲过,不再赘述了。

PauseScene.h:

#include "cocos2d.h"  
#include "cocos-ext.h" //使用按钮事件,必须要需要的头文件  
USING_NS_CC_EXT;//使用按钮事件,必须要需要的命名空间    
using namespace cocos2d;  
  
class PauseScene:public CCLayer{  
public:  
    static CCScene* scene();  
    virtual bool init();  
    CREATE_FUNC(PauseScene);  
    void back(CCObject* pSender,CCControlEvent event);//返回场景  
};  

PauseScene.cpp:
#include "PauseScene.h"  

USING_NS_CC;  

CCScene* PauseScene::scene()  
{  
	CCScene *scene=CCScene::create();    
	PauseScene* pauseScene=PauseScene::create();  
	scene->addChild(pauseScene);  
	return scene;    
}  

bool PauseScene::init()  
{  
	//获取屏幕的尺寸、位置信息等      
	CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();    

	/*通过载入strings.xml的中文,防止乱码*/
	CCDictionary *strings = CCDictionary::createWithContentsOfFile("strings.xml");//利用CCDictionary来读取xml,载入资源文件夹的strings.xml
	const char *fanhui = ((CCString*)strings->objectForKey("fanhui"))->m_sString.c_str();//读取xueliang键中的值,objectForKey会根据key,获取对应的string

	//声明按钮部分    
	cocos2d::extension::CCScale9Sprite *btn_noraml=cocos2d::extension::CCScale9Sprite::create("kuang_fan.png");//声明按钮没被按下时的背景图片    
	CCLabelTTF *label1=CCLabelTTF::create(CCString::createWithFormat("%s",fanhui)->getCString(),"arial",36);//声明第1个参数是文字内容,第2个参数是字体,仅能使用Resource文件夹中fonts文件夹中的字体,第3个参数是字体大小    
	CCControlButton *controlButton=CCControlButton::create(label1,btn_noraml);//创建按钮
	controlButton->setPosition(ccp(visibleSize.width/2,visibleSize.height/2));//按钮的位于屏幕的中央    
	controlButton->addTargetWithActionForControlEvents(this,cccontrol_selector(PauseScene::back),CCControlEventTouchDown);//声明按钮的事件,第三个参数为定值常量意为,点击此按钮之后,触发第二个函数所声明的,下面给出的PauseScene::back(){}中所有代码。    
	this->addChild(controlButton);//将此按钮添加到场景,默认不自动添加      
	return true;  
}  


void PauseScene::back(CCObject* pSender,CCControlEvent event)    
{  
	//本场景出栈  
	CCDirector::sharedDirector()->popScene();  
}  

接下来比较重要的两个主角,一个玩家类,一个是怪物类:

首先是怪物类Monster,也就是那些箭矢,一只怪物很简单,声明好其开始位置、图片即可,到时候其产生与击中玩家、飞出屏幕外围的方法,在MainScene这个主场景类中控制。唯一注意的是暴露出CCSprite* sprite;自身精灵类与是否处于屏幕的标识bool isEmerge给主场景类MainScene控制。

Monster.h:

#include "cocos2d.h"
USING_NS_CC;//用到了CCxx,比如CCNode

class Monster:public CCNode{//由于用到了this->addChild(sprite);必须继承CCNode
public:
	Monster();//构造函数
	CCSprite* sprite;
	bool isEmerge;//是否处于屏幕的标识
};
Monster.cpp:
#include "Monster.h"
Monster::Monster(){
	CCSize visibleSize=CCDirector::sharedDirector()->getVisibleSize();//获取屏幕的尺寸、位置信息等
	sprite=CCSprite::create("array.png");//使用CloseSelected.png这张图片
	sprite->setScale(0.5f);
	sprite->setPosition(ccp(5*visibleSize.width/6+CCRANDOM_0_1()*visibleSize.width/6,5*visibleSize.height/6+CCRANDOM_0_1()*visibleSize.height/6));
	this->addChild(sprite);//添加到舞台
	isEmerge=true;//开始为已经出现状态
}

随后是玩家类Player,要完成的事情是三件,一个在玩家的构造函数,设置其初始诞生的位置、自身拥有的属性等;二是,其跳跃与二段跳跃具体是怎么实现的,原理与《【Cocos2dx】精灵触摸跳跃功能》( 点击打开链接)一模一样,这里不再赘述了,二段跳跃只是在此基础上加深,具体见下面代码的注释;最后是被箭矢击中,怎么做什么动作的hit(),主要就是调用FlowWord的showword()飘字,扣血除自身的hp10点。

Player.h,暴露jump()这个方法给主场景类MainScene,主场景类的触摸事件直接调用这个方法即可。hit()、hp、score都要暴露给主函数所操作、修改、判断、执行:

#include "cocos2d.h"
#include "FlowWord.h"
USING_NS_CC;//用到了CCxx,比如CCNode

class Player:public CCNode{//由于用到了this->addChild(sprite);必须继承CCNode
public:
	Player();//构造函数	
	void jump();//跳跃
	CCSprite* sprite;
	void hit();//被击中的处理函数
	float score;//当前得分
	int hp;//当前血量
private:	
	bool isJumping;//是否跳跃的flag
	void doubleJump();//二段跳的实现
	void jumpEnd();//声明跳跃结束的回调函数
	bool isDoubleJumping;//是否二段条的flag
	void doubleJumpEnd();//声明二段条结束的回调函数
};

Player.cpp:
#include "Player.h"
/*构造函数,也就是初始化的函数*/
Player::Player(){
	CCSize visibleSize=CCDirector::sharedDirector()->getVisibleSize();//获取屏幕的尺寸、位置信息等
	sprite=CCSprite::create("player.png");//使用CloseSelected.png这张图片
	sprite->setPosition(ccp(visibleSize.width/3,visibleSize.height/6));//放在屏幕大小的(1/3,1/6)这个位置
	this->addChild(sprite);//添加到舞台
	isJumping=false;//开始为没有跳跃状态
	isDoubleJumping=false;
	score=0;
	hp=1000;
}

/*被击中之后的动作*/
void Player::hit(){
	FlowWord* flowWord=new FlowWord();//初始化FlowWord  
	this->addChild(flowWord);//将FlowWord飘字特效放上舞台,尽管飘字特效,一不是精灵,二在showWord中同样有将字体放上舞台的代码,然而没有这一句,HelloWorldScene这个场景根本不会与FlowWord联系起来,也就是FlowWord中添加的Label根本无法在HelloWorldScene中显示。  
	flowWord->showWord("-10",sprite->getPosition());//执行飘字-10,位置从自身位置开始。 
	hp-=10;
}

/*跳跃*/
void Player::jump(){ 
	CCSize visibleSize=CCDirector::sharedDirector()->getVisibleSize();//获取屏幕的尺寸、位置信息等
	if(!isJumping){//如果主角还在跳跃中,则不重复执行
		isJumping=true;//标记主角为跳跃状态     
		CCJumpBy* jump=CCJumpBy::create(1.0f,ccp(0,0),visibleSize.height/2,1);//在2.0秒内,先跳起屏幕尺寸的1/2再落下0px,该动作重复1次
		CCCallFunc* callFunc=CCCallFunc::create(this,callfunc_selector(Player::jumpEnd));//创建回调函数,声明跳跃结束后调用jumpEnd函数
		CCActionInterval* jumpActions=CCSequence::create(jump,NULL);//将回调函数与跳跃动作结合起来,这个NULL不能省 
		sprite->runAction(jumpActions);//执行动作
	}
	else{//如果是在跳跃
		if(isDoubleJumping){//判断是否在二段跳
			return;//否则不能二段跳
		}
		else{//如果不是,则可以二段跳
			doubleJump();
		}
	}
};   

void Player::jumpEnd(){//主角已经完成跳跃了  
	isJumping=false;//标志主角为没有跳跃状态
	isDoubleJumping=false;
}  

/*二段跳跃*/
void Player::doubleJump(){ 
	CCSize visibleSize=CCDirector::sharedDirector()->getVisibleSize();//获取屏幕的尺寸、位置信息等
	isDoubleJumping=true;//标记主角为跳跃状态     
	CCJumpBy* double_jump=CCJumpBy::create(0.5f,visibleSize.height/3,1);//在2.0秒内,先跳起屏幕尺寸的1/2再落下0px,该动作重复1次
	CCCallFunc* callFunc=CCCallFunc::create(this,callfunc_selector(Player::doubleJumpEnd));//创建回调函数,声明跳跃结束后调用jumpEnd函数
	CCActionInterval* jumpActions=CCSequence::create(double_jump,NULL);//将回调函数与跳跃动作结合起来,这个NULL不能省 
	sprite->runAction(jumpActions);//执行动作
};   


void Player::doubleJumpEnd(){//主角已经完成二段跳跃了  
	isDoubleJumping=false;//标志主角为没有二段跳跃状态
}  

最后是整个程序的核心、入口,主函数类MainScene,

1、首先因为用到了音乐资源,所以先给这个类如同《【Cocos2dx】资源文件夹,播放背景音乐,导入外部库》(点击打开链接)一样,引入cocos2dx的音频引擎,否则SimpleAudioEngine.h会被说是找不到这个类,编译错误

2、Cocos2dx中文的使用请看《【Cocos2dx】中文乱码问题》(点击打开链接

3、滚动背景的实现请看《【Cocos2dx】连续滚动的场景》(点击打开链接

4、血条的使用请看《【Cocos2dx】利用音量螺旋控件控制血量条》(点击打开链接

5、按钮的使用请看《【Cocos2dx】使用CCControlButton创建按钮、按钮点击事件,点击事件中的组件获取,setPosition的坐标问题》(点击打开链接

6、关于两只精灵如何的碰撞检测的,请看《【Cocos2dx】飘字特效与碰撞检测》(点击打开链接

7、暂停游戏、退出游戏等请看《【Cocos2dx】利用导演类、场景类完成重新开始游戏、暂停游戏、关闭游戏功能》(点击打开链接

8、关键在与箭矢的产生、也就是怪物的产生,大家可以看到上面介绍过的怪物类,通过主场景类中的init的new方法,执行怪物的构造函数,怪物将产生如下图的在右上角的区域,区域的控制,核心在设置了一个固定位置再加上一个随机数。


之后,我们将这一个一个类的指针压入一个类指针数组,在Java就是将类压入一个ArrayList,在这C++中可以清晰地看到实质是在操作类的指针。

当然这扯远了,回到正题,主场景类中的update即时更新函数,这个类指针数组被不停地遍历,被不停地操作。不停地判断箭矢,是否碰到玩家、是否已经飞出屏幕,对碰到玩家、飞出屏幕的箭矢,重新将其位置搞出其原来产生的地方,同时记得更改其出现标识与显示与否。

触摸事件只放一个Player类的jump函数就可以了,当用户触摸屏幕之时,则不停地执行jump(),但是,我们已经在Player实现了封装,判断好此时主角是处于什么状态,该怎么操作了。

具体见下面的代码的注释,欢迎交流。

MainScene.h:

#include "cocos2d.h"
#include "Player.h"
#include "Monster.h"
#include "cocos-ext.h"//血条
#include "SimpleAudioEngine.h"//BGM

#include "PauseScene.h"

USING_NS_CC; //用到了CCxx,比如CCNode
using namespace cocos2d::extension;//血条

#define MAX_MONSTER_NUM 2//怪物最大数量

class MainScene:public cocos2d::CCLayer
{
public:
	/*场景创建必须的函数*/
	static cocos2d::CCScene* scene();
	CREATE_FUNC(MainScene);	
	virtual bool init();//场景初始化函数
	virtual void update(float delta);//即使更新事件
private:
	CCLabelTTF* label_upper_left;//左上角文字
	CCLabelTTF* label_upper_right;//右上角文字	
	void ccTouchesBegan(CCSet *pTouches,CCEvent *pEvent);//触摸事件的函数声明,开始触摸屏幕的瞬间则触发此事件  
	Player* player;//主角类
	Monster* monster;//怪物类
	CCControlSlider *controlSlider;//血条
	//添加两个背景精灵,作为背景用,实质上就是同一张图片放上二个不同的背景精灵
	CCSprite* bgSprite1;  
	CCSprite* bgSprite2;

	Monster* monster_arr[10];//存放怪物的数组

	void close(CCObject* pSender,CCControlEvent event);//关闭  
	void pause(CCObject* pSender,CCControlEvent event);//暂停
};

MainScene.cpp:
#include "MainScene.h"

CCScene* MainScene::scene()//必须存在的场景建立函数
{
	CCScene *scene = CCScene::create();
	MainScene *layer = MainScene::create();
	scene->addChild(layer);
	return scene;
}

/*初始化*/
bool MainScene::init(){

	CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();//获取屏幕的尺寸、位置信息等

	/*BGM*/
	CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic("Kalimba.mp3",true);//播放音乐,BGM是Kalimba.mp3这首难听的歌,而且是洗脑循环

	/*事件声明*/
	this->setTouchEnabled(true);//声明这个场景是存在触摸事件的
	this->scheduleUpdate();//声明这个场景是存在即使更新事件的

	/*通过载入strings.xml的中文,防止乱码*/
	CCDictionary *strings = CCDictionary::createWithContentsOfFile("strings.xml");//利用CCDictionary来读取xml,载入资源文件夹的strings.xml
	const char *xueliang = ((CCString*)strings->objectForKey("xueliang"))->m_sString.c_str();//读取xueliang键中的值,objectForKey会根据key,获取对应的string
	const char *fenshu = ((CCString*)strings->objectForKey("fenshu"))->m_sString.c_str();//读取fenshu键中的值,objectForKey会根据key,获取对应的string
	const char *zanting = ((CCString*)strings->objectForKey("zanting"))->m_sString.c_str();//读取zanting键中的值,objectForKey会根据key,获取对应的string
	const char *tuichu = ((CCString*)strings->objectForKey("tuichu"))->m_sString.c_str();//读取tuichu键中的值,objectForKey会根据key,获取对应的string

	/*背景*/
	bgSprite1=CCSprite::create("background.png");  
	bgSprite1->setPosition(ccp(visibleSize.width/2,visibleSize.height/2));
	this->addChild(bgSprite1,0);//将此控件添加到场景,层次为0,最底部 

	bgSprite2=CCSprite::create("background.png");  
	bgSprite2->setPosition(ccp(visibleSize.width+visibleSize.width/2,visibleSize.height/2));
	this->addChild(bgSprite2,0);//将此控件添加到场景,层次为0,最底部

	/*文字声明*/
	label_upper_left=CCLabelTTF::create(CCString::createWithFormat("%s%d",xueliang,1000)->getCString(),36);
	label_upper_left->setAnchorPoint(ccp(0,1));//设置label的中心点在左上角
	label_upper_left->setPosition(ccp(0,visibleSize.height));//把中心点摆在屏幕的左上角
	label_upper_left->setColor(ccc3(0,0));
	this->addChild(label_upper_left,1);//添加文字到场景中,层次为1

	label_upper_right=CCLabelTTF::create(CCString::createWithFormat("%s%d",fenshu,0)->getCString(),36);
	label_upper_right->setAnchorPoint(ccp(1,1));//设置label的中心点在左下角
	label_upper_right->setPosition(ccp(visibleSize.width,visibleSize.height));//把中心点摆在屏幕的左下角
	label_upper_right->setColor(ccc3(0,0));
	this->addChild(label_upper_right,1);//添加文字到场景中,层次为1

	/*血条声明*/
	controlSlider = CCControlSlider::create("kuang.png","hp_full.png","1.png");//第1个参数是血条没有被占据的部分的背景图片,第2是血条被占据的部分的背景图片,第3个参数是条件按钮。  
	controlSlider->setAnchorPoint(ccp(0.5,1));//设置controlSlider的中心点在中上部
	controlSlider->setPosition(ccp(visibleSize.width/2,visibleSize.height));//将此组件布置在中上部
	//设置按钮最大、最小值的基准
	controlSlider->setMinimumValue(0);  
	controlSlider->setMaximumValue(1000);
	controlSlider->setValue(1000);//设置按钮当前值  
	controlSlider->setTouchEnabled(false);//本来CCControlSlider是供用户调节的,调节按钮是1.png,但是1.png是一张1x1的近乎看不到的图片,同时利用setTouchEnabled(false)将此按钮锁上,禁止用户调节  
	this->addChild(controlSlider,1);//将此控件添加到场景,层次为1

	/*右下角按钮*/  
	CCScale9Sprite *btn_noraml3 = CCScale9Sprite::create("kuang.png");//声明按钮没被按下时的背景图片    
	CCLabelTTF *label3 = CCLabelTTF::create(CCString::createWithFormat("%s",tuichu)->getCString(),36);//第1个参数是按钮的内容,第2个参数是字体,仅能使用Resource文件夹中fonts文件夹中的字体,第3个参数是字体大小    
	label3->setColor(ccc3(0,0));
	CCControlButton *controlButton3 = CCControlButton::create(label3,btn_noraml3);    
	controlButton3->setAnchorPoint(ccp(1,0));  
	controlButton3->setPosition(ccp(visibleSize.width,0));  
	controlButton3->addTargetWithActionForControlEvents(this,cccontrol_selector(MainScene::close),CCControlEventTouchDown);//声明按钮的事件,第三个参数为定值常量意为,点击此按钮之后,触发第二个函数所声明的,下面给出的MainScene::close(){}中所有代码。    
	this->addChild(controlButton3);//将此按钮添加到场景,默认不自动添加   


	/*左下角按钮*/  
	CCScale9Sprite *btn_noraml2 = CCScale9Sprite::create("kuang.png");//声明CloseNormal图片,用于按钮没被按下时的背景图片    
	CCLabelTTF *label2 = CCLabelTTF::create(CCString::createWithFormat("%s",zanting)->getCString(),36);//声明一个文字Refresh!第2个参数是字体,仅能使用Resource文件夹中fonts文件夹中的字体,第3个参数是字体大小    
	label2->setColor(ccc3(0,0));
	CCControlButton *controlButton2 = CCControlButton::create(label2,btn_noraml2);    	
	controlButton2->setAnchorPoint(ccp(0,0));  
	controlButton2->setPosition(ccp(0,0));  
	controlButton2->addTargetWithActionForControlEvents(this,cccontrol_selector(MainScene::pause),CCControlEventTouchDown);//声明按钮的事件,第三个参数为定值常量意为,点击此按钮之后,触发第二个函数所声明的,下面给出的HelloWorld::restart(){}中所有代码。    
	this->addChild(controlButton2);//将此按钮添加到场景,默认不自动添加    

	/*精灵声明*/
	player=new Player();//创建一个主角
	this->addChild(player,2);//将主角注册到这个场景中,层次为2

	/*怪物的产生*/
	for(int i=0;i<MAX_MONSTER_NUM;i++){
		monster=new Monster();	
		this->addChild(monster,2);//将此控件添加到场景,层次为2
		monster_arr[i]=monster;//保存怪物对象到类指针中,给即时更新事件update中处理。
	}
	return true;
}

/*碰撞检测,判断两只精灵是否相交的函数*/
bool is_collision(CCSprite* sprite1,CCSprite* sprite2){  

	//建立精灵1的矩形  
	CCSize sprite_size1=sprite1->getContentSize();//求精灵的尺寸  
	CCPoint sprite_position1=sprite1->getPosition();//求精灵的中心点坐标  
	CCRect sprite_rect1=CCRectMake(//以精灵的中心点为中心点、以精灵的尺寸为宽与高,建立一个矩形。  
		sprite_position1.x-sprite_size1.width/2,sprite_position1.y-sprite_size1.height/2,sprite_size1.width,sprite_size1.height);  
	//建立精灵2的矩形,同理  
	CCSize sprite_size2=sprite2->getContentSize();  
	CCPoint sprite_position2=sprite2->getPosition();  
	CCRect sprite_rect2=CCRectMake(  
		sprite_position2.x-sprite_size2.width / 2,sprite_position2.y-sprite_size2.height / 2,sprite_size2.width,sprite_size2.height);
	return sprite_rect1.intersectsRect(sprite_rect2);//如果是判断矩形与一个像素点则用Rect实例.containsPoint(像素点);这里是判断两个矩形是否相交  


}

/*触摸屏幕*/
void MainScene::ccTouchesBegan(cocos2d::CCSet *pTouches,cocos2d::CCEvent *pEvent){
	player->jump();//主角跳跃
}

/*即时更新事件*/
void MainScene::update(float delta){
	CCSize visibleSize = CCDirector::sharedDirector()->getVisibleSize();//获取屏幕的尺寸、位置信息等
	/*背景连续滚动*/
	int posX1=bgSprite1->getPositionX();//背景地图1的x坐标  
	int posX2=bgSprite2->getPositionX();//背景地图2的x坐标  

	int iSpeed=1;//地图滚动速度  

	//两张地图向左滚动,因为两张地图是相邻的,所以要一起滚动,否则会出现空隙。  
	posX1-=iSpeed;  
	posX2-=iSpeed; 

	CCSize mapSize=bgSprite1->getContentSize();//地图大小  

	//当第1个地图完全离开屏幕时,让第2个地图完全出现在屏幕上,同时让第1个地图紧贴在第2个地图后面  
	if(posX1<-mapSize.width/2){  
		posX2=mapSize.width/2;  
		posX1=mapSize.width+mapSize.width/2;  
	}  
	//同理,当第2个地图完全离开屏幕时,让第1个地图完全出现在屏幕上,同时让第2个地图紧贴在第1个地图后面  
	if(posX2<-mapSize.width/2){  
		posX1=mapSize.width/2;  
		posX2=mapSize.width+mapSize.width/2;  
	}  

	bgSprite1->setPositionX(posX1);  
	bgSprite2->setPositionX(posX2);

	/*通过载入strings.xml的中文,防止乱码*/
	CCDictionary *strings = CCDictionary::createWithContentsOfFile("strings.xml");//利用CCDictionary来读取xml,载入资源文件夹的strings.xml
	const char *xueliang = ((CCString*)strings->objectForKey("xueliang"))->m_sString.c_str();//读取xueliang键中的值,objectForKey会根据key,获取对应的string
	const char *fenshu = ((CCString*)strings->objectForKey("fenshu"))->m_sString.c_str();//读取fenshu键中的值,objectForKey会根据key,获取对应的string

	player->score+=0.2;//不断给玩家加分
	label_upper_right->setString(CCString::createWithFormat("%s%.0f",player->score)->getCString());//改变右上角的标签文本


	for(int i=0;i<MAX_MONSTER_NUM;i++){//时刻遍历怪物的类指针数组
		monster=monster_arr[i];
		if(monster->isEmerge) {//如果怪物处于屏幕内	
			monster->sprite->setPosition(ccp(monster->sprite->getPositionX()-visibleSize.width/100,monster->sprite->getPositionY()-visibleSize.height/100));//那么他们的位置将会移动当前屏幕宽度与高度的1/100
			if(monster->sprite->getPositionX()<0|| monster->sprite->getPositionY()<0){//如果怪物x坐标小于0,则表示已经超出屏幕范围,隐藏怪物
				monster->sprite->setVisible(false);//将其隐藏
				monster->isEmerge=false;//设置为不在屏幕内
			}
			if (is_collision(player->sprite,monster->sprite)){//判断怪物是否碰撞玩家
				monster->sprite->setVisible(false);//将其隐藏
				player->hit();//玩家执行被撞击函数
				monster->isEmerge=false;//设置为不在屏幕内		
				controlSlider->setValue(player->hp);//改变中上部血条当前的值
				label_upper_left->setString(CCString::createWithFormat("%s%d",player->hp)->getCString());//左上角的文字
				if(player->hp<1){//如果玩家被扣到0
					CCDirector::sharedDirector()->replaceScene(MainScene::scene());//游戏重新开始
				}
			}			
		}
		else {			
			monster->sprite->setPosition(ccp(5*visibleSize.width/6+CCRANDOM_0_1()*visibleSize.width/6,5*visibleSize.height/6+CCRANDOM_0_1()*visibleSize.height/6));//在屏幕的右上方区域产生箭矢
			monster->sprite->setVisible(true);
			monster->isEmerge=true;			
		}
	}
}

void MainScene::close(CCObject* pSender,CCControlEvent event)    
{  
	//结束当前游戏  
	CCDirector::sharedDirector()->end();   
	exit(0);    
}

void MainScene::pause(CCObject* pSender,CCControlEvent event)    
{  
	//将游戏界面暂停,压入场景堆栈。并切换到GamePause界面  
	CCDirector::sharedDirector()->pushScene(PauseScene::scene());  
}  

总体来说吧,这个游戏的逻辑并不是复杂,但是将Cocos2dx所有的基本知识一次性地运用起来了。

而且在C++中,尤其是这些多个类配合一起来工作的时候,一定要时刻注意你是在操作哪个指针,不要出现指针的重复声明,导致编译没错,程序打死都运行都不起来。

原文链接:https://www.f2er.com/cocos2dx/340964.html

猜你在找的Cocos2d-x相关文章