Cocos2dx制作太空射击游戏.docx
《Cocos2dx制作太空射击游戏.docx》由会员分享,可在线阅读,更多相关《Cocos2dx制作太空射击游戏.docx(25页珍藏版)》请在冰豆网上搜索。
Cocos2dx制作太空射击游戏
Cocos2d-x制作太空射击游戏
在这篇教程里,我将向你展示如何利用HowtoMakeaSpaceShooteriPhoneGame里创建的工程制作一个太空游戏。
这里有一个主要的区别——这次是用跨平台的cocs2d-x开发。
这就意味在教程里开发的游戏可以在你的iphone和andorid上运行。
当然,再稍微做修改,你可以让它在Windows、Linux或者Mac下运行。
深吸一口气,我们就要开始啦!
GettingStarted
第一件事情就是下载并解压spacegameresourcesZIPfile。
就像我们在之前教程里面添加两个项目里都可以使用的C++类一样,我们需要以同样的方式来添加这些资源文件使ios和andriod项目都可以引用同样的资源。
我们把这些文件添加到Android工程的Resource目录下面,然后在ios项目里面引用这个目录。
为了方便添加图片和其它资源到我们的工程里,我们需要把它们添加到$PROJECT_HOME\Resources目录(请记住$PROJECT_HOME是你AndriodCocosd-Xproject-samplecocos2dxandroid的位置)。
然而,我们的Eclipse工程只会显示$PROJECT_HOME\android目录下的文件,所以这确实是一个问题!
幸运的是这里有一个简单的变通方案:
我们在$PROJECT_HOME\Resources目录下面建立一个符号链接,指向$PROJECT_HOME\android\Resources目录,这样Eclipse就可以看到它们了。
接着,打开终端,在$PROJECT_HOME\android目录下运行如下的命令:
1ln-s../Resources./Resources.
现在拷贝文件到Resources文件夹。
请注意,由于跨平台可移植性的原因,你需要避免使用层级式的子目录。
尽管子目录在iOS下运行起来很好,但是它们不一定在Android上运行地很好。
举例来说,如果你有一个Sprites.pvr.ccz文件在一个SpriteSheet子目录里,在Android里面使用CCSpriteBatchNode:
:
bathNodeWithFile方法将会调用失败并返回一个空指针。
所以,从spacegameresourcesZIPfile里面把单个的文件拷贝到Resource文件夹下去,请记得不要创建任何子目录,仅仅拷贝一个个的文件过来就可以了。
在资源文件里存在一个字体的子文件夹,从字体文件夹里把所有的文件拷贝到Resources里时,直接替换就可以了。
此外,在压缩文件里有个Classes子文件夹,你不必把它添加到Resources目录下,把它删除就行了。
接下来,让我们在iOS工程里引用这些文件,打开你的Xcode工程,创建一个新的Group叫做SharedResources。
选择新的Group,在Inspector里点击按钮选择路径,然后把你在Android工程里的资源文件夹选择上。
右键点击SharedResources组,选择添加文件,从Android文件夹里添加所有的文件。
目前,你完成所有的项目配置了!
增加一个太空飞船
让我们试试,看是否工作!
打开Classes\HelloWorldScene.h,在HelloWorld类开头加入下面代码(在已有public:
行的上面)
2private:
3cocos2d:
:
CCSpriteBatchNode*_batchNode;
4cocos2d:
:
CCSprite*_ship;
上面的代码创建了两个私有实例变量–一个是spritebatchnode,一个是太空飞船精灵
现在切换到HelloWorldScene.cpp,在init方法里,删除从注释“2.addamenuitem”到方法最后的所有代码,加入下面代码:
5_batchNode=CCSpriteBatchNode:
:
batchNodeWithFile("Sprites.pvr.ccz");
6this->addChild(_batchNode);
7CCSpriteFrameCache:
:
sharedSpriteFrameCache()->addSpriteFramesWithFile("Sprites.plist");
8_ship=CCSprite:
:
spriteWithSpriteFrameName("SpaceFlier_sm_1.png");
9CCSizewinSize=CCDirector:
:
sharedDirector()->getWinSize();
10_ship->setPosition(ccp(winSize.width*0.1,winSize.height*0.5));
11_batchNode->addChild(_ship,1);
12returntrue;
注意这些代码和你过去使用的Objective-C版的cocos2d非常类似。
API是有很多相同的地方的,仅仅是有一些和C++的语法不同。
在Android模拟器中编译运行,你应该可以看到你的船出现在屏幕上。
最妙的事情是在iOS上也能运行。
增加视差滚动
接下来,我们会加入宇宙背景,使它以视差滚动这种很酷的方式来滚动。
首先,我们不得不在所有的类名前面加上cocos2d:
:
这个名字空间,这太烦人了!
所以在HelloWorldScene.h类声明前加入下面行:
13USING_NS_CC;
接着在HelloWorld的private部分加入一些新的变量(注意我们不再需要加cocos2d前缀):
14CCParallaxNode*_backgroundNode;
15CCSprite*_spacedust1;
16CCSprite*_spacedust2;
17CCSprite*_planetsunrise;
18CCSprite*_galaxy;
19CCSprite*_spacialanomaly;
20CCSprite*_spacialanomaly2;
然后,在HelloWorldScene.cpp的init方法中,return语句前加入下面代码:
21//1)CreatetheCCParallaxNode
22_backgroundNode=CCParallaxNode:
:
node();//1
23this->addChild(_backgroundNode,-1);
24//2)Createthespriteswe'lladdtotheCCParallaxNode
25_spacedust1=CCSprite:
:
spriteWithFile("bg_front_spacedust.png");
26_spacedust2=CCSprite:
:
spriteWithFile("bg_front_spacedust.png");
27_planetsunrise=CCSprite:
:
spriteWithFile("bg_planetsunrise.png");
28_galaxy=CCSprite:
:
spriteWithFile("bg_galaxy.png");
29_spacialanomaly=CCSprite:
:
spriteWithFile("bg_spacialanomaly.png");
30_spacialanomaly2=CCSprite:
:
spriteWithFile("bg_spacialanomaly2.png");
31//3)Determinerelativemovementspeedsforspacedustandbackground
32CCPointdustSpeed=ccp(0.1,0.1);
33CCPointbgSpeed=ccp(0.05,0.05);
34//4)AddchildrentoCCParallaxNode
35_backgroundNode->addChild(_spacedust1,0,dustSpeed,ccp(0,winSize.height/2));//2
36_backgroundNode->addChild(_spacedust2,0,dustSpeed,ccp(_spacedust1->getContentSize().width,winSize.height/2));
37_backgroundNode->addChild(_galaxy,-1,bgSpeed,ccp(0,winSize.height*0.7));
38_backgroundNode->addChild(_planetsunrise,-1,bgSpeed,ccp(600,winSize.height*0));
39_backgroundNode->addChild(_spacialanomaly,-1,bgSpeed,ccp(900,winSize.height*0.3));
40_backgroundNode->addChild(_spacialanomaly2,-1,bgSpeed,ccp(1500,winSize.height*0.9));
再一次说明,这段代码和我们的《如何使用cocos2d制作一个太空射击游戏》非常类似,只是有些小的句法变化。
你可以比较一下2个教程在句法上的不同。
Android模拟器中编译运行,你应该可以看到一个宇宙场景的启动,同样的,也能在iphone上运行。
现在使背景滚动,在HelloWorldScene.h中预先声明update方法–你可以在private或public部分加入下面代码,但是既然update方法是内部使用的,所以作为一个private方法更恰当:
41//scheduledUpdate
42voidupdate(cocos2d:
:
ccTimedt);
然后在HelloWorldScene.cpp最后加入下面的方法实现
43voidHelloWorld:
:
update(ccTimedt){
44CCPointbackgroundScrollVert=ccp(-1000,0);
45_backgroundNode->setPosition(ccpAdd(_backgroundNode->getPosition(),ccpMult(backgroundScrollVert,dt)));
46}
最后,在init方法末尾(但是在最后的return语句前)调用scheduleUpdate方法
47this->scheduleUpdate();
编译运行,你将会看到背景滚动!
持续滚动
这时,你应该注意到了背景滚出屏幕后没有循环,那么我们来修这个bug
在我们的《如何使用cocos2d制作一个太空射击游戏》教程中,我们通过Objective-c的分类(category)扩展了CCParallaxNode类来实现。
不幸的是,C++中是不存在分类的,所以我们需要借助继承来实现之。
我们将去定义一个CCParallaxNode扩展类来扩展标准的CCParallaNode。
这样做虽然不如Objective-C优雅,但是有时我们需要为软件可移植性做一些牺牲。
在Xcode中,在Glassesgroup上单击右键,选择NewFile。
选择iOS\CandC++\C++文件末尾,点击Next,为他命名为CCParallaxNodeExtras.cpp,存储到$PROJECT_HOME\Classes,然后点击创建。
然后重复上述过程,但要选择iOS\CandC++\Header文件模板,来创建CCParallaxNodeExtras.h
用下面的代码替换CCParallaxNodeExtras.h中的内容
48#ifndef
49Cocos2DxFirstIosSample_CCParallaxNodeExtras_h#define
50Cocos2DxFirstIosSample_CCParallaxNodeExtras_h#include“cocos2d.h”USING_NS_CC;classCCParallaxNodeExtras:
publicCCParallaxNode
51{public:
//NeedtoprovideourownconstructorCCParallaxNodeExtras();//justtoavoiduglylatercastandalsoforsafety
52staticCCParallaxNodeExtras*node();//Facilitymethod(weexpecttohaveitsooninCOCOS2DX)voidincrementOffset(CCPoint
53offset,CCNode*node);};#endif
这里我们为CCParallaxNode添加一个新的方法(incrementOffset),我们用它来更新parallaxnode每个child的位置。
当背景移动出屏幕左端的时候我们会使用它来将背景放到屏幕的右端,来实现持续的滚动。
将下面的代码替换到CCParallaxNodeExtras.cpp
54#include"CCParallaxNodeExtras.h"
55//HacktoaccessCCPointObject(whichisnotapublicclass)
56classCCPointObject:
CCObject{
57CC_SYNTHESIZE(CCPoint,m_tRatio,Ratio)
58CC_SYNTHESIZE(CCPoint,m_tOffset,Offset)
59CC_SYNTHESIZE(CCNode*,m_pChild,Child)//weakref
60};
61//Needtoprovideourownconstructor
62CCParallaxNodeExtras:
:
CCParallaxNodeExtras(){
63CCParallaxNode:
:
CCParallaxNode();//callparentconstructor
64}
65CCParallaxNodeExtras*CCParallaxNodeExtras:
:
node(){
66returnnewCCParallaxNodeExtras();
67}
68voidCCParallaxNodeExtras:
:
incrementOffset(CCPointoffset,CCNode*node){
69for(unsignedinti=0;inum;i++){
70CCPointObject*point=(CCPointObject*)m_pParallaxArray->arr[i];
71CCNode*curNode=point->getChild();
72if(curNode->isEqual(node)){
73point->setOffset(ccpAdd(point->getOffset(),offset));
74break;
75}
76}
77}
注意,很不幸的是CCPointObject在Cocos2d中并不是公共的类,所以我们需要借住一些小手段来hack。
(重定义它为我们的类,并具有相同的签名)。
虽然它能工作的很好,但是他的缺点是,如果CCPointObject改动了,你这里也要跟着改动,否则程序会崩溃。
代码的重点是incrementOffset方法,他和《如何使用cocos2d制作一个太空射击游戏》中的实现相同,只是用了不同的语言。
下一步,选择HelloWorldScene.h,在文件顶部的#include语句之后添加这些代码:
78#include"CCParallaxNodeExtras.h"
然后像下面的代码一样,将private区域中_backgroundNode定义由CCParallaNode改为CCParallaxNodeExtras
79CCParallaxNodeExtras*_backgroundNode;
然后选择HelloWorldScene.cpp用下面的代码替换掉section#1(_backgroundNode创建的地方)的第一行。
80_backgroundNode=CCParallaxNodeExtras:
:
node();
最后,添加下面的代码,到update方法的底部。
81CCArray*spaceDusts=CCArray:
:
arrayWithCapacity
(2);
82spaceDusts->addObject(_spacedust1);
83spaceDusts->addObject(_spacedust2);
84for(intii=0;iicount();ii++){
85CCSprite*spaceDust=(CCSprite*)(spaceDusts->objectAtIndex(ii));
86floatxPosition=_backgroundNode->convertToWorldSpace(spaceDust->getPosition()).x;
87floatsize=spaceDust->getContentSize().width;
88if(xPosition<-size){_backgroundNode->incrementOffset(ccp(spaceDust->getContentSize().width*2,0),spaceDust);
89}
90}
91CCArray*backGrounds=CCArray:
:
arrayWithCapacity(4);
92backGrounds->addObject(_galaxy);
93backGrounds->addObject(_planetsunrise);
94backGrounds->addObject(_spacialanomaly);
95backGrounds->addObject(_spacialanomaly2);
96for(intii=0;iicount();ii++){
97CCSprite*background=(CCSprite*)(backGrounds->objectAtIndex(ii));
98floatxPosition=_backgroundNode->convertToWorldSpace(background->getPosition()).x;
99floatsize=background->getContentSize().width;
100if(xPosition<-size){_backgroundNode->incrementOffset(ccp(2000,0),background);
101}
102}
你可以看到,NSArray的替代品是基于STL(C++标准库)实现的CCArray。
我们用可以帮我们自动释放对象的arrayWithCapacity构造函数。
注意这里同样也有一个更先进的CCMutableArray来用于存储集合元素。
最后的修改-因为你添加了新文件,你需要把它添加到android工程的Makefile来让他编译正确。
于是用Eclipse打开Classes\Android.mk然后改动行LOCAL_SRC_FILES为下面的代码。
103LOCAL_SRC_FILES:
=AppDelegate.cpp\
104HelloWorldScene.cpp\
105CCParallaxNodeExtras.cpp
编译运行,现在背景可以无限滚动了!
添加星星
添加星星是非常简单的,只是添加下面的代码到HelloWorldScene.cpp的init方法的return之前。
106HelloWorld:
:
addChild(CCParticleSystemQuad:
:
particleWithFile("Stars1.plist"));
107HelloWorld:
:
addChild(CCParticleSystemQuad:
:
particleWithFile("Stars2.plist"));
108HelloWorld:
:
addChild(CCParticleSystemQuad:
:
particleWithFile("Stars3.plist"));
编译运行,漂亮!
他已经开始看起来像一个太空游戏了。
使用加速计来移动飞船
在之前的Cocos2Dspaceshootertutorial里面,我们使用ios的加速计api来检测加速计输入。
很明显,ios下面的加速计api是不可以跨平台的,那么我们怎么办呢?
幸运的是,cocos2d-x对加速计进行了封装,我们可以不用关心具体平台api,直接使用抽象后的加速计api就可以了。
让我们看看它是怎么工作的吧。
首先,在HelloWorldScnee.H头文件里面添加一个新的私有成员变量:
109float_shipPointsPerSecY;
然后,添加一个新的public方法声明:
110virtualvoiddidAccelerate(CCAcceleration*pAccelerationValue);
然后在HelloWorldScene.cpp的init方法的return语句之前添加下列代码:
111this->setIsAccelerometerEnabled(true);
接下来,在HelloWorldScene.CPP文件底部添加下面这些新方法定义:
112voidHelloWorld:
:
didAccelerate(CCAcceleration*pAccelerationValue){
113#defineKFILTERINGFACTOR0.1
114#defineKRESTACCELX-0.6
115#defineKSHIPMAXPOINTSPERSEC(winSize.height*0.5)
116#defineKMAXDIFFX0.2
117doublerollingX;
118//Cocos2DXinvertsXandYaccelerometerdependingondeviceorientation
119//inlandscapemoderightx=-yandy=x!
!
!
(Strangeandconfusingchoice)
120pAccelerationValue->x=pAccelerationValue->y;
121rollingX=(pAccelerationValue->x*KFILTERINGFACTOR)+(rollingX*(1.0-KFILTERINGFACTOR));
122floataccelX=pAccelerationValue->x-rollingX;
123CCSizewinSize=CCDirector:
:
sharedDirector()->getWinSize();
124floataccelDiff=accelX-KRESTACCELX;
125floatac