個人的なメモ

Tomohiro Suzuki @hiro128_777 のブログです。Microsoft MVP for Developer Technologies 2017- 本ブログと所属組織の公式見解は関係ございません。

Cocos Sharp ハンズオン(2)地図のアニメーション設定

はじめに

こんにちは、@hiro128_777です。


前回は地図が表示される部分までを作成しました。今回はハンズオン用のテキスト後半部分です。ボタンをタップすると地図がアニメーションする部分を作成していきます。

この記事からご覧になった方は、前回からご覧になることをお勧めします。

hiro128.hatenablog.jp

ハンズオン続き

それではさっそく続きを始めましょう。

アニメーションを追加 : GameLayer.cs

GameLayer.csにアニメーション用のフィールドを追加します。

CCActionStateはアニメーションの動作中、終了のステータス管理、CCBlinkCCScaleByなどはアニメーションを表すオブジェクトです。

private CCActionState tokyoActionState;
private CCActionState kanagawaActionState;
private CCActionState saitamaActionState;
private CCActionState chibaActionState;
private CCActionState gunmaActionState;
private CCActionState tochigiActionState;
private CCActionState ibarakiActionState;

private CCBlink blink;
private CCScaleBy scaleLarge;
private CCEaseBackIn easedScaleLarge;
private CCRotateBy rotate;
private CCEaseBounceIn easedRotate;
private CCScaleBy scaleOrigin;

次にGameLayer.csのコンストラクタにアニメーションのインスタンスを作成するコードを追加します。

blink = new CCBlink(2, 10); 
scaleLarge = new CCScaleBy(1, 4); 
easedScaleLarge = new CCEaseBackIn(scaleLarge); 
rotate = new CCRotateBy(3, 2880); 
easedRotate = new CCEaseBounceIn(rotate); 
scaleOrigin = new CCScaleBy(1, 0.25f); 

さらにGameLayer.csに各県ごとの、アニメーションの実行可否判断用のプロパティとアニメーションの実行用のメソッドを追加します。

実行可否判断は現在実行中のアニメーションが終了するまで次のアニメーションを実行させないようにするために使用します。

public bool CanPlayAnimationTokyo
{
	get { return tokyoActionState == null ? true : tokyoActionState.IsDone; }
}

public void PlayAnimationTokyo()
{
	if (!CanPlayAnimationTokyo)
		return;

	var sequence = new CCSequence(
		new CCCallFunc(() => tokyoSprite.ZOrder = 1000),
		blink,
		easedScaleLarge,
		easedRotate,
		scaleOrigin,
		new CCCallFunc(() => tokyoSprite.ZOrder = 0)
		);
	tokyoActionState = tokyoSprite.RunAction(sequence);
}

public bool CanPlayAnimationKanagawa
{
	get { return kanagawaActionState == null ? true : kanagawaActionState.IsDone; }
}

public void PlayAnimationKanagawa()
{
	if (!CanPlayAnimationKanagawa)
		return;

	var sequence = new CCSequence(
		new CCCallFunc(() => kanagawaSprite.ZOrder = 1000),
		blink,
		easedScaleLarge,
		scaleOrigin,
		new CCCallFunc(() => kanagawaSprite.ZOrder = 0)
		);
	kanagawaActionState = kanagawaSprite.RunAction(sequence);
}

public bool CanPlayAnimationSaitama
{
	get { return saitamaActionState == null ? true : saitamaActionState.IsDone; }
}

public void PlayAnimationSaitama()
{
	if (!CanPlayAnimationSaitama)
		return;

	var sequence = new CCSequence(
		new CCCallFunc(() => saitamaSprite.ZOrder = 1000),
		blink,
		scaleLarge,
		rotate,
		scaleOrigin,
		new CCCallFunc(() => saitamaSprite.ZOrder = 0)
		);
	saitamaActionState = saitamaSprite.RunAction(sequence);
}

public bool CanPlayAnimationChiba
{
	get { return chibaActionState == null ? true : chibaActionState.IsDone; }
}

public void PlayAnimationChiba()
{
	if (!CanPlayAnimationChiba)
		return;

	var sequence = new CCSequence(
		new CCCallFunc(() => chibaSprite.ZOrder = 1000),
		easedScaleLarge,
		scaleOrigin,
		new CCCallFunc(() => chibaSprite.ZOrder = 0)
		);
	chibaActionState = chibaSprite.RunAction(sequence);
}

public bool CanPlayAnimationGunma
{
	get { return gunmaActionState == null ? true : gunmaActionState.IsDone; }
}

public void PlayAnimationGunma()
{
	if (!CanPlayAnimationGunma)
		return;

	var sequence = new CCSequence(blink);
	gunmaActionState = gunmaSprite.RunAction(sequence);
}

public bool CanPlayAnimationTochigi
{
	get { return tochigiActionState == null ? true : tochigiActionState.IsDone; }
}

public void PlayAnimationTochigi()
{
	if (!CanPlayAnimationTochigi)
		return;

	var sequence = new CCSequence(
		new CCCallFunc(() => tochigiSprite.ZOrder = 1000),
		scaleLarge,
		scaleOrigin,
		new CCCallFunc(() => tochigiSprite.ZOrder = 0)
		);
	tochigiActionState = tochigiSprite.RunAction(sequence);
}

