プレイしたゲームに於いてハイスコアを獲得したか否かに応じて ゲームオーバー画面に表示するアニメーションを変更しようとゲーム起動時 AppDelegate.mに生成した可変辞書 toyBox を以てハイスコアフラグをゲームオーバー画面に渡して分岐条件とすべく実装したのが前回の記事 ハイスコアに準じてUIViewぱらぱらアニメを変更する だったのですが分岐表示には成功したものの問題も発生してしまいました。 ゲームを繰り返す内にアニメーションが重複して描画されてしまうのです。 本稿では此の問題を解決した記事としてものします。
手元の開発ゲームでは リプレイ 機能をもたせていますが此れがトラブルの引き金となりました。 ほんの僅かでも機能追加すればバグの元となるとのセオリーを地で行き 端なくも其の証左となりました。 しかしリプレイ機能は出来得るならば保たせたい機能ではありますので何とか解決を図った次第。
開発機:MacBook Air(11-inch, Mid 2013)
MacOSバージョン:OS X 10.9.2
Xcodeバージョン:5.1
言語:Objective-C
主関連アプリ:uPanda Breaks Out Fruits
手元の開発ゲームではゲームオーバー画面にリプレイボタンを表示しており 此れをタップした際に再度SpriteKitを用いたプレイシーンを読み込ませるように仕組んであります。 ゲーム画面に於いては土台のゲーム画面用ViewControllerが ゲームの情報を表示するUIViewと SpriteKitを用いたゲーム専用画面のSKSceneを読み込んでいます。 ゲームオーバーとなったタイミングでプレイシーンは破棄され 元々表示されていたUIViewが表に現れると言った塩梅です。 此のUIViewにプレイシーンから受け取ったハイスコア判定値を受け取って 表示されるアニメーションが分岐するのです。 此の仕組みに於いては一度目は問題ないのですが 二度目のゲームオーバー時にアニメーションが重複して表示されてしまいます。 一度目に描画されたアニメーションがリプレイ画面の水面下で動き続けており 二度目のゲームオーバー時にプレイシーンが破棄されると 二度目で指定された表示されたアニメーションの下に見えてしまって重複表示の状態を招いてしまったいたのでした。
問題はプレイシーンを搭載するサブビューのクラスを何処で何度呼び出しているかにあります。 -(void)didMoveToSuperview メソッドは ViewController 上で PlayUIView.m が呼ばれた時にシーンを1回だけ呼ぶ具合のメソッドであり 従って PlayUIView.m の subview の PlayScene.m をリプレイで何度呼んでも此処の処理は最初の処理したものから金輪際変わらない筈です。
一方 -(void)willRemoveSubview:(UIView *)subview メソッドは PlayUIView.m が subview を自ら加える度に呼び出されるため BOPlayUIView.m の subview の PlayScene.m をリプレイの度に呼ぶ処か 別の subview を add した時さえ呼ばれてしまうので一度のリプレイで何度も呼び出されるメソッドです。
さて以下に今回惹起された問題を列挙しましょう。 此れ等を鑑みて如何に処方すべきか考えます。
上記列挙の3問題を解決する為に最初に -(void)didMoveToSuperview メソッドでアニメを生成し其の際にノードにtag付けをしてユニーク判断を可能にしておいて -(void)willRemoveSubview:(UIView *)subview メソッドが呼ばれる度にハイスコアフラグを呼び出し tag付けされたアニメを差し替える方法で実装し 漸く目論見に沿う動きが得られたのでした。 ラフなコーディングでリファクタリングが必要なものの其の際のコードが以下となります。
/* ハイスコア・フラグ */
BOAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
highScoreFlag = [appDelegate.toyBox objectForKey:@"hs_flag"];
if ([highScoreFlag isEqualToString:@"1"]) {
/* ハイスコアボードを掲げてハイスコアダンスを踊るウパンダアニメ */
// アニメーション用イメージビューの用意
CGRect highScoreUpandaRect = CGRectMake(110, 330, 105, 120);
upandaAnime = [[UIImageView alloc]initWithFrame:highScoreUpandaRect];
upandaAnime.image = [UIImage imageNamed:@"hiscore_dance-1.png"];
upandaAnime.tag = 5;
// [self addSubview:upandaAnime];
upandaAnime = (UIImageView *)[self viewWithTag:5];
// アニメーション用画像を配列にセット
NSMutableArray *highScoreUpandaImageList = [NSMutableArray array];
for (NSInteger i = 1; i <= 6; i++) {
NSString *highScoreUpandaImagePath = [NSString stringWithFormat:@"hiscore_dance-%d.png", i];
UIImage *highScoreUpandaImg = [UIImage imageNamed:highScoreUpandaImagePath];
[highScoreUpandaImageList addObject:highScoreUpandaImg];
}
// アニメーション用画像をセット
upandaAnime.animationImages = highScoreUpandaImageList;
// アニメーションの速度
upandaAnime.animationDuration = 1.5;
// アニメーションのリピート回数
upandaAnime.animationRepeatCount = 0;
// アニメーションのスタート
[upandaAnime startAnimating];
} else {
NSLog(@"HS FLAG FALSE:%@",highScoreFlag);
/* 目の回ったウパンダアニメ */
// アニメーション用イメージビューの用意
CGRect dizzyUpandaRect = CGRectMake(110, 330, 105, 120);
upandaAnime = [[UIImageView alloc]initWithFrame:dizzyUpandaRect];
upandaAnime.image = [UIImage imageNamed:@"dizzy-1.png"];
upandaAnime.tag = 5;
// [self addSubview:upandaAnime];
upandaAnime = (UIImageView *)[self viewWithTag:5];
// アニメーション用画像を配列にセット
NSMutableArray *dizzyUpandaImageList = [NSMutableArray array];
for (NSInteger i = 1; i <= 8; i++) {
NSString *dizzyUpandaImagePath = [NSString stringWithFormat:@"dizzy-%d.png", i];
UIImage *dizzyUpandaImg = [UIImage imageNamed:dizzyUpandaImagePath];
[dizzyUpandaImageList addObject:dizzyUpandaImg];
}
// アニメーション用画像をセット
upandaAnime.animationImages = dizzyUpandaImageList;
// アニメーションの速度
upandaAnime.animationDuration = 2.0;
// アニメーションのリピート回数
upandaAnime.animationRepeatCount = 0;
// アニメーションのスタート
[upandaAnime startAnimating];
}
上記コードに於いてのポイントは赤字で記した描画時の命令 [self addSubview:upandaAnime]; を以下で差し替えの緑色の命令に書き換えている部分となるでしょう。 upandaAnime = (UIImageView *)[self viewWithTag:5];
追記
(2016年7月22日)
以上のコードの冗長部分を除くべく
ゲームオーバー画面重複アニメ問題解決コードのリファクタリング
として記事を配信しました。
バージョン: 4.12
リリース: 2014年9月15日
更新: 2022年4月20日
サイズ : 10.7 MB
互換性: iOS 14.4 以降のiPhone、iPod touch に対応。および、macOS 11.0以降とApple M1 チップを搭載したMac に対応。
1件のコメント
コメントは受け付けていません。