這一周接觸到Cocos2D開(kāi)發(fā),在它的官網(wǎng)上看到Ray Wenderlic寫(xiě)的關(guān)于cocos2d開(kāi)發(fā)的文章,感覺(jué)寫(xiě)的挺好,翻譯了一下。
原文鏈接地址
大家可以在上面看到作者的更多內(nèi)容
初次翻譯文章,望各位關(guān)照,想說(shuō)的話在作者的文章里邊也有表述,就直接開(kāi)始吧
游戲截圖
?
例子下載:
Cocos2DSimpleGame.zip
(776 K) 下載次數(shù):348
????? Cocos2D是iPhone開(kāi)發(fā)中一個(gè)非常有用的庫(kù),它可以讓你在創(chuàng)建自己的iPhone游戲時(shí)節(jié)省很多的時(shí)間。它具有很多的功能,比如sprite(精靈)扶持,非常酷的圖形效果,動(dòng)畫(huà)效果,物理庫(kù),音頻引擎等等。
????? 我是一個(gè)Cocos2D開(kāi)發(fā)的新手,盡管有很多有用的教程來(lái)介紹如何開(kāi)始利用Cocos2D開(kāi)發(fā),但我不能找到一個(gè)教程是我期待的那樣,它可以創(chuàng)建一個(gè)簡(jiǎn)單但功能豐富的游戲,這個(gè)游戲具有動(dòng)畫(huà),碰撞還有音頻,不需要其它更多的高級(jí)功能。我最終自己完成了一個(gè)簡(jiǎn)單的例子,并且在我自己的經(jīng)驗(yàn)下寫(xiě)了這篇教程以便于它對(duì)于其它的新手會(huì)有用。
???? 這篇教程將帶你從頭到尾的來(lái)了解用Cocos2D來(lái)創(chuàng)建一個(gè)簡(jiǎn)單的iPhone游戲的過(guò)程。你可以一步步的按教程來(lái),也可能跳過(guò)直接從文章的最后來(lái)下載例子工程。當(dāng)然,里邊會(huì)有ninjas(忍者)
。
下載與安裝Cocos2D
??? 你可以從
the Cocos2D Google Code page
下載Cocos2D,現(xiàn)在的最新版本是0.99.0-final(這也是這篇教程使用的)。?
?
??? 在你下載完代碼后,你應(yīng)該安裝有用的工程模板。打開(kāi)Terminal window(終端窗口),找到下載的Cocos2D所在的目錄,輸入下面的命令:./install_template.sh。
如果你的XCode不是安裝在默認(rèn)的目錄下面(比如說(shuō)你的機(jī)器上面可能安裝了多個(gè)版本的SDK),你可以在安裝腳本里邊手工的添加一個(gè)參數(shù)。(譯者注,我沒(méi)試過(guò),試過(guò)的大大可以給指明一下,17樓寫(xiě)明了, 謝謝17樓的提示)
Hello, Cocos2D
????? 讓我們開(kāi)始來(lái)用剛剛安裝的Cocos2D工程模板來(lái)建立并運(yùn)行一個(gè)簡(jiǎn)單的Hello World 工程。啟動(dòng)XCode ,選中 cocos2d-0.99.0 Applications模板創(chuàng)建一個(gè)新的Cocos2D工程,給工程命名為“Cocos2DSimpleGame
?
”.
?
?
繼續(xù)編譯并運(yùn)行該工程。如果一切正常,你將看到下圖:
???? Cocos2D被組織到”scenes”(場(chǎng)景)的概念中,有點(diǎn)類(lèi)似于游戲中的”levels”(等級(jí))或是”screens”(屏幕).比如你需要有一個(gè)場(chǎng)景來(lái)為游戲初始化菜單,一個(gè)場(chǎng)景為游戲的主要?jiǎng)幼鳎粋€(gè)場(chǎng)景為游戲結(jié)束。?
?
?
???? 在場(chǎng)景里邊,你要有許多的圖層(就像Photoshop里邊的一樣),圖層可能包含多個(gè)(nodes)結(jié)點(diǎn),比如sprites(精靈),labels(標(biāo)簽),menus(菜單)及其它。當(dāng)然結(jié)點(diǎn)也包含其它的結(jié)點(diǎn)(比如,一個(gè)精靈可以有一個(gè)子精靈)。
???? 在這個(gè)例子工程中,你可以看到有一個(gè)場(chǎng)景-HelloWorldScene,我們也將在它里邊開(kāi)始實(shí)現(xiàn)我們的游戲。繼續(xù)打開(kāi)源文件,你會(huì)看到在init這個(gè)方法中,它加入了一個(gè)label來(lái)在場(chǎng)景中顯示”Hello World”。我們將要放入一個(gè)精靈來(lái)代替它。
?
添加一個(gè)精靈
???? 在添加精靈之前,我們需要即將用到的圖片。你可以自己創(chuàng)建,或者是用Ray Wenderlich妻子為這個(gè)工程專(zhuān)門(mén)繪制的圖片:
a player Image
a Projectile Image
a Target Image
???? 當(dāng)你得到這些圖片后,把它們直接拖到XCode里邊的resources文件夾里邊去,一定要
選中"Copy items into destination group’s folder (if needed)”。
?
??? 既然我們已經(jīng)有了自己的圖片,我們就要找出應(yīng)該在哪來(lái)放置玩家。請(qǐng)注意,在
Cocos2D里邊屏幕的左下角是坐標(biāo)原點(diǎn)(0,0),x和y值向右上角遞增
。因?yàn)楣こ淌窃跈M向模式,這意味著右上角的坐標(biāo)值是(480, 320)。
????
還需要注意的是在默認(rèn)狀態(tài)下當(dāng)我們?yōu)橐粋€(gè)物體設(shè)置position屬性時(shí),position屬性是和我們添加的精靈的中心點(diǎn)關(guān)聯(lián)起來(lái)的。
因此如果我們想把玩家精靈放置在屏幕水平方向的左邊,垂直方向的中間:
position的X坐標(biāo),要設(shè)置成[player sprite's width]/2.
Position的Y坐標(biāo),要設(shè)置成[window height]/2
下面這張圖可以幫助我們更好的理解
???? 讓我們?cè)囈幌掳桑〈蜷_(kāi)Classes文件夾選中HelloWorldScene.m,用下面的代碼來(lái)代替init方法:
-(id) init{ if( (self=[super init] )) { CGSize winSize = [[CCDirector sharedDirector] winSize]; CCSprite *player = [CCSprite spriteWithFile:@"Player.png" rect:CGRectMake(0, 0, 27, 40)]; player.position = ccp(player.contentSize.width/2, winSize.height/2); [self addChild:player]; } return self; }
?
???? 你現(xiàn)在可以編譯并運(yùn)行這個(gè)工程,你的精靈應(yīng)該會(huì)正確顯示,
但背景默認(rèn)是黑色的
。對(duì)這個(gè)作品來(lái)說(shuō),白色背景會(huì)更好。在Cocos2D中,把一個(gè)圖層的的背景顏色更改成為一個(gè)自定義顏色的簡(jiǎn)單方法是利用
CCColoredLayer
這個(gè)類(lèi)。來(lái)嘗試一下吧。選中HelloWorldScene.h并且改變HelloWorld接口省明像下面的那樣:
@interface HelloWorld : CCColorLayer
?
?? 然后選中HelloWorldScene.m并對(duì)init方法進(jìn)行一個(gè)細(xì)微的修改來(lái)把背景色改為白色。
?
if( (self=[super initWithColor:ccc4(255,255,255,255)] ))
?
????? 繼續(xù)編譯并運(yùn)行工程,你會(huì)看到你的玩家精靈在白色的背景上。噢,我們的忍者已經(jīng)準(zhǔn)備表演了。????
移動(dòng)目標(biāo)
???? 下面我們需要在場(chǎng)景中添加一些目標(biāo)讓忍者去打擊。為了讓事情變的更有趣一些,我們要讓這些目標(biāo)移動(dòng)起來(lái)-要不然沒(méi)什么挑戰(zhàn)性。我們?cè)谏陨云聊挥疫叺牡胤絼?chuàng)建一些目標(biāo),并為它們建立動(dòng)作來(lái)讓它們向左移動(dòng)。
在init方法之前添加下面的方法:
-(void)addTarget { CCSprite *target = [CCSprite spriteWithFile:@"Target.png"rect:CGRectMak(0, 0, 27, 40)]; // Determine where to spawn the target along the Y axis CGSize winSize = [[CCDirector sharedDirector] winSize]; int minY = target.contentSize.height/2; int maxY = winSize.height - target.contentSize.height/2; int rangeY = maxY - minY; int actualY = (arc4random() % rangeY) + minY; // Create the target slightly off-screen along the right edge, // and along a random position along the Y axis as calculated above target.position = ccp(winSize.width + (target.contentSize.width/2), actualY); [self addChild:target]; // Determine speed of the target int minDuration = 2.0; int maxDuration = 4.0; int rangeDuration = maxDuration - minDuration; int actualDuration = (arc4random() % rangeDuration) + minDuration; // Create the actions id actionMove = [CCMoveTo actionWithDuration:actualDuration position:ccp(-target.contentSize.width/2, actualY)]; id actionMoveDone = [CCCallFuncN actionWithTarget:self selector:@selector(spriteMoveFinished:)]; [target runAction:[CCSequence actions:actionMove,actionMoveDone, nil]]; }
?
???? 在這里我以一種詳細(xì)的方式來(lái)闡明事情以便讓事情更容易理解。第一部分我們應(yīng)該理解目前已經(jīng)討論了:我們做一些簡(jiǎn)單的計(jì)算,以確定我們要?jiǎng)?chuàng)建對(duì)象,設(shè)置對(duì)象的位置,并把它以添加玩家精靈的相同方式添加到場(chǎng)景中去。
???? 這里邊的新元素是添加動(dòng)作。Cocos2D提供了很多非常方便內(nèi)置的行動(dòng)可以用來(lái)制作動(dòng)畫(huà)的行動(dòng),如移動(dòng),跳躍的行動(dòng),褪色的行動(dòng),動(dòng)畫(huà)動(dòng)作及更多。在這里我們?yōu)槟繕?biāo)使用了三項(xiàng)動(dòng)作。
????? ?CCMoveTo:我們使用CCMoveTo動(dòng)作來(lái)指導(dǎo)物體屏幕左邊。請(qǐng)注意,我們可以指定運(yùn)動(dòng)應(yīng)采取的持續(xù)時(shí)間,在這里,我們采用2-4秒的隨機(jī)速度。
????? ?CCCallFuncN: 該CCCallFuncN函數(shù)允許我們指定一個(gè)回調(diào)到我們的對(duì)象出現(xiàn)時(shí),執(zhí)行操作。
????? 我們正在指定一個(gè)回調(diào)稱(chēng)為"spriteMoveFinished”我們還沒(méi)有寫(xiě)呢
????? ?CCSequence: 該CCSequence動(dòng)作讓我們創(chuàng)建一系列的動(dòng)作,一次一個(gè)。這樣,我們可以先執(zhí)行CCMoveTo動(dòng)作,一旦完成執(zhí)行CCCallFuncN動(dòng)作。
??? 下面,添加前面我們已經(jīng)在CCCallFuncN動(dòng)作中已經(jīng)提過(guò)的回調(diào)函數(shù)。你可以在addTarget函數(shù)前面添加:
?
?
-(void)spriteMoveFinished:(id)sender { CCSprite *sprite = (CCSprite *)sender; [self removeChild:sprite cleanup:YES]; }
??
????? 該函數(shù)的目的是從場(chǎng)景中移除精靈,一旦該精靈離開(kāi)屏幕。這一點(diǎn)很重要,這樣我們不會(huì)隨著時(shí)間的推移,有許許多多的無(wú)用精靈在場(chǎng)景之外而內(nèi)存泄漏。請(qǐng)注意,還有其他(更好)的方式來(lái)解決這個(gè)問(wèn)題諸如具有可重復(fù)使用Sprite的數(shù)組,但這個(gè)初級(jí)教程,我們正在采取簡(jiǎn)單的方法。
????? 最后一件事情在我們運(yùn)行程序前。我們需要實(shí)際調(diào)用的方法來(lái)創(chuàng)建目標(biāo)!為了讓事情更有趣點(diǎn),我們讓目標(biāo)隨著時(shí)間的推移持續(xù)大量的出現(xiàn)。我們可以在Cocos2D中通過(guò)安排一個(gè)回調(diào)函數(shù)的定期調(diào)用來(lái)完成這個(gè)任務(wù)。每1秒執(zhí)行一次。因此,
在init函數(shù)返回之前調(diào)用下面的函數(shù)調(diào)用。
?
[self schedule:@selector(gameLogic:) interval:1.0];
?
現(xiàn)在像下面這樣簡(jiǎn)單的實(shí)現(xiàn)這個(gè)回調(diào)函數(shù):
?
-(void)gameLogic:(ccTime)dt { [self addTarget]; }
??
?
?
????? 就是這樣!所以,現(xiàn)在,如果你編譯并運(yùn)行該項(xiàng)目,現(xiàn)在你應(yīng)該看到目標(biāo)愉快地在屏幕上移動(dòng):
射擊子彈
????? 在這時(shí),忍者希望有一些動(dòng)作-讓們添加射擊吧!我們有很多的方法來(lái)實(shí)現(xiàn)射擊,但在這個(gè)游戲中我們要在用戶(hù)點(diǎn)擊屏幕時(shí)來(lái)進(jìn)行射擊,從玩家射出的子彈將按照點(diǎn)擊的方向前進(jìn)。
????? 我想用一個(gè)CCMoveTo動(dòng)作去保持事情還在初級(jí)層面上,但為了實(shí)現(xiàn)這個(gè),我們必須做一些數(shù)學(xué)。這是因?yàn)镃CMoveTo要求我們必須為子彈目的地,但我們不能只使用觸摸點(diǎn),因?yàn)榻佑|點(diǎn)僅僅代表相對(duì)于玩家的射擊方向。事實(shí)上,我們希望保持子彈通過(guò)觸摸點(diǎn),直到移出屏幕。
用一張圖來(lái)解釋這個(gè)事情:
?
因此,大家可以看到,我們利用起點(diǎn)到觸摸點(diǎn)的X和Y方向的偏移創(chuàng)造了個(gè)小三角形。我們只需要以同樣的比例大三角形 - 我們知道我們需要一個(gè)離開(kāi)屏幕的結(jié)束點(diǎn)。
?
好了,上代碼。首先,
我們必須使我們的層可以支持觸摸
。添加下面一行到您的init方法:
?
?
self.isTouchEnabled = YES;
?
????? 因?yàn)槲覀円呀?jīng)讓圖層支持觸摸,現(xiàn)在我們可以收到觸摸事件的回調(diào)。因此,讓我們實(shí)現(xiàn)
ccTouchesEnded
方法,只要用戶(hù)完成了接觸該方法就會(huì)調(diào)用,具體如下:
?
?
- (void)ccTouchesEnded:(NSSet *)touches withEvent:(UIEvent *)event { // Choose one of the touches to work with UITouch *touch = [touches anyObject]; CGPoint location = [touch locationInView:[touch view]]; location = [[CCDirector sharedDirector] convertToGL:location]; // Set up initial location of projectile CGSize winSize = [[CCDirector sharedDirector] winSize]; CCSprite *projectile = [CCSprite spriteWithFile:@"Projectile.png" rect:CGRectMake(0, 0, 20, 20)]; projectile.position = ccp(20, winSize.height/2); // Determine offset of location to projectile int offX = location.x - projectile.position.x; int offY = location.y - projectile.position.y; // Bail out if we are shooting down or backwards if (offX <= 0) return; // Ok to add now - we've double checked position [self addChild:projectile]; // Determine where we wish to shoot the projectile to int realX = winSize.width + (projectile.contentSize.width/2); float ratio = (float) offY / (float) offX; int realY = (realX * ratio) + projectile.position.y; CGPoint realDest = ccp(realX, realY); // Determine the length of how far we're shooting int offRealX = realX - projectile.position.x; int offRealY = realY - projectile.position.y; float length = sqrtf((offRealX*offRealX)+(offRealY*offRealY)); float velocity = 480/1; // 480pixels/1sec float realMoveDuration = length/velocity; // Move projectile to actual endpoint [projectile runAction:[CCSequence actions: [CCMoveTo actionWithDuration:realMoveDuration position:realDest], [CCCallFuncN actionWithTarget:self selector:@selector(spriteMoveFinished:)], nil]]; }
?
????? 在第一部分,
我們選擇一個(gè)觸摸點(diǎn)來(lái)使用,先得到在當(dāng)前視圖中的位置,然后調(diào)用convertToGL來(lái)把坐標(biāo)轉(zhuǎn)化到當(dāng)前的布局
。這點(diǎn)很重要,因?yàn)槲覀儸F(xiàn)在是橫向模式。
???? 接下來(lái)我
們加載子彈精靈并像往常一樣設(shè)置初始坐標(biāo)
。然后,我們確定我們希望子彈移動(dòng)的位置,按照前面描述的算法,使用玩家和觸摸點(diǎn)之間的聯(lián)系來(lái)作為指導(dǎo)載體。
???? 請(qǐng)注意,該算法并不理想。我們正在迫使子彈繼續(xù)前進(jìn)直到在X方向上離開(kāi)屏幕-即使首先在Y方向上已經(jīng)離開(kāi)了屏幕!有不同的方法來(lái)解決這個(gè),包括檢查離開(kāi)屏幕的最小長(zhǎng)度,讓游戲的邏輯回調(diào)核查離開(kāi)屏幕的子彈和消除回調(diào),而不是使用回調(diào)方法,等等。但這個(gè)初級(jí)教程,我們將保持原樣。
????? 我們最需要做的就是確定為運(yùn)動(dòng)時(shí)間。我們希望,子彈會(huì)于一個(gè)恒定的速率按照射擊方向前進(jìn),所以我們?cè)俅巫鲆恍?shù)學(xué)。我們可以找出利用勾股定理來(lái)算出移動(dòng)的距離。記得在幾何學(xué)里邊,這是規(guī)則,指出了一個(gè)直角三角形的斜邊長(zhǎng)度等于兩直角邊的平方的和的開(kāi)方。
???? 一旦我們有了距離,我們只是除以速度,以獲得所需的時(shí)間。這是因?yàn)樗俣?距離/時(shí)間,或換句話說(shuō) 時(shí)間=距離/速度。
??? 剩下的事情就是設(shè)置動(dòng)作,就想給目標(biāo)設(shè)置動(dòng)作一樣。編譯并運(yùn)行,現(xiàn)在你的忍者可以向前來(lái)的一大群目標(biāo)開(kāi)火了
!
碰撞檢測(cè)
???? 所以現(xiàn)在我們已經(jīng)讓shurikens滿(mǎn)天飛了-但我們的忍者真正想要做的是放倒一些目標(biāo)。因此,讓我們加入一些代碼,以檢測(cè)當(dāng)我們的子彈和目標(biāo)的相交。
???? 要做到這一點(diǎn),我們首先要在目前的場(chǎng)景中更好的跟蹤目標(biāo)和子彈。把以下的代碼添加到你的HelloWorldScene類(lèi)聲明中:
?
NSMutableArray *_targets; NSMutableArray *_projectiles;
?
在
init方法中初始化這兩個(gè)數(shù)組
:
?
?
_targets = [[NSMutableArray alloc] init]; _projectiles = [[NSMutableArray alloc] init];
?
我們也應(yīng)該考慮,
在你的dealloc方法中清理內(nèi)存
:
?
[ _targets release]; _targets = nil; [ _projectiles release]; _projectiles = nil;
?
????? 現(xiàn)在,修改你的addTarget方法,
添加新目標(biāo)到目標(biāo)數(shù)組中并給它設(shè)置一個(gè)標(biāo)記以便在以后使用:
target.tag = 1; [ _targets addObject:target];
?
????
???? 還要修改你的ccTouchesEnded方法,把新子彈添加到子彈數(shù)組中給它設(shè)置一個(gè)標(biāo)記以便在以后使用:
?
projectile.tag = 2; [_projectiles addObject:projectile];
?
???? 最后,修改你的spriteMoveFinished方法,根據(jù)標(biāo)記的不同在適當(dāng)?shù)臄?shù)組中移除精靈:?
if (sprite.tag == 1) { // target [_targets removeObject:sprite]; } else if (sprite.tag == 2) { // projectile [_projectiles removeObject:sprite]; }
?
?
?
????? 編譯并運(yùn)行該項(xiàng)目以確保一切正常。在這個(gè)時(shí)候應(yīng)該沒(méi)有什么明顯的不同,但現(xiàn)在我們有標(biāo)記,我們要實(shí)現(xiàn)碰撞檢測(cè)。
現(xiàn)在在HelloWorldScene類(lèi)中添加下面的方法:
- (void)update:(ccTime)dt { NSMutableArray *projectilesToDelete = [[NSMutableArray alloc] init]; for (CCSprite *projectile in _projectiles) { CGRect projectileRect = CGRectMake( projectile.position.x -(projectile.contentSize.width/2), projectile.position.y - (projectile.contentSize.height/2), projectile.contentSize.width, projectile.contentSize.height); NSMutableArray *targetsToDelete = [[NSMutableArray alloc] init]; for (CCSprite *target in _targets) { CGRect targetRect = CGRectMake( target.position.x -(target.contentSize.width/2), target.position.y - (target.contentSize.height/2), target.contentSize.width, target.contentSize.height); if (CGRectIntersectsRect(projectileRect, targetRect)) { [targetsToDelete addObject:target]; } } for (CCSprite *target in targetsToDelete) { [_targets removeObject:target]; [self removeChild:target cleanup:YES]; } if (targetsToDelete.count > 0) { [projectilesToDelete addObject:projectile]; } [targetsToDelete release]; } for (CCSprite *projectile in projectilesToDelete) { [_projectiles removeObject:projectile]; [self removeChild:projectile cleanup:YES]; } [projectilesToDelete release]; }
?
?
??? 以上應(yīng)該很清楚了。
我們只是通過(guò)子彈和目標(biāo)數(shù)組,按照它們的邊界框創(chuàng)建相應(yīng)的矩形,并使用CGRectIntersectsRect方法來(lái)檢查交叉
。
??? 如果發(fā)現(xiàn)有,我們從場(chǎng)景和數(shù)組中把它們移除。 請(qǐng)注意,我們是把這些對(duì)象添加到一個(gè)toDelete數(shù)組中,因?yàn)槟悴荒茉谝粋€(gè)正在迭代的數(shù)組中刪除一個(gè)對(duì)象 。同樣,有更多的最佳方法來(lái)實(shí)現(xiàn)這種事情,但我采用了這個(gè)簡(jiǎn)單的方法
????? 在你準(zhǔn)備要運(yùn)行前你只需要做一件事-通過(guò)添加下面的代碼到init方法中去安排上面的方法盡可能多的運(yùn)行
???
[self schedule:@selector(update:)];
?
讓它編譯并運(yùn)行,現(xiàn)在當(dāng)你的子彈和目標(biāo)碰撞時(shí)它們就會(huì)消失!
最后的潤(rùn)色
????? 我們非常接近擁有一個(gè)可行的(但非常簡(jiǎn)單)的游戲了。我們只需要添加一些聲音效果和音樂(lè)(因?yàn)槭裁搭?lèi)型的游戲沒(méi)有音樂(lè)的!)和一些簡(jiǎn)單的游戲邏輯。
???? 如果您一直關(guān)注我的blog series on audio programming for the iPhone
blog series on audio programming for the iPhone
,關(guān)于iPhone的一系列音頻編程博客,你會(huì)非常高興地知道,對(duì)于Cocos2D開(kāi)發(fā)者來(lái)說(shuō),在游戲中實(shí)現(xiàn)基本的聲音效果是多么的簡(jiǎn)單。
?
第一步:
????? ?拖動(dòng)一些背景音樂(lè)和一個(gè)射擊聲音效果到你的resources文件夾中。隨意使用
cool background music I made
background-music-aac.caf.zip
(252 K) 下載次數(shù):52
或是 awesome pew-pew sound effect
pew-pew-lei.caf.zip
(40 K) 下載次數(shù):42
,或者制作你自己的。
然后:
?????? 添加下面的代碼到你的HelloWorldScene.m文件的頭部:
#import "SimpleAudioEngine.h"
?
???? 在你的init方法,像下面的代碼所示啟動(dòng)背景音樂(lè):
?
[[SimpleAudioEngine sharedEngine]playBackgroundMusic:@"background-music-aac.caf"];
?
0.99-final update:(關(guān)于0.99-final更新):
??????
看起來(lái)在0.99-final版本中有一個(gè)小小的bug,背景音樂(lè)只能播放一次(而它本應(yīng)該循環(huán))-要么是它的錯(cuò)要么就是我弄錯(cuò)了。對(duì)于一個(gè)變通方法,請(qǐng)參閱本文結(jié)尾的意見(jiàn)。
關(guān)于??0.99-final版本中有一個(gè)小小的bug,
在 CDAudioManager.m 的第72行加入以下代碼,??可以解決背景音樂(lè)只能播放一次(而它本應(yīng)該循環(huán))
? - ( void ) setNumberOfLoops : ( NSInteger ) theNumberOfLoops { numberOfLoops = theNumberOfLoops; audioSourcePlayer.numberOfLoops = theNumberOfLoops; } ? |
在你的ccTouchesEnded方法中播放下面的聲音效果:
[[SimpleAudioEngine sharedEngine] playEffect:@"pew-pew-lei.caf"];
?
????? 現(xiàn)在,讓我們創(chuàng)建一個(gè)新的場(chǎng)景,將作為我們的“你贏了”,或“你輸”的指示。點(diǎn)擊Classes文件夾,進(jìn)入File\New File,并選擇Objective-C class,并確定了NSObject類(lèi)被選中。單擊Next,然后輸入GameOverScene作為文件名,并確保“Also create GameOverScene.h”被選中。
然后用下面的代碼來(lái)代替GameOverScene.h中的內(nèi)容:
#import "cocos2d.h" @interface GameOverLayer : CCColorLayer { CCLabel *_label; } @property (nonatomic, retain) CCLabel *label; @end @interface GameOverScene : CCScene { GameOverLayer *_layer; } @property (nonatomic, retain) GameOverLayer *layer; @end
?
再用下面的代碼來(lái)代替GameOverScene.m中的內(nèi)容
#import "GameOverScene.h" #import "HelloWorldScene.h" @implementation GameOverScene @synthesize layer = _layer; - (id)init { if ((self = [super init])) { self.layer = [GameOverLayer node]; [self addChild:_layer]; } return self; } - (void)dealloc { [ _layer release]; _layer = nil; [super dealloc]; } @end @implementation GameOverLayer @synthesize label = _label; -(id) init { if( (self=[super initWithColor:ccc4(255,255,255,255)] )) { CGSize winSize = [[CCDirector sharedDirector] winSize]; self.label = [CCLabel labelWithString:@"" fontName:@"Arial" fontSize:32]; _label.color = ccc3(0,0,0); _label.position = ccp(winSize.width/2, winSize.height/2); [self addChild:_label]; [self runAction:[CCSequence actions: [CCDelayTime actionWithDuration:3], [CCCallFunc actionWithTarget:self selector:@selector(gameOverDone)], nil]]; } return self; } - (void)gameOverDone { [[CCDirector sharedDirector] replaceScene:[HelloWorld scene]]; } - (void)dealloc { [_label release]; _label = nil; [super dealloc]; } @end
?
????? 請(qǐng)注意,這里有兩個(gè)不同的對(duì)象:
一個(gè)場(chǎng)景(scene)和一個(gè)圖層(layer)。
場(chǎng)景可以包含多個(gè)圖層,盡管在這個(gè)例子是它只有一個(gè)。圖層里邊只在屏幕中心放了一個(gè)標(biāo)簽,并安排了一個(gè)3秒中的過(guò)渡,然后返回到HelloWorld場(chǎng)景中。
?
????? 最后,讓我們添加一些非常基本的游戲邏輯。首先,讓我們跟蹤玩家破壞的目標(biāo)。添加一個(gè)成員變量到您的HelloWorldScene.h中 HelloWorld類(lèi)如下:
?
int _projectilesDestroyed; ?
在HelloWorldScene.m中,添加GameOverScene類(lèi)的聲明:
?
#import "GameOverScene.h"
??
???? 在update方法中removeChile:target:后面的targetsToDelete循環(huán)中增加計(jì)數(shù)并檢查獲勝條件
_projectilesDestroyed++; if (_projectilesDestroyed > 30) { GameOverScene *gameOverScene = [GameOverScene node]; [gameOverScene.layer.label setString:@"You Win!"]; [[CCDirector sharedDirector] replaceScene:gameOverScene]; }
?
?
???? 最后我們這樣來(lái)規(guī)定,即使只有一個(gè)目標(biāo)過(guò)去了,你就輸了。修改spriteMoveFinished方法,在removeChild:sprite:方法的后面的tag == 1條件里邊添加下面的代碼:
?
GameOverScene *gameOverScene = [GameOverScene node]; [gameOverScene.layer.label setString:@"You Lose :["]; [[CCDirector sharedDirector] replaceScene:gameOverScene];
?
繼續(xù)編譯并運(yùn)行該項(xiàng)目,這樣你有了羸和輸?shù)呐袛鄺l件并會(huì)在適當(dāng)?shù)臅r(shí)候看到游戲結(jié)束的場(chǎng)景。
?
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
