デザイナーにも分かりやすいjQuery入門講座|jQueryの使い方

このエントリーをはてなブックマークに追加
索引
1章:短編集
2章:診断系コンテンツ
3章:製品抽出系コンテンツ
番外:Simulation Game

ユニットの移動

ファミコンウォーズに方向転換

前回マップの画像を作成している際、ドット絵を作成するのは以外と面倒ということに気が付きました。そしてファイナルファンタジータクティクス系のゲームだとドット絵のキャラもたくさん作成しなければ行けないことに躊躇したのです。

そこでドット絵が少なくて済みそうな「ファミコンウォーズ」系のゲームに方向転換することにしました。ファミコンウォーズ系だと街の占領とかがある分、思考ルーチンの作成が面倒なので、また日和るかもしれませんが...。

移動にも再帰処理が必要だった

選択した場所に移動する

今回作成したのはサンプル(sample/02_move.html)です。マップ上に配置された赤い戦車をクリックすると、移動範囲が明示されます。次に移動したい場所をクリックしてください、するとクリックした位置に向かって戦車が移動します。

数の多い方向へ進む

移動範囲が確定すれば移動は簡単だと思っていたのですが違いました。演出上、どの様な経路で移動したかを示さねばならず目的地までの道順を調べなければならないのです。

しかし前回デバッグ用にマスに残りの移動量を表示していたことで、以外と早く解決策が見つかりました。

左図のように選択した位置からスタートして、数値の多いマスを辿るのです。そして数値の一番多い点(周りが自分の数値より小さい点)まで来たら終了。マスの情報は配列に入れて、移動の際のアニメに利用します。

この数値の多いマスを辿る部分に再帰処理が必要になりました。仕組みは前回の移動範囲を探るのと非常に似ています。

function routeSearchFunc(x,y,now){//----最短経路のリストを作成する再帰処理
	var maxPoint = 0;
	var nextTarget = [];
	for(var i=0;i<searchArray.length;i++){
		var myDirection = searchArray[i];
		var posX = x + myDirection[1];
		var posY = y + myDirection[0];
		var chk_flg = true;
		if (posY < 0 || posY > mapLength_y-1) chk_flg = false;
		if (posX < 0 || posX > mapLength_x-1) chk_flg = false;
		if (chk_flg){
			var myPoint = blankArray[posY][posX];
			if (myPoint > maxPoint){
				maxPoint = myPoint;
				nextTarget = [posX,posY];
			}
		}
	}
	if (maxPoint>now){
		routeList.push(nextTarget);
		routeSearchFunc(nextTarget[0],nextTarget[1],maxPoint)//-----再帰
	}
}

4行目で移動範囲と同じように4方のマス目を調べます。8〜11行目のマップ内かどうか調べる処理も同じです。異なるのは12行目以降で、ここで数値を取得し最大の数値(maxPoint)を保存するようにしています。あわせて最大の数値の持つマスの座標を変数nextTargetに保存します。

そして4方を調べた後、19行目以降で最大値が自分よりも大きい場合は次のマス情報「nextTarget」を配列に記憶し再帰処理で辿ります。もし最大値が自分の数値よりも小さい場合(つまり一番数値が多い場所)は、そこがゴールとなるので再帰処理はせずに終了となります。

この段階で移動に関する難しい部分は完了したと思います。しかし現状ではユニットを管理しておらず1つのユニットしか操作できません。次はユニットを管理する仕組みを作成し、複数のユニットを移動できるようにしたいと思います。

複数のユニットを操作

課題を洗い出す

配置するユニットはdiv要素なので、これにidを設定すれば「とりあえず」複数のユニットに対応できます。
→サンプル(sample/03_multi.html

次なる課題

サンプルでは「船」を追加しており、移動範囲が相容れないため重複することはありません。ゲームにするためには重複を防ぐ仕組みを追加する必要があり、ポイントなのは陣営によって扱いが変わる点です。

陣営により異なる処理

敵陣営のユニットがある場合、そのマスは通過不可になり、また同じ場所に停止することもできない。
同じ陣営のユニットでも同じ場所に停止する事ができないのは同じだが、通過は可能となる。
なので陣営毎に個別にユニットを管理する必要がある。

自軍ユニットのマスク

同じマスには移動できない

ユニットは同じマスに移動できないようにしなければなりません。なのでユニットの配置されているマップにもマスクをかけるようにしました。
→サンプル(sample/04_ally.html

懸案事項

通常はユニットはマスクの下に配置すべきなのですが、操作中のユニットと他のユニットは同じレイヤーに存在しているため、捜査中のユニットもマスクの下になってしまいます。つまりマスクの下をくぐるように移動するようになってしまいます。cocos2d-xでは重ね順の変更も少しは容易だと思うので、この問題は移植する際に対応しようと思います。しかしユニットがマスクの上にあると情勢を把握しやすいので、このままでも良いかなとも思ったりしています。

function chkAllyUnitFunc(myThis){//=====移動の際に味方ユニットをマスクする
	var myData = $(myThis).data();
	var mySide = myData.side;//=========陣営のデータを取得
	var myUnitID = myData.unitID;//=====ユニットIDを取得
	var mySideList = allUnitData[mySide];
	var chkUnitList = arraySubFunc(mySideList,myUnitID);
	for (var i in chkUnitList){
		var unitData = $("#u_"+chkUnitList[i]).data();
		var x = unitData.x;var y = unitData.y;
		var mapValue = blankArray[y][x];
		if (mapValue > -1){//====マスク対象になっていないものだけをマスクする
			var hexPos = new Object();
			hexPos.left = x*hexSize;
			hexPos.top = y*hexSize;
			$("<div class='maskHex'></div>").appendTo("#selectArea").offset(hexPos);
		}
	}
}

3行目で自分の陣営IDを取得し、それを利用して5行目で自陣のユニットリストを取得します。4行目で自分のユニットIDを取得しているのは自分(現在操作しているユニット)にはマスクしないように区別するため。

7行目のfor文で自軍のユニットについてすべて調べるようにする。自軍ユニットの位置を9行目で取得し、その位置の数値(blankArrayの値)を調べる。この値が-1の場合は移動範囲でないため、もともとからマスクされる。なので11行目でのif文により、-1より大きい場合だけを処理するようにします。実際にマスクを追加しているのは15行目。

敵のユニット処理

今回はここまで、次回は敵ユニットを追加しようと思います。敵ユニットの場合は通過できないようにするため色々と配列を操作しなければならなそうです...。