【Cocos2dx】跑酷游戏

【Cocos2dx】跑酷游戏,第1张

概述下面将用Cocos2dx完成一个跑酷游戏,跑酷游戏从头到尾包括美工完全可以一个人完成,就是比较耗费时间,只能达到能玩的程度而已。 做出来的跑酷游戏如下所示: 玩家能做的就只有一个动作,触摸屏幕,触摸屏幕之后,游戏的主角,就是黑色的方块,能够向上跳跃,再次触摸就能够二段跳, 而在屏幕右上方则有不停发射的箭矢,玩家控制的黑色方块被射中,则会掉10滴血,从1000血可以扣,扣到0则游戏自动重新开始。在屏

下面将用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,比如CCNodeclass Monster:public CCNode{//由于用到了this->addChild(sprite);必须继承CCNodepublic:	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,比如CCNodeclass Player:public CCNode{//由于用到了this->addChild(sprite);必须继承CCNodepublic:	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,比如CCNodeusing 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++中,尤其是这些多个类配合一起来工作的时候,一定要时刻注意你是在 *** 作哪个指针,不要出现指针的重复声明,导致编译没错,程序打死都运行都不起来。

总结

以上是内存溢出为你收集整理的【Cocos2dx】跑酷游戏全部内容,希望文章能够帮你解决【Cocos2dx】跑酷游戏所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/web/1073612.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2022-05-26
下一篇2022-05-26

发表评论

登录后才能评论

评论列表(0条)

    保存