Python3でRPGを作る時に使えそうな技術の断片 -道路を生成しよう-

f:id:sakage24:20170726201621j:plain

前回は村を自動生成出来るようにしました。今回は村と村とを道路で接続してみましょう。現時点では単なるフレーバーですが、例えば道路上では移動速度2倍とか、エンカウント率軽減…とかのメリットを持たせると👍です。

というか、PCでも絵文字使えるんですね…unicodeに入ってるのかな?

前回(見なくても平気です見て下さい)

https://www.kiwi-bird.xyz/2017/07/26/20170726000312/

今回やること

  • 村同士を道で相互に接続する

必要なのは村の座標と2次元配列のマップです。適当に作ってしまいましょう

初期設定

  • 草原 = 0
  • 村 = 1
  • 道路 = 2
  • 進入不可タイル = 9

上記の様に、代数的記法でマップを表現します。


from pprint import PrettyPrinter
pp = PrettyPrinter(indent=4)
# 10 * 10のワールドマップ
x = [[0 for x in range(10)] for y in range(10)]
# 村の位置
grid = 1)2, 2), (8, 6), (4, 4), (9, 1
for i, j in grid:
x[i][j] = 1
# 壁の作成
for i in range(1, 8):
x[6][i] = 9
pp.pprint(x)
[   [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 1, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 1, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 9, 9, 9, 9, 9, 9, 9, 9, 0],
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
[0, 0, 0, 0, 0, 0, 1, 0, 0, 0],
[0, 1, 0, 0, 0, 0, 0, 0, 0, 0]]

こんな感じにしてみました。9は進入禁止なので、避けて道を作成してほしいですね。

組み合わせ

村と村は道によって、相互に接続される必要があります。ただし重複して作る必要はありませんよね。

中学の頃に習った確率の知識がこんな所で役に立ちます。もしも貴方が学生で、学校の勉強に意義を見いだせないならば、ゲーム作りをしてみましょう。圧倒的に数学やっておいてよかった…と思いますよ。

話がそれましたね。さて、数学で習ったであろう順列と組み合わせを思い出しましょう。私のように綺麗さっぱり忘れている人も安心です。itertoolsモジュールからcombinationsをインポートすればイチコロですね。
*1

from itertools import combinations
pos = list(combinations(grid, 2))
>>> pos
[2)2, 2), (8, 6, 3)2, 2), (4, 4, 4)2, 2), (9, 1, 5)8, 6), (4, 4, 6)8, 6), (9, 1, 7)4, 4), (9, 1]

全ての組み合わせが簡単に出てきました。接続元と接続先が求められたので、後は最短経路を求めて繋いでいくだけですね。

最短経路

過去の記事で纏めてあるので、割愛します。

https://www.kiwi-bird.xyz/2017/07/17/20170717183403
https://www.kiwi-bird.xyz/2017/07/15/20170715160456

上記を適当にコピペして使って下さい。全部書くとめっちゃ長くなるので、擬似コードでやり方を書いてみます。


for x in list(combinations(comb, 2)):
start_pos, target_pos = x
ブレゼンハム = ブレゼンハムのアルゴリズム(start_pos, target_pos)
# 初めに直線での最短距離を求めて、進入不可のタイルがあるかどうかを判断するフラグ
bresenham_flag = True
for i in ブレゼンハム:
if マップの値は進入不可かどうか?:
bresenham_flag = False
break
if bresenham_flag:
for i in ブレゼンハム:
if maps[i] != 村:
maps[i] = 道
else:
routes = A*法
for i in routes:
if maps[i] != 村:
maps[i] = 道

考え方としてはこんな感じですかね。とりあえず比較的軽量なブレゼンハムのアルゴリズムで最短ルートを出します。道中に進入不可タイルがある場合はループを打ち切り、A*法での探索に切り替えています。

終わり

Pythonの検索殆ど流れてこなくて涙目ww普通、男の子ならRPG作るの好きやろーーー!!!

人工知能の作り方 ――「おもしろい」ゲームAIはいかにして動くのか

人工知能の作り方 ――「おもしろい」ゲームAIはいかにして動くのか

*1:復習したい場合は、こちらが参考になるかもしれません。

脚注   [ + ]

1. 2, 2), (8, 6), (4, 4), (9, 1
2. 2, 2), (8, 6
3. 2, 2), (4, 4
4. 2, 2), (9, 1
5. 8, 6), (4, 4
6. 8, 6), (9, 1
7. 4, 4), (9, 1

コメントを残す

メールアドレスが公開されることはありません。