戦術SLGの作り方(移動範囲を求める)
文章:.1064
日付:2004/06/27
目次
1.はじめに
2.基本編
−地形データを作成する
−移動データを作成する
−移動範囲を求める
2.応用編
−地形データを作成する
−移動範囲を求める
1.はじめに
ここでは、戦術SLGの作り方について説明をします。
戦術SLGとは、将棋やチェスのように、自分のコマを動かして
相手のコマを倒すゲームのことです。
将棋やチェスと違うのは、コマに色々なパラメータがあることでしょう。
例えば「ファイヤーエンブレム」や「オウガバトル」のようなゲームといえば
分かりやすいでしょうか。
今回の講座はここを参考にしています。
「戦術SLGの移動アルゴリズム」
http://www.campus.ne.jp/~ishigami/CREATION/MAKING/index.html
なかなか詳しく書いてあるので、勉強になります。
普通の戦術SLGでは、コマを選択したときに、
どこまで移動できるのかを明るくしたりして、視覚的に分かるようにしています。
今回は、その移動範囲の求め方を説明します。
2.基本編
まず最初は、
- 「10×10」のマップ
- 地形のタイプは「平地」(移動力を「1」消費する)しか存在しない
- コマの初期位置は(x, y) = (6, 6)
- コマの移動力は「3」
といったシンプルなモデルで考えてみます。
−地形データを作成する
「10×10」のマップなので、そのままですが、「10×10」の配列を作成します。
(正確には配列オーバーを防ぐための「壁」を作成するため、12×12となります)
配列の初期値として、「-1」を設定します。
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
−移動データを作成する
コマの初期位置と移動力を設定します。
初期位置は(6, 6)、移動力は「3」とします。
−移動範囲を求める
データの準備ができたので、移動範囲を求めます。
初期処理として、開始位置に移動力をセットします。
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 3 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
ここで2つ関数を作成します。
一つは現在位置から、上/下/左/右を探索する関数です。
この関数を「Search4」とします。
もう一つは移動先が移動可能な場所であるかを判定する関数です。
この関数を「Search」とします。
「Search4」は各方向(上/下/左/右)ごとに、探索する地点の座標と移動力を「Search」に渡します。
「Search」は移動力を1つ減らし、移動力が残っていれば、「Search4」を再帰呼び出しします。
たとえば、「Search4」で上を探索すると、「Search」で「2」を設定します。
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 2 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 3 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
移動力がまだ残っていますので、「Search4」を再帰呼び出しし、上を探索して、「Search」で「1」を設定します。
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 2 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 3 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
さらに、移動力がまだ残っていますので、「Search4」を再帰呼び出しし、上を探索して、「Search」で「0」を設定します。
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 0 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 2 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 3 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
移動力がなくなったので、(6, 4)地点に戻り、左を探索し、「Search」で「0」を設定します。
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 0 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | 0 | 1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 2 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 3 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
移動力がなくなったので、(6, 4)地点に戻り、下を探索し、「Search」で「0」を設定します。
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 0 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | 0 | 1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 0 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 3 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
移動力がなくなったので、(6, 4)地点に戻り、右を探索し、「Search」で「0」を設定します。
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 0 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | 0 | 1 | 0 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 0 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 3 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
といったことを繰り返すと、以下のようになります。
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 0 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | 0 | 1 | 0 | -1 | -1 | -1 |
-1 | -1 | -1 | 0 | 1 | 0 | 1 | 0 | -1 | -1 |
-1 | -1 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | -1 |
-1 | -1 | -1 | 0 | 1 | 0 | 1 | 0 | -1 | -1 |
-1 | -1 | -1 | -1 | 0 | 1 | 0 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 0 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
ここで、この処理が無駄なことをしていることに気がついたでしょうか?
例えば、上・上と探索した後に上・下と探索していたりします。
移動力が大きいほど、探索範囲は大きくなりますので、
処理速度の遅いコンピュータでは、致命的となりかねません。
そこで、「Search」関数で、「移動力-1 < 地形の値」であった場合には、その地点の探索を行わないようにします。
こうすることで無駄な処理がなくなり、以下のようになると思います。
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 0 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | 0 | 1 | 0 | -1 | -1 | -1 |
-1 | -1 | -1 | 0 | 1 | 2 | 1 | 0 | -1 | -1 |
-1 | -1 | 0 | 1 | 2 | 3 | 2 | 1 | 0 | -1 |
-1 | -1 | -1 | 0 | 1 | 2 | 1 | 0 | -1 | -1 |
-1 | -1 | -1 | -1 | 0 | 1 | 0 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | 0 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
これで移動範囲を求めることができました。(´▽`)
3.応用編
応用として、以下の地形データを追加し、バリエーションを持たせます。
−地形データを作成する
マップデータを以下のようにしてみます。
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -2 | -2 | -1 | -1 | -1 | -1 | -1 | -9 | -1 |
-1 | -2 | -2 | -1 | -1 | -1 | -1 | -1 | -1 | -2 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -9 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -2 | -1 | -1 | -2 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -2 | -1 | -1 | -1 | -1 | -9 | -1 | -1 | -9 |
-1 | -2 | -2 | -1 | -1 | -1 | -1 | -1 | -9 | -1 |
ところどころにある、「-2」が「森」、「-9」が「山」です。
移動できないはずなのに、なぜ「山」が「-9」であるのかというと、
現在の移動力が「3」であるため、論理的に移動できないからです。
作ってみるとわかりますが、例外的な処理をもうけて処理を複雑にするよりは、こうしたほうが処理が楽になります。
−移動範囲を求める
移動範囲の求め方は、基本編とほぼ変わりません。
違うのは、「Search」関数で単純に移動力を「-1」としていたものを、地形の値から引くというところです。
具体的には、以下のようになります。
-1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 | -1 |
-1 | -2 | -2 | -1 | -1 | -1 | -1 | -1 | -9 | -1 |
-1 | -2 | -2 | -1 | -1 | 0 | -1 | -1 | -1 | -2 |
-1 | -1 | -1 | -1 | 0 | 1 | 0 | -1 | -1 | -1 |
-1 | -1 | -1 | 0 | 1 | 2 | -9 | -1 | -1 | -1 |
-1 | -1 | -1 | 0 | 1 | 3 | 2 | 0 | -1 | -1 |
-1 | -1 | -1 | 0 | 1 | 2 | 1 | 0 | -1 | -1 |
-1 | -1 | -1 | -1 | 0 | 1 | 0 | -1 | -1 | -1 |
-1 | -2 | -1 | -1 | -1 | 0 | -9 | -1 | -1 | -9 |
-1 | -2 | -2 | -1 | -1 | -1 | -1 | -1 | -9 | -1 |
どうでしょうか。
それっぽくなったのではないでしょうか。
今回の処理は、単に移動範囲を求めるだけでなく、
魔法や飛び道具などの射程範囲・効果範囲や、
コンピュータの索敵範囲を求めるのに必要となるので、しっかり理解してくださいね。
以上、.1064でした。