SKSceneのpausedを勝手に変更されないようにする
一番ハードルが高かったのはリリースですね、本当に。。。
前回は、現象を再現したので、次は対策を打っていきたいと思います。
とりあえず、SKView
のpaused
が変更されるのは良しとします。
ただし、その下にぶら下がってるSKScene
はダメです。
なので、例のコードをSKScene
を継承したクラスに追加します。
// // FOOHogeScene.h // @property (nonatomic, assign) BOOL stayPaused; // <-- 追加 // // FOOHogeScene.m // // 初期化時に追加 self.stayPaused = NO; // 適当なところに追加 -(void)setPaused:(BOOL)newValue { if ( _stayPaused && !newValue ) { // ユーザーの操作ではないと判断して、Pauseを解除しない //NSLog( @"LCWGameScene setPaused rejected! newValue: %d", newValue ); } else { //NSLog( @"LCWGameScene setPaused newValue: %d", newValue ); super.paused = newValue; } } // 外からポーズにする関数の例 -(void)pause { if ( self.paused ) { return; } self.paused = YES; self.stayPaused = YES; [self addCoverSprite]; [self addChild:_resumuHintLabel]; } // 外からポーズを解除する関数の例 -(void)resume { self.stayPaused = NO; _resumeRequest = YES; _resumeDelayTime = .5f; _pauseButton.alpha = .3f; // 押せないので無効っぽい色に設定 [_resumuHintLabel removeFromParent]; [self removeCoverSprite]; }
もう少し補足しますね。
基本的に、SKView
のpaused
が勝手に変わっても、
大抵の場合は問題ないかと思います。
ですが、今回のケースでは、
プレイ中にホームボタンが押された場合は、
SKScene
で管理していないBGMの停止を行ったり、
再度、アプリが選択された場合は、
PAUSEボタンをタップするように促した状態を維持する必要があります。
要は、この手(シューティング)のゲームで勝手に再開されたら困る訳です。
なので、SKView
からSKScene
に対して、
pause/resumeを呼んで、停止と再開を実装するようにしました。(*1)
最後に、pause/resumeについて。
1. pause
PAUSEボタンがすでに押されて、ポーズに入っているケースを想定して、
すでにポーズに入っていないかチェックしています。
現在表示されているスプライトを少し薄く表示するために、
SKScene
を覆うようなスプライトを用意して追加しています。
-(void)addCoverSprite { UIColor *color = [self.backgroundColor copy]; SKSpriteNode *sprite = [SKSpriteNode spriteNodeWithColor:color size:self.size]; sprite.alpha = .3f; sprite.anchorPoint = CGPointZero; sprite.position = CGPointZero; sprite.name = kCoverSpriteName; sprite.zPosition = 2.0f; // 敵機のミサイルがカバーの上にくるのを防ぐ [self addChild:sprite]; }
あとで取り除くのに、name
を設定しているのもポイントです。
PAUSEを解除するボタンは、カバーの下になって薄くならないように、
zPosition
の値をカバーより少し大きな値を設定しています。
_resumuHintLabel
のzPosition
も同様です。
ちなみに、_resumuHintLabel
は、
「再開するにはPAUSEボタンをタップしてください」といった感じの内容になっています。
2. resume
再開時は、すぐにpaused
を変更しないで、若干の間を置いてから実行しています。
そのためのフラグであったり、どの程度時間を置くかだけ設定しています。
それと、先ほど追加したカバーを削除したり、ラベルの削除も行ってします。
-(void)removeCoverSprite { SKNode *node = [self childNodeWithName:kCoverSpriteName]; if ( node ) { [node removeFromParent]; } }
まとめ
変更した行数は少なかったですが、
SKView
が変更されると、そこにぶら下がってるSKScene
も変更されるのは、
今思うと当然といえば当然ですが、このおかげで変更点は少なくて済みました。
iOSのバージョンを見て切り替えるような方法もあるかもですが、
その手のコードを入れるのは後々面倒を招くので避けた次第です。
あとは、審査が通ることを祈るだけですね!
おしまい。
(*1) この方法が最善かは別(なんせ処女作ですから)
Leave a Comment