(NO.00004)iOS實現打磚塊遊戲(十二):伸縮自如,我是如意金箍棒(上)!
大熊貓豬·侯佩原創或翻譯作品.歡迎轉載,轉載請註明出處.
如果覺得寫的不好請告訴我,如果覺得不錯請多多支援點贊.謝謝! hopy ;)
通用的星星類已經完成了,下面我們來實現具體的變長和縮短道具.
變長的反彈棒
我們想實現如下功能:在掉落變長星之後,如果反彈棒接到它,則使反彈棒的長度變為原先的2倍.
看似很簡單,但實際有一個問題.你不能僅僅延長反彈棒精靈紋理的長度,因為你在這個遊戲中使用的是物理引擎,反彈棒的物理對象的大小是不可以在遊戲運行中隨意變化的.
所以我們需要想辦法延長反彈棒的物理大小,當然同時也要延長其精靈幀的大小,這樣才能相互配合達到逼真的延長效果.
這裡本貓使用偷梁換柱的方法,用Ai製作一個延長後的反彈棒,並調整它的物理對象適應新的長度,然後在反彈棒需要變長時,用新長棒代替原來的短棒.
首先用Ai製作一個長的反彈棒.然後在SpriteBuilder中建立一個StickLonger.ccb檔案,設定好其物理對象的邊界:
實現變長星道具
回到Xcode中,在Stick類的介面檔案中添加一個新屬性:
+(instancetype)stickLonger;
在Stick.m中實現該類方法:
+(instancetype)stickLonger{ Stick *stick = (Stick*)[CCBReader load:@Elements/StickLonger]; stick.name = @stickLonger; return stick;}
可以看到除了stick對象發生了變化,其名稱也和普通的stick有所區別.
回到GameScene.m中在小球與磚塊的碰撞處理中添加以下一句:
[Star spawnStar:(Brick*)brick];
接著我們要處理星星和反彈棒接觸時的事件:
-(BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair star:(CCNode *)star stick:(CCNode *)stick{ //star形狀是五角星,可能會在短時間內多次發生碰撞;但在star已經由第一次碰撞時刪除掉從而導致star為nil //所以這裡要確保star不為nil. //star刪除也不能保證其一定為nil,所以增加判斷其parent是否為nil.(2015-11-09 2006) StarType starType; @synchronized(self){ if (!star || !star.parent) { return YES; } starType = ((Star*)star).starType; [star removeFromParentAndCleanup:YES]; } switch (starType) { case starTypeStickLonger: @synchronized(self){ [self scheduleBlock:^(CCTimer *timer){ [Star doStickLongerWork:self.stickInGameScene]; } delay:0]; } break; case starTypeUnknown: case starTypeMax: NSAssert(NO, @error star type!); break; default: break; } return YES;}
為什麼其中使用了同步偽指令呢?因為其中的代碼會改變GameScene中反彈棒的狀態,而該狀態在GameScene中也可能同時被改變,所以我們需要將其做同步處理.
擴充Star類
最後我們在Star類中添加doStickLongerWork方法:
+(void)doStickLongerWork:(Stick *)stick{ GameScene *gameScene = [GameScene sharedGameScene]; CCPhysicsNode *physicsWorld = (CCPhysicsNode*)stick.parent; @synchronized(gameScene){ if ([stick.name isEqualToString:@stickLonger]) { return; } if ([stick.name isEqualToString:@stickShorter]) { Stick *stickNormal = [Stick stickNormal]; stickNormal.position = stick.position; [stick removeFromParent]; //[physicsWorld removeChild:stick cleanup:YES]; [physicsWorld addChild:stickNormal]; gameScene.stickInGameScene = stickNormal; return; } } CGPoint position = stick.position; __block Stick *stickLonger; @synchronized(gameScene){ stickLonger = [Stick stickLonger]; //[physicsWorld removeChild:stick cleanup:YES]; [stick removeFromParent]; stickLonger.position = position; [physicsWorld addChild:stickLonger]; stickLonger.visible = NO; gameScene.stickInGameScene = stickLonger; CCSprite *stickNode = (CCSprite*)[CCBReader load:@Elements/StickNode]; stickNode.position = stickLonger.position; [gameScene addChild:stickNode z:50]; CCActionScaleTo *longerAction = [CCActionScaleTo actionWithDuration:0.4f scaleX:2.0f scaleY:1.0f]; CCActionCallBlock *blk = [CCActionCallBlock actionWithBlock:^{ [stickNode removeFromParent]; stickLonger.visible = YES; }]; CCActionSequence *seq = [CCActionSequence actions:longerAction,blk,nil]; [stickNode runAction:seq]; } [stickLonger scheduleBlock:^(CCTimer *timer){ @synchronized(gameScene){ Stick *stickNormal = [Stick stickNormal]; stickNormal.position = stickLonger.position; [stickLonger removeFromParent]; [physicsWorld addChild:stickNormal]; gameScene.stickInGameScene = stickNormal; } } delay:10];}
你看到以上方法的第一感覺估計是:好長啊!其實內容很好理解,基本上它做了如下幾件事:
如果反彈棒已經變長了,則啥也不做返回 如果反彈棒處在變短狀態,則恢複其原本大小.這裡考慮到了其他可能改變反彈棒的疊加效果.在反彈棒變短的代碼邏輯中,我們同樣會考慮到這一點. 建立一個變長的反彈棒對象,但暫時將其隱藏,因為我們還想實現一個反彈棒由短變長的動畫效果.因為這個動畫很短,所以不會影響使用者的操控.如果你希望更完美的實現使用者操控的連續性,你可以將反彈棒的觸摸處理臨時”嫁接”到這個臨時對象上,當然是有點麻煩,篇幅原因,這裡只是點到為止. 在10秒之後將反彈棒恢複為原來大小
變長道具製作完畢,我們現在編譯運行app,看一下效果: