ゲームの演出
Core Animationを使ったエフェクトクラス
次にCore Animationを使ったエフェクトを追加して行ってみよう。まずはウサギがオオカミに攻撃された時のマークを付けてみる。第5回で紹介したようなマークをあらかじめKeynoteで作っておこう。これをウサギのダメージアニメーション開始時に表示する。
図2:ウサギ攻撃されるエフェクト |
エフェクトのための新しいクラスを追加しよう。以下がそのインターフェースだ。このオブジェクトはキャラクターのサブビューとして設定して使う。
@interface EffectView : UIView { BOOL isLoop; BOOL isFinishDelete; BOOL isOpacity; BOOL isPosition; BOOL isBounds; } @property (nonatomic, assign) BOOL isLoop; @property (nonatomic, assign) BOOL isFinishDelete; - (id)initWith:(UIImage*)image; - (void)setAnimePosition:(CGPoint)toPoint Duration:(CGFloat)dur; - (void)setAnimeOpacityFrom:(CGFloat)opa1 To:(CGFloat)opa2 Duration:(CGFloat)dur; - (void)setAnimeBoundsScaleFrom:(CGFloat)scl1 To:(CGFloat)scl2 Duration:(CGFloat)dur; @end
クラスには初期化メソッドとこのビュー自身をCore Animationを使ってアニメーションさせるためのメソッドが3つある。それぞれ位置、透明度、サイズをアニメーションさせるメソッドだ。以下が初期化メソッドになる。
- (id)initWith:(UIImage*)image { CGRect rect = CGRectMake(0, 0, image.size.width, image.size.height); if (self = [super initWithFrame:rect]) { self.layer.contents = (id)image.CGImage; isLoop = NO; isFinishDelete = YES; } return self; }
引数として渡されたUIImageをレイヤーのコンテンツとして設定し、削除のためのフラグisFinishDeleteを立てる、isFinishDeleteが YES の場合、アニメーションが終了したら自分自身を削除する。isLoopが NO ならループ再生する。
以下が透明値をアニメーションさせるメソッドだ。引数に開始値と終わり値、アニメーションの時間を渡す。他の2つもアニメーションさせるプロパティーが違うだけでやっていることは同じだ。
//透明度のアニメーション - (void)setAnimeOpacityFrom:(CGFloat)opa1 To:(CGFloat)opa2 Duration:(CGFloat)dur { //透明値のアニメーションを作成 CABasicAnimation* opacity = [CABasicAnimation animationWithKeyPath:@"opacity"]; //透明値の開始と終わりを設定 opacity.fromValue = [NSNumber numberWithFloat:opa1]; opacity.toValue = [NSNumber numberWithFloat:opa2]; opacity.delegate = self; //デリゲート opacity.duration = dur; //アニメーションの時間 opacity.autoreverses = isLoop; // YESならアニメーションを繰り返す if( isLoop ) opacity.repeatCount = 10000; // 繰り返し回数 // アニメーション設定 [self.layer addAnimation:opacity forKey:@"animateOpacity"]; isOpacity = YES; self.layer.opacity = opa2; }
そして、アニメーション終了時に呼ばれるデリゲートメソッドで全てのアニメーションの再生が終了し、削除のためのフラグが YES なら自分自身を親ビューから削除する。
- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag { if(isOpacity) isOpacity = NO; if(isPosition) isPosition = NO; if(isBounds) isBounds = NO; if( isOpacity==NO && isPosition==NO && isBounds==NO && isFinishDelete ) [self removeFromSuperview]; }
ダメージエフェクト
以下が実際の使用例だ。GamePieceViewの setState: で、ステータスがダメージに変わる時にEffectViewをキャラクターに設定している。エフェクト用のビューを作成した後、サイズと透明のアニメーションを0.2秒で設定している。これで「攻撃されたマーク」が0.2秒かけて1.2倍になりながら透明になって消えて行く、そして消えた後、エフェクト用のビューは自分自身を削除して解放される。
case STATE_DAMAGE: //ダメージ { efView = autorelease]; [self addSubview:efView]; efView.center = CGPointMake(24, 0); [efView setAnimeBoundsScaleFrom:1.0 To:1.2 Duration:0.2]; [efView setAnimeOpacityFrom:1.0 To:0.0 Duration:0.2]; efView=nil; ~略~ }break;
眠りエフェクト
次にキャラクターの状態変化が視覚的に分かるようなエフェクトを追加してみよう。オオカミは最初、眠った状態で配置されている。この時にマンガでよくあるような吹き出しを表示する。
図3:オオカミ眠りエフェクト |
以下がその設定部分のコードだ。ここでは efView.isFinishDelete に NO を設定しているので、アニメーション終了後も削除されること無くループ再生される。
case STATE_SLEEP: //眠り { imageIndex = MOVANGL_SLEEP; efView = ; efView.isFinishDelete = NO; [self addSubview:efView]; [efView release]; efView.center = CGPointMake(40, 0); [efView setAnimeBoundsScaleFrom:1.0 To:1.2 Duration:1.5]; }break;
「ゲームの演出」サンプルプログラム