public bool CanPlayAnimationIbaraki
{
	get { return ibarakiActionState == null ? true : ibarakiActionState.IsDone; }
}

public void PlayAnimationIbaraki()
{
	if (!CanPlayAnimationIbaraki)
		return;

	var sequence = new CCSequence(
		new CCCallFunc(() => ibarakiSprite.ZOrder = 1000),
		rotate,
		new CCCallFunc(() => ibarakiSprite.ZOrder = 0)
		);
	ibarakiActionState = ibarakiSprite.RunAction(sequence);
}


この部分もう少し詳しく解説します。

CanPlayAnimationTokyoプロパティでは、アニメーションのステータスを確認し、アニメーション実行前、または終了後であれば、実行許可を許可します。

public bool CanPlayAnimationTokyo
{
	get { return tokyoActionState == null ? true : tokyoActionState.IsDone; }
}


PlayAnimationTokyoメソッドでは、以下のような処理を行っています。


実行許可が出ていなければアニメーションを実行しません。

if (!CanPlayAnimationTokyo)
	return;

個別のアニメーションを連続実行するように組み合わせ、連続したアニメーションを構築します。

アニメーション時に最前面にないと他のスプライトの後ろに隠れたりしますので、最初に今回アニメーションするスプライトを最前面に移動させ、終了後元に戻しています。

CCSequenceはアニメーションを連続的に実行しますが、CCSpawnでは複数のアニメーションを同時実行できます。

CCEaseBackInなどを使うことによって通常はリニアなアニメーションの変化量を関数的に変化するように装飾できます。

var sequence = new CCSequence(
	new CCCallFunc(() => tokyoSprite.ZOrder = 1000),
	blink,
	easedScaleLarge,
	easedRotate,
	scaleOrigin,
	new CCCallFunc(() => tokyoSprite.ZOrder = 0)
	);

アニメーションをスプライトに紐づけて実行し、実行状況を参照できるようにします。

tokyoActionState = tokyoSprite.RunAction(sequence);

GameLayerの操作メソッドをViewModelに公開する : GameScene.cs

GameSceneGameLayerCanPlayAnimationTokyoなどのアニメーション実行メソッドをViewModelに公開するためのメソッドを追加します。

public void PlayAnimationTokyo()
{
	layer.PlayAnimationTokyo();
}

public void PlayAnimationKanagawa()
{
	layer.PlayAnimationKanagawa();
}

public void PlayAnimationSaitama()
{
	layer.PlayAnimationSaitama();
}

public void PlayAnimationChiba()
{
	layer.PlayAnimationChiba();
}

public void PlayAnimationGunma()
{
	layer.PlayAnimationGunma();
}

public void PlayAnimationTochigi()
{
	layer.PlayAnimationTochigi();
}

public void PlayAnimationIbaraki()
{
	layer.PlayAnimationIbaraki();
}

ViewModelのCommandのデリゲートを設定する : MainPageViewModel.cs

MainPageViewModelDelegateCommandGameSceneのアニメーション起動メソッドを設定します。

public DelegateCommand TokyoCommand => new DelegateCommand(() => GameScene.PlayAnimationTokyo());
public DelegateCommand KanagawaCommand => new DelegateCommand(() => GameScene.PlayAnimationKanagawa());
public DelegateCommand SaitamaCommand => new DelegateCommand(() => GameScene.PlayAnimationSaitama());
public DelegateCommand ChibaCommand => new DelegateCommand(() => GameScene.PlayAnimationChiba());
public DelegateCommand GunmaCommand => new DelegateCommand(() => GameScene.PlayAnimationGunma());
public DelegateCommand TochigiCommand => new DelegateCommand(() => GameScene.PlayAnimationTochigi());
public DelegateCommand IbarakiCommand => new DelegateCommand(() => GameScene.PlayAnimationIbaraki());

確認

以上でプログラムは完成しました!
ボタンをタップすると地図がアニメーションするか試してみましょう。


f:id:hiro128:20170704201300g:plain


いかがでしょうか!これで Cocos Sharp の基本的な使い方はバッチリです!

この後は完成したサンプルをアレンジしてみましょう!

プラクティス

  • アニメーションの種類を変更してみましょう。

CCMoveByCCMoveTo 移動
CCScaleByCCScaleTo 拡大・縮小
CCRotateByCCRotateTo 回転
CCJumpByCCJumpTo ジャンプ
CCFadeInCCFadeOutCCFadeTo フェード
CCTintByCCTintTo 色合いを変化
CCSkewByCCSkewTo ゆがませる
CCBlink 点滅させる


  • CCSequenceの代わりにCCSpawnを使ってみましょう。

 
 

  • 動きにイージングを適用してみましょう。

CCEaseInCCEaseOutCCEaseInOut
CCEaseExponentialInCCEaseExponentialOutCCEaseExponentialInOut
CCEaseSineInCCEaseSineOutCCEaseSineInOut


CCEaseElasticInCCEaseElasticOutCCEaseElasticInOut
CCEaseBounceInCCEaseBounceOutCCEaseBounceInOut
CCEaseBackInCCEaseBackOutCCEaseBackInOut