こんにちは、ロックです!
今回は皆さんもお馴染みのゲームジャンル「戦略SLG」についてです!
戦略SLGとは
ターン性でキャラクターを動かし合うシミュレーションゲーム。
代表としては、ファミコンウォーズシリーズですね。
今回の主題を考えると、ファイアーエムブレムシリーズにも密接に関わってくるでしょう。
どちらにも共通してキャラクターを動かす時にどれくらい移動できるかが表示されます。
本日はその移動範囲を求めてみたいと思います。
環境
- Ubuntu16.04(VirtualBoxでの仮想環境)
- gcc version 5.4.0
c言語とCUIで表現してみようと思います。
実行結果画面
前準備
- map_move
- 20*20の移動範囲計算結果格納
- cal_can_move_range(y, x, n)
- 移動範囲を計算して map_move を更新していく関数
以上のものを用意します。
それでは考えて行きましょう。
方針
- 位置:(5,5)
- 移動可能量:3
- 検索順:↑→←↓
- 検索条件①:一度行った場所は検索しない(足跡)
- 検索条件②:????
1.思考用に9*9用いてみましょう。
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|
1 | |||||||||
2 | |||||||||
3 | |||||||||
4 | |||||||||
5 | P | ||||||||
6 | |||||||||
7 | |||||||||
8 | |||||||||
9 |
2.上が歩けそうなので上に1歩行ってみましょう。
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|
1 | |||||||||
2 | |||||||||
3 | |||||||||
4 | 1 | ||||||||
5 | P | ||||||||
6 | |||||||||
7 | |||||||||
8 | |||||||||
9 |
3.まだ上に行けそうです、上に2歩目。
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|
1 | |||||||||
2 | |||||||||
3 | 2 | ||||||||
4 | 1 | ||||||||
5 | P | ||||||||
6 | |||||||||
7 | |||||||||
8 | |||||||||
9 |
4.まだまだ上に行けそうです、上に3歩目。
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|
1 | |||||||||
2 | 3 | ||||||||
3 | 2 | ||||||||
4 | 1 | ||||||||
5 | P | ||||||||
6 | |||||||||
7 | |||||||||
8 | |||||||||
9 |
5.3歩動いてしまいました。これ以上は上に行けないので、一つ前のマスから右へ3歩目を踏み出してみましょう。
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|
1 | |||||||||
2 | 3 | ||||||||
3 | 2 | 3 | |||||||
4 | 1 | ||||||||
5 | P | ||||||||
6 | |||||||||
7 | |||||||||
8 | |||||||||
9 |
6.3歩目なのでこれ以上動けません、一つ前のマスに戻って左へ行ってみましょう。
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|
1 | |||||||||
2 | 3 | ||||||||
3 | 3 | 2 | 3 | ||||||
4 | 1 | ||||||||
5 | P | ||||||||
6 | |||||||||
7 | |||||||||
8 | |||||||||
9 |
7.このように続けていくと、以下のようになりますね(まだ終わりではない)
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|
1 | |||||||||
2 | 3 | ||||||||
3 | 3 | 2 | 3 | ||||||
4 | 3 | 2 | 1 | 2 | 3 | ||||
5 | 3 | P | 3 | ||||||
6 | 3 | 2 | 1 | 2 | 3 | ||||
7 | 3 | 2 | 3 | ||||||
8 | 3 | ||||||||
9 |
おやおや、左右に伸びきれてませんね。
検索の都合上、(4,5),(6,5)は3歩目の足跡がついてしまうのですね。
これを修正するのはとても簡単です。
以下の検索条件を加えてあげれば良さそうです。
検索条件②:すでに足跡がついていても、現在の歩数よりも大きければ、上書きする
8.すると、こうなります。
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|
1 | |||||||||
2 | 3 | ||||||||
3 | 3 | 2 | 3 | ||||||
4 | 3 | 2 | 1 | 2 | 3 | ||||
5 | 3 | 2 | 1 | P | 1 | 2 | 3 | ||
6 | 3 | 2 | 1 | 2 | 3 | ||||
7 | 3 | 2 | 3 | ||||||
8 | 3 | ||||||||
9 |
無事に求めていたことが実現できました。
では実際のコードはどのように実現できるでしょうか。
設計
- map_move
- 20*20の移動範囲計算結果格納
これに歩数を入れていきます。
さて、肝心のコードですが、マスを順々に追っていくような処理に適したものがあります。
それは、再帰です。
再帰でなくとも良いですが、再帰だと短く書けるのでおすすめです。(某パズルゲームの連結しているかも再帰で判定できますね)
実際のコードがこちら
void cal_can_move_range(int y, int x, int n){ // 足跡をつける(現在歩数を代入) map_move[y][x] = n; // 残り歩数が0ならば終了 if(n == 0) return; // 上へ行けるなら if(map_move[y-1][x] < n) cal_can_move_range(y-1,x,n-1); // 右へ行けるなら if(map_move[y][x+1] < n) cal_can_move_range(y,x+1,n-1); // 左へ行けるなら if(map_move[y][x-1] < n) cal_can_move_range(y,x-1,n-1); // 下へ行けるなら if(map_move[y+1][x] < n) cal_can_move_range(y+1,x,n-1); }
※ map_moveは全て-1で初期化しておく
1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | |
---|---|---|---|---|---|---|---|---|---|
1 | |||||||||
2 | 0 | ||||||||
3 | 0 | 1 | 0 | ||||||
4 | 0 | 1 | 2 | 1 | 0 | ||||
5 | 0 | 1 | 2 | P | 2 | 1 | 0 | ||
6 | 0 | 1 | 2 | 1 | 0 | ||||
7 | 0 | 1 | 0 | ||||||
8 | 0 | ||||||||
9 |
※ 残り歩数を入れているので、方針時とは数字が異なる
これで完成です。
発展編
マスによっては移動コストが異なる場合もあるでしょう。
平地であれば移動に1かかるが、森であれば移動には2必要である。
これは実は簡単です。
先ほど n-1 していた部分を変えてあげれば良いでしょう。
平地なら n-1 森なら n-2 という風に。
そこまで実装した画面が一番初めに見せた実行結果画面ということになります。
^
が森として、移動コストは2必要としています。どうなるか見てみましょう。
森を通ると残り歩数の減少量が2であることがわかるかと思います。
#
は壁を意味しており、通行不可マスです。
移動コストは100必要としています(これで実質通行不可)
あとがき
ということで本日の主題は、戦略SLGの移動範囲計算を実装してみた、でした!
今年の冬は自作でこれを用いたゲームでも作ってみたいなーと夢想しているロックがお送りしました!
ありがとうございました!