Day 4: レベルの生成
本日の成果
レベル生成アルゴリズムの学習:
Procedural Generation in Game Design by Tanya X. Short
RogueBasin
Dungeon Generation
ヘロンの数学ちゃんねる で概要を確認
アルゴリズムの概要
このコードは、ランダムなダンジョンを生成するためのアルゴリズムを利用しています。以下にアルゴリズムの概要を説明します。
-
ダンジョンの要素を表す定数
WALL
(壁)、FLOOR
(床)、PLAYER
(プレイヤー)を定義します。 -
create_dungeon
関数では、指定された幅と高さを持つダンジョンを作成します。初期状態ではすべてのセルが壁で埋められています。 -
create_room
関数では、指定された範囲内でランダムな幅と高さの部屋を生成し、ダンジョンに部屋を配置します。部屋は床で埋められます。 -
place_rooms
関数では、指定された数の部屋をダンジョン内に配置します。部屋の配置はランダムです。 -
create_corridor
関数では、2つの部屋の中間点を結ぶ通路を生成し、ダンジョンに床を配置します。 -
generate_dungeon
関数では、ダンジョンの生成と部屋の配置、通路の生成を行います。また、プレイヤーの初期位置もランダムな部屋内に設定されます。 -
draw_dungeon
関数では、ダンジョンをグラフィックスウィンドウに描画します。各セルは矩形で表示され、壁、床、プレイヤーは異なる色で描画されます。 -
メインのゲームループでは、Pygame のイベントを処理し、プレイヤーの移動を制御します。プレイヤーが移動するたびに、ダンジョン内のセルの状態が更新されます。
-
ゲームループの中で
draw_dungeon
関数を呼び出してダンジョンを描画し、pygame.display.flip()
でウィンドウを更新します。
このアルゴリズムにより、部屋と通路からなるランダムなダンジョンが生成され、プレイヤーがキーボード入力に応じて移動することができます。
コードの詳細
モジュールのインポート:
import pygame
import random
-
pygame
モジュール: ゲーム開発用の Python ライブラリです。 -
random
モジュール: 乱数生成のための Python ライブラリです。
ダンジョンの要素を表す定数の定義:
WALL = 0
FLOOR = 1
PLAYER = 2
-
WALL
: 壁を表す定数 -
FLOOR
: 床を表す定数 -
PLAYER
: プレイヤーを表す定数
ダンジョン生成関連の関数の定義:
def create_dungeon(width, height):
dungeon = [[WALL for _ in range(width)] for _ in range(height)]
return dungeon
-
create_dungeon(width, height)
: 指定された幅と高さのダンジョンを作成し、壁で初期化して返します。
def create_room(min_width, max_width, min_height, max_height, dungeon):
width = random.randint(min_width, max_width)
height = random.randint(min_height, max_height)
x = random.randint(1, len(dungeon[0]) - width - 1)
y = random.randint(1, len(dungeon) - height - 1)
for i in range(y, y + height):
for j in range(x, x + width):
dungeon[i][j] = FLOOR
return (x, y, width, height)
-
create_room(min_width, max_width, min_height, max_height, dungeon)
: 指定された範囲内でランダムなサイズの部屋を作成し、ダンジョン上の床に変換します。部屋の位置とサイズの情報をタプルとして返します。
def place_rooms(num_rooms, min_width, max_width, min_height, max_height, dungeon):
rooms = []
for _ in range(num_rooms):
room = create_room(min_width, max_width, min_height, max_height, dungeon)
rooms.append(room)
return rooms
-
place_rooms(num_rooms, min_width, max_width, min_height, max_height, dungeon)
: 指定された数の部屋を生成し、ダンジョン内に配置します。各部屋の位置とサイズの情報をリストとして返します。
def create_corridor(start, end, dungeon):
x1, y1 = start
x2, y2 = end
while x1 != x2 or y1 != y2:
if x1 < x2:
x1 += 1
elif x1 > x2:
x1 -= 1
elif y1 < y2:
y1 += 1
elif y1 > y2:
y1 -= 1
dungeon[y1][x1] = FLOOR
-
create_corridor(start, end, dungeon)
: 部屋の中心座標を指定して通路を生成し、ダンジョン上の床に変換します。
ダンジョン全体の生成関数:
def generate_dungeon(width, height, num_rooms, min_width, max_width, min_height, max_height):
dungeon = create_dungeon(width, height)
rooms = place_rooms(num_rooms, min_width, max_width, min_height, max_height, dungeon)
for i in range(len(rooms) - 1):
start = (rooms[i][0] + rooms[i][2] // 2, rooms[i][1] + rooms[i][3] // 2)
end = (rooms[i+1][0] + rooms[i+1][2] // 2, rooms[i+1][1] + rooms[i+1][3] // 2)
create_corridor(start, end, dungeon)
player_room = random.choice(rooms)
player_x = random.randint(player_room[0], player_room[0] + player_room[2] - 1)
player_y = random.randint(player_room[1], player_room[1] + player_room[3] - 1)
dungeon[player_y][player_x] = PLAYER
return dungeon, rooms, player_x, player_y
-
generate_dungeon
関数: 指定されたパラメータに基づいてダンジョン全体を生成します。ダンジョンの作成、部屋の配置、通路の作成、プレイヤーの初期位置の設定を行います。ダンジョン、部屋のリスト、プレイヤーの初期位置を返します。
ダンジョンの描画関数:
def draw_dungeon(dungeon):
for y in range(len(dungeon)):
for x in range(len(dungeon[y])):
cell = dungeon[y][x]
cell_rect = pygame.Rect(x * cell_size, y * cell_size, cell_size, cell_size)
if cell == WALL:
pygame.draw.rect(window, (0, 0, 0), cell_rect)
elif cell == FLOOR:
pygame.draw.rect(window, (255, 255, 255), cell_rect)
elif cell == PLAYER:
pygame.draw.rect(window, (255, 0, 0), cell_rect)
-
draw_dungeon
関数: ダンジョンの状態を描画します。ダンジョンの各セルに対応する矩形を作成し、セルの値に応じて色を設定して描画します。
Pygame の初期化とウィンドウの作成:
dungeon_width = 800
dungeon_height = 600
cell_size = 20
pygame.init()
window = pygame.display.set_mode((dungeon_width, dungeon_height))
pygame.display_set_caption("Dungeon Game")
-
dungeon_width
とdungeon_height
はそれぞれウィンドウの幅と高さを表します。 -
cell_size
はダンジョン内のセル(部屋や通路のタイル)のサイズを表します。 -
pygame.init()
は Pygame ライブラリを初期化します。 -
window
変数にpygame.display.set_mode((dungeon_width, dungeon_height))
を用いてウィンドウを作成します。 -
pygame.display.set_caption("Dungeon Game")
はウィンドウのキャプション(タイトル)を設定します。
プレイヤーの初期位置の設定:
player_x = 0
player_y = 0
-
player_x
とplayer_y
はプレイヤーの初期位置の座標を表します。ここでは 0 で初期化されています。
ダンジョンの生成とプレイヤーの初期位置の取得:
dungeon, rooms, player_x, player_y = generate_dungeon(40, 30, 15, 3, 10, 3, 10)
-
generate_dungeon
関数を呼び出して、ダンジョンを生成し、部屋のリストとプレイヤーの初期位置を取得します。引数として、ダンジョンの幅と高さ、部屋の数、部屋の最小幅と最大幅、部屋の最小高さと最大高さが指定されています。
ゲームループ:
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
# プレイヤーの移動処理
if event.key == pygame.K_UP:
# 上キーが押された場合の処理
elif event.key == pygame.K_DOWN:
# 下キーが押された場合の処理
elif event.key == pygame.K_LEFT:
# 左キーが押された場合の処理
elif event.key == pygame.K_RIGHT:
# 右キーが押された場合の処理
# ダンジョンの描画処理
draw_dungeon(dungeon)
# 画面の更新
pygame.display.flip()
pygame.quit()
-
running
変数がTrue
の間、ゲームループが実行されます。 - イベントループ内でキーボードイベントを処理し、プレイヤーの移動を制御します。
-
draw_dungeon
関数を呼び出してダンジョンを描画します。 -
pygame.display.flip()
でウィンドウの内容を更新します。 - ゲームループが終了した後、
pygame.quit()
を呼び出して Pygame を終了します。
まとめ
今回作成したものを基準に、前回までに学んだ内容を追加したら敵キャラやアイテムを作れないかな~
アルゴリズムについては、正直理解できなかった…
英語と数学、アルゴリズムの勉強しなければ…
とりあえずは、手を動かして完成までもっていこう!