Edge Animateでドラクエ風バトルシーン(簡易)を作ってみる

Edge Animateの性能を見極めるため、ちょっと込み入ったものを作りたいと思い、ドラクエ風バトルシーン(簡易)を作ってみました。

※執筆時点でバージョン1.0.1でご説明します。

今回のドラクエ風バトルシーン(簡易)の要件定義

あくまでドラクエの想定でつくるので、簡易的なものにします。

そもそもEdgeはFlashのように複雑なインタラクションになってしまうと時間がかかってしまうので以下のように制限しました。

  • スマートフォンでの動作を想定する
    • Android2.3
    • Android4.0以上
    • iPhone4以上(手持ちの実機ではiPodTouch iOS5.1想定)
  • Edgeでは複雑なインタラクティブの動作はせずクリックして進む方法をとる。
    • clickのみ
    • 簡易的な連打防御も入れる
  • 外部からデータシナリオは配列でもらう。Edgeは再生するだけとする。
    • いろいろなパターンは想定せず、流し込む1パターンのみ。
    • 既にシステムでバトル結果が出ていて、生死判定・勝敗判定については内部で演出するイメージ
  • 今回はユーザー勝利の想定で作る。
    • とはいえある程度はバトルをする。

といったところで、ざっくり決めました。

できあがったもの

ということで、概ね1~2日程度で出来上がりました。リアルにガチの仕様で、例えばスキル発生・必殺技演出などが入って、分岐がくるともう少し時間がかかってくると思う。

別ページで開く 

作業メモ

  • スマートフォンでの動作
    • Android2.3、Android4.0以上、iPhone4以上(手持ちの実機ではiPodTouch iOS5.1想定)でちゃんと動いた。
  • シンボルの入れ子構造は今回最大3階層だった。問題ない。
    • FlashのMovieClipシンボル的な想定で作ったがある程度想定通り動作した
  • 再生がおかしくなるとき、アラートがFlashほど親切ではない。
    • Edge Animate単体だとよっぽど深刻なものでないとアラートは出ない
      • 再生してみて確かめるということ
    • Chromeデベロッパーツールでのコンソールでのエラーで追うのがやりやすかった
    • edge_battle_sample_edgeActions.jsで起きているケース
      • elementがうんたら、timelineがうんたら → getSymbolやエレメントがうまくたどれてないケースが多かった
      • そもその}や;などの閉じ忘れだったこともあったので、自分頑張れというところ。
    • edge.1.0.0.min.jsで起きているといわれるケース
      • こうなるとかなり追いにくいので、なるべく直前にやらかした作業を追う
    • 2~3時間組んだらだいぶ慣れてきたかんじ
  • シンボル化のタイミングはかなり重要
    • 今回のようにスクリプト組み込みが多い場合、Flashほどシンボルでまとめたり解いたり設計変更がしにくい印象。
    • 最初の設計でなるべく基本構造の設計がぶれないようにしておきたいところ。
    • 例えば、あとでウィスプをもう一段入れ子にしてフワフワさせたかったが、操作がやりにくかった。
      • FLASHのMovieClipで包んだり分解したりほどはやりやすくない
  • トリガーやエレメントに対しスクリプトを書き込めるの便利。
    • とはいえ、私はFLASHでもボタンアクション・フレームアクションでUIを行き来するのは、出来たら避けたい人なので、~_edgeActions.js直編集もいずれ極めてみたい。
  • 実制作時は、演出の分岐数は重要になってくるかも
    • 演出の入れ子がどこまで耐えられるか、というより、Flashほどオーサリングツールがこなれてないので、外部からの値による分岐があまり多くなると、いろいろ大変になるかもしれないので、やっぱり設計と要件の絞り込みは重要か。
  • 最初のフレームあたりに演出を盛り込み過ぎると負荷がかかるのか一気に進んでわかりにくい場合があるので、少し間をおいてから始めたほうがいいかんじ。

TIPS

初期化処理

FLASHで言うメインタイムラインのコンストラクタ的な処理はStageのcreationCompleteで動作させました。

// ターン数
turnNum = 0;  // 全体で使うので var しない。
// 連打防止フラグ
isAnimate = false;  // 全体で使うので var しない。
// ステータス反映
for( var i = 0 ; i < battleData.startStatus.length ; i++ ){
	var currentStatus = battleData.startStatus[ i ];
	var statusElement = sym.getSymbol("TopIndex").getSymbol("OwnStatus" + i);
	statusElement.$("NameText").html( currentStatus.Name );
	statusElement.$("HPText").html( currentStatus.HP );
	statusElement.$("SPText").html( currentStatus.SP );
	statusElement.$("LVText").html( currentStatus.LV );
}
// 初回処理
var currentTurn = battleData.turn[ turnNum ];
// メッセージ反映
sym.getSymbol("TopIndex").$("Message").html( currentTurn.message );
// ターンのカウントを増やす
turnNum++;

sym.getSymbol(“TopIndex”).getSymbol(“OwnStatus” + i)のあたりは上部の味方のステータスを表示する部分にデータを渡しているところです。OwnStatusひとつが一つのキャラのHP,SP,LV,名前をとりまとめているシンボルです。

クリック動作

ステージのクリック動作をきっかけに、敵の動きや演出が動くようにしました。

if( isAnimate ){
	// アニメ中は動作しない。
} else {
	// 現在のターン
	currentTurn = battleData.turn[ turnNum ];
	nextTurn = battleData.turn[ turnNum + 1 ];
	// modeによって表示分岐
	if( currentTurn.mode == "attack" ) {
		sym.getSymbol("TopIndex").$("Message").html( currentTurn.message );
		sym.getSymbol("TopIndex").getSymbol( "Enemy" + currentTurn.effect.eid ).play( 2000 );
		sym.getSymbol("TopIndex").getSymbol( "Slash" + currentTurn.effect.eid ).play( 500 );
		sym.play(3000);
		// アニメ中フラグ ON
		isAnimate = true;
	} else if( currentTurn.mode == "defence" ) {
		sym.getSymbol("TopIndex").$("Message").html( currentTurn.message );
		sym.getSymbol("TopIndex").getSymbol( "Enemy" + currentTurn.effect.eid ).play( 1000 );
		sym.play(1500); // 画面揺れ
		// ダメージ反映
		var currentStatus = battleData.startStatus[ currentTurn.effect.id ];
		var statusElement = sym.getSymbol("TopIndex").getSymbol("OwnStatus" + currentTurn.effect.id);
		var afterHP = currentStatus.HP - currentTurn.effect.damage;
		statusElement.$("HPText").html( afterHP );
		// アニメ中フラグ ON
		isAnimate = true;
	} else if( currentTurn.mode == "finish" ) {
		window.open("edge_battle_sample.html", "_self");
	}

	// ターンのカウントを増やす
	turnNum++;
}

isAnimate は簡易的に連打による演出飛びや不都合を軽減するために実装しました。各演出が終わると、isAnimateをfalseに戻し、操作可能にします。

データのやり取りはedge_battle_sample.htmlのJavaScriptから

edge_battle_sample.htmlをみていただくと、データのやり取りはここのJavaScriptから行なっています。

	<script>
	// バトルデータ
    battleData = {
		startStatus:[
			{ Name:"主人公" , HP:500 , SP:50 , LV:20 },
			{ Name:"仲間A" , HP:400 , SP:80 , LV:22 },
			{ Name:"仲間B" , HP:200 , SP:200 , LV:18 }
		]
		,
		turn:[
			{ mode:"info" , message:"ウィスプ 3ひきがあらわれた!<br /><br /> →つぎへ" },
			{ mode:"attack" , message:"主人公のこうげき!ウィスプAに30のダメージをあたえた!" , effect:{ eid:0 , damage:30 } },
			{ mode:"attack" , message:"仲間Aのこうげき!ウィスプBに25のダメージをあたえた!" , effect:{ eid:1 , damage:25 } },
			{ mode:"attack" , message:"仲間Bのこうげき!ウィスプCに8のダメージをあたえた!" , effect:{ eid:2 , damage:18 } },
			{ mode:"defence" , message:"ウィスプAのこうげき!主人公は5のダメージをうけた!" , effect:{ eid:0 , id:0 , damage:5 } },
			{ mode:"defence" , message:"ウィスプBのこうげき!主人公は12のダメージをうけた!" , effect:{ eid:1 , id:0 , damage:12 } },
			{ mode:"defence" , message:"ウィスプCのこうげき!仲間Bは8のダメージをうけた!" , effect:{ eid:2 , id:2 , damage:8 } },
			{ mode:"attack" , message:"主人公のこうげき!ウィスプAに28のダメージをあたえた!<br />ウィスプAをたおした!!" , effect:{ eid:0 , damage:28 } , dead:{ eid:0 } },
			{ mode:"attack" , message:"仲間Aのこうげき!ウィスプBに20のダメージをあたえた!" , effect:{ eid:1 , damage:20 } },
			{ mode:"attack" , message:"仲間Bのこうげき!ウィスプBに18のダメージをあたえた!<br />ウィスプBをたおした!!" , effect:{ eid:1 , damage:18 } , dead:{ eid:1 } },
			{ mode:"defence" , message:"ウィスプCのこうげき!仲間Aは8のダメージをうけた!" , effect:{ eid:2 , id:1 , damage:8 } },
			{ mode:"attack" , message:"主人公のこうげき!ウィスプCに22のダメージをあたえた!" , effect:{ eid:2 , damage:22 } },
			{ mode:"attack" , message:"仲間Aのこうげき!ウィスプCに11のダメージをあたえた!" , effect:{ eid:2 , damage:11 } },
			{ mode:"attack" , message:"仲間Bのこうげき!ウィスプCに15のダメージをあたえた!<br />ウィスプCをたおした!!" , effect:{ eid:2 , damage:15 } , dead:{ eid:2 } },
			{ mode:"finish" , message:"ウィスプ 3ひきをたおした!<br /><br /> →タッチするともう一度再生" }
		]
    }
	</script>

画面の揺らし

画面の揺らしについて、いろいろどう作るか考えたのですが、結局、メイン演出を一つシンボルに包んで揺らすようにしました。

Edgeのシンボルは、オーサリング上でFLASHでいうグラフィックシンボルのような挙動をするので、内部のトリガーでsym.stop()をかけていても絵が進みます。最初戸惑いました。

トリガーにコメント書いて挙動を覚えておいた

FLASHのようなラベルはないのでトリガーにコメント書いて挙動を覚えておくようにしました。今後のバージョンアップでgotoAndPlay(ラベル)のような設定ができると演出の調整がしやすいなあ。

DIV構造

今回の演出のDIV構造も載せておきます。ChromeデベロッパーツールのElementでキャプチャ。

image_20130211_232139_1
(クリックすると拡大します)

おおむね、Edge内で表現されている階層が素直に表現されている印象です。

おわりに

本番の仕様ではないですが、ある程度、突っ込んで作ってみると、制作のサジ加減が見えてきて良いですね。この程度の作りであれば、途方もない仕様というわけでなく、負荷をみつつ設計次第でなんとかなりそうなラインと感じました。

今回のソースコードも以下においておきます。

Edge Animateデータダウンロード:edge_battle_sample.zip

それでは、よき Edge Animate Life を!