モジュールからパックマンのゲームを探し、自分なりに画像を変更しアレンジした

  1. import pygame
  2. import sys
  3. import random
  4. import math
  5. from collections import deque
  6. # ******************** 画像の読込 ********************
  7. img_road = pygame.image.load("image/road.png")
  8. img_wall = pygame.image.load("image/wall.png")
  9. img_scope = [
  10.     pygame.image.load("image/scope_0.png"),
  11.     pygame.image.load("image/scope_1.png")
  12. ]
  13. img_player = [
  14.     pygame.image.load("image/S__14762009.jpg"),
  15.     pygame.image.load("image/S__14762009.jpg"),
  16.     pygame.image.load("image/player_2.png"),
  17.     pygame.image.load("image/player_3.png"),
  18.     pygame.image.load("image/player_4.png"),
  19.     pygame.image.load("image/player_5.png"),
  20.     pygame.image.load("image/player_6.png"),
  21.     pygame.image.load("image/player_7.png"),
  22.     pygame.image.load("image/player_8.png"),
  23.     pygame.image.load("image/player_9.png"),
  24.     pygame.image.load("image/player_10.png"),
  25.     pygame.image.load("image/player_11.png")
  26. ]
  27. img_enemy = [
  28.     pygame.image.load("image/enemy_0.png"),
  29.     pygame.image.load("image/enemy_1.png"),
  30.     pygame.image.load("image/enemy_2.png"),
  31.     pygame.image.load("image/enemy_3.png"),
  32.     pygame.image.load("image/enemy_4.png"),
  33.     pygame.image.load("image/enemy_5.png"),
  34.     pygame.image.load("image/enemy_6.png"),
  35.     pygame.image.load("image/enemy_7.png"),
  36.     pygame.image.load("image/enemy_8.png"),
  37.     pygame.image.load("image/enemy_9.png"),
  38.     pygame.image.load("image/enemy_10.png"),
  39.     pygame.image.load("image/enemy_11.png"),
  40.     pygame.image.load("image/enemy_12.png"),
  41.     pygame.image.load("image/enemy_13.png"),
  42.     pygame.image.load("image/enemy_14.png"),
  43.     pygame.image.load("image/enemy_15.png"),
  44.     pygame.image.load("image/enemy_16.png"),
  45.     pygame.image.load("image/enemy_17.png"),
  46.     pygame.image.load("image/enemy_18.png"),
  47.     pygame.image.load("image/enemy_19.png"),
  48.     pygame.image.load("image/enemy_20.png"),
  49.     pygame.image.load("image/enemy_21.png"),
  50.     pygame.image.load("image/enemy_22.png"),
  51.     pygame.image.load("image/enemy_23.png")
  52. ]
  53. img_goal = pygame.image.load("image/goal.png")
  54. img_coin = pygame.image.load("image/coin.png")
  55. img_item = pygame.image.load("image/item.png")
  56. img_arrow = pygame.image.load("image/arrow.png")
  57. # ******************** 定数/変数 ********************
  58. # =============== COLOR ===============
  59. WHITE = (255, 255, 255)
  60. BLACK = (0, 0, 0)
  61. RED = (255, 0, 0)
  62. # =============== SOUND ===============
  63. snd_pacman_blue = None
  64. snd_pacman_red = None
  65. snd_pacman_yellow = None
  66. snd_pacman_green = None
  67. snd_pacman_brown = None
  68. snd_player_attack = None
  69. snd_player_damage = None
  70. snd_break_wall = None
  71. snd_arrive_goal = None
  72. snd_get_coin = None
  73. snd_get_item = None
  74. # =============== SIZE / FPS ===============
  75. SCREEN_SIZE = 900 # スクリーンサイズ
  76. FPS = 10 # フレームレート
  77. # =============== DIRECTION ===============
  78. DIR_UP = 0 # 上方向
  79. DIR_RIGHT = 1 # 右方向
  80. DIR_DOWN = 2 # 下方向
  81. DIR_LEFT = 3 # 左方向
  82. # =============== COLOR ===============
  83. COLOR_BLACK = 0 # 黒色
  84. COLOR_BLUE = 1 # 青色
  85. COLOR_RED = 2 # 赤色
  86. COLOR_YELLOW = 3 # 黄色
  87. COLOR_GREEN = 4 # 緑色
  88. COLOR_BROWN = 5 # 茶色
  89. # =============== GAME MANAGE ===============
  90. idx = 0 # ゲーム進行のインデックス
  91. tmr = 0 # ゲームのタイマー
  92. course = 0 # コースの回数
  93. WALL = 0 # 壁
  94. ROAD = -1 # 通路
  95. GOAL = -2 # ゴール
  96. ITEM = -3 # アイテム
  97. COIN = -4 # コイン
  98. # =============== PLAYER ===============
  99. pl_col = 0 # パックマンの色(使用するアイテムで変化)
  100. pl_x = 0 # x座標
  101. pl_y = 0 # y座標
  102. pl_d = 0 # 移動方向
  103. pl_fast = False # 移動スピードが早い
  104. pl_coin = 0 # 拾ったコインの数
  105. pl_life = 0 # 残機(100コインごとに1増える)
  106. pl_item = [0] * 6 # 各アイテムの所有数
  107. pl_scope = 0 # 視界の広さ
  108. pl_muteki = 0
  109. # =============== ENEMY ===============
  110. emy_max = 0 # 敵の最大数
  111. emy_no = 0 # 敵の配列の添字
  112. emy_num_max = False # 敵が最大数いるか
  113. emy_time = 0 # 敵を生成するまでの時間
  114. emy_f = [False] * emy_max # 敵が存在するか
  115. emy_col = [0] * emy_max # 敵の色(タイプ)
  116. emy_x = [0] * emy_max # x座標
  117. emy_y = [0] * emy_max # y座標
  118. emy_d = [0] * emy_max # 移動方向
  119. emy_s = [0] * emy_max # 移動スピード
  120. ENEMY_HIGH_SPEED = 2 # 移動スピード:早い
  121. ENEMY_NORMAL_SPEED = 4 # 移動スピード:普通
  122. ENEMY_LOW_SPEED = 6 # 移動スピード:遅い
  123. # =============== ITEM ===============
  124. item_use = False # 使用中の有無
  125. item_time = 0 # 使用時間
  126. item_max = 0 # アイテムの最大数
  127. item_generate_time = 0 # アイテムを生成するまでの時間
  128. # =============== MAZE ===============
  129. goal_f = False # ゴールが迷路上にあるか
  130. goal_generate_time = 0 # ゴールを生成するまでの時間
  131. # =============== MAZE ===============
  132. maze_size = 60 # 迷路の1ブロックのサイズ
  133. maze_num = 17 # 迷路のブロック数
  134. maze = [] # 迷路を管理
  135. # =============== BFS ===============
  136. q = deque()
  137. dist = []
  138. # ============================================================
  139. # DRAW
  140. # ============================================================
  141. # ******************** 文字の描画 ********************
  142. def draw_text(sc, txt, x, y, siz, col, center):
  143.     fnt = pygame.font.Font(None, siz)
  144.     sur = fnt.render(txt, True, col)
  145.     # 中央揃え
  146.     if center == True:
  147.         x = x - sur.get_width() / 2
  148.         y = y - sur.get_height() / 2
  149.     # 文字の描画
  150.     sc.blit(sur, [x, y])
  151. # ******************** 画像の描画 ********************
  152. def draw_img(sc, img, x, y):
  153.     # 中央揃え
  154.     x = x - img.get_width() / 2
  155.     y = y - img.get_height() / 2
  156.     # 画像の描画
  157.     sc.blit(img, [x, y])
  158. # ******************** 迷路の描画 ********************
  159. def draw_maze(sc):
  160.     for y in range(-7, 8):
  161.         for x in range(-7, 8):
  162.             X = (x + 7) * maze_size
  163.             Y = (y + 7) * maze_size
  164.             mx = pl_x + x
  165.             my = pl_y + y
  166.             # 描画:壁と通路
  167.             if 0 <= mx < maze_num and 0 <= my < maze_num:
  168.                 if maze[my][mx] == WALL: # 壁
  169.                     sc.blit(img_wall, [X, Y])
  170.                 if maze[my][mx] == ROAD: # 通路
  171.                     sc.blit(img_road, [X, Y])
  172.                 # 描画:ゴール
  173.                 if maze[my][mx] == GOAL:
  174.                     sc.blit(img_goal, [X, Y])
  175.                 # 描画:コイン
  176.                 if maze[my][mx] == COIN:
  177.                     sc.blit(img_coin, [X, Y])
  178.                 # 描画:アイテム
  179.                 if maze[my][mx] == ITEM:
  180.                     sc.blit(img_item, [X, Y])
  181.                 # 描画:敵
  182.                 for n in range(emy_max):
  183.                     if emy_f[n] == False:
  184.                         continue
  185.                     if emy_x[n] == mx and emy_y[n] == my:
  186.                         sc.blit(img_enemy[emy_col[n] * 4 + emy_d[n]], [X, Y])
  187.             # 描画:プレイヤー
  188.             if x == 0 and y == 0:
  189.                 if pl_muteki % 2 == 0:
  190.                     img_rz = pygame.transform.rotozoom(img_player[pl_col * 2 + tmr % 2], pl_d * (-90), 1.0)
  191.                     # アイテム使用中 + 使用時間切れ間近
  192.                     if item_use == True and item_time < FPS * 3:
  193.                         if tmr % 2 == 0:
  194.                             sc.blit(img_rz, [X, Y])
  195.                     else:
  196.                         sc.blit(img_rz, [X, Y])
  197.                 # 緑色のパックマンの効果:矢印
  198.                 if pl_col == COLOR_GREEN and goal_f == True:
  199.                     # プレイヤーからゴールの方向(角度)を取得
  200.                     a = calc_angle_of_goal_from_player()
  201.                     # ゴールの方向に矢印を向ける
  202.                     img_rz = pygame.transform.rotozoom(img_arrow, -a, 1.0)
  203.                     draw_img(sc, img_rz, X + maze_size / 2, Y - maze_size)
  204.     # 描画:視界エリア
  205.     draw_img(sc, img_scope[pl_scope], SCREEN_SIZE / 2, SCREEN_SIZE / 2)
  206.     # 枠組み
  207.     pygame.draw.rect(sc, WHITE, [SCREEN_SIZE + 30, 30, 240, 340])
  208.     pygame.draw.rect(sc, WHITE, [SCREEN_SIZE + 30, 400, 240, 290])
  209.     pygame.draw.rect(sc, WHITE, [SCREEN_SIZE + 30, 720, 240, 150])
  210.     # 色別の敵の数
  211.     count_enemy_color = [0] * 6
  212.     for n in range(emy_max):
  213.         if emy_f[n] == False:
  214.             continue
  215.         # 色別にカウント
  216.         count_enemy_color[emy_col[n]] += 1
  217.     # 敵の情報
  218.     for i in range(6):
  219.         # 画像の描画
  220.         img_rz = pygame.transform.rotozoom(img_enemy[i * 4], 0, 0.8)
  221.         sc.blit(img_rz, [SCREEN_SIZE + 70, 50 + 50 * i])
  222.         # 文字の描画
  223.         draw_text(sc, "X " + str(count_enemy_color[i]), SCREEN_SIZE + 150, 60 + 50 * i, 35, BLACK, False)
  224.     # パックマン(効果)の情報
  225.     for i in range(1, 6):
  226.         # 画像の描画
  227.         img_rz = pygame.transform.rotozoom(img_player[i * 2], -90, 0.8)
  228.         sc.blit(img_rz, [SCREEN_SIZE + 110, 370 + 50 * i])
  229.         # 文字の描画
  230.         draw_text(sc, "[" + str(i) + "]:", SCREEN_SIZE + 50, 380 + 50 * i, 35, BLACK, False)
  231.         draw_text(sc, "X " + str(pl_item[i]), SCREEN_SIZE + 180, 380 + 50 * i, 35, BLACK, False)
  232.     # プレイヤーの情報
  233.     draw_text(sc, "COURSE : " + str(course), SCREEN_SIZE + 70, 750, 35, BLACK, False)
  234.     draw_text(sc, "COIN : " + str(pl_coin), SCREEN_SIZE + 70, 790, 35, BLACK, False)
  235.     draw_text(sc, "LIFE : " + str(pl_life), SCREEN_SIZE + 70, 830, 35, BLACK, False)
  236. # ============================================================
  237. # MAZE
  238. # ============================================================
  239. # ******************** 迷路の初期化 ********************
  240. def init_maze():
  241.     global maze, maze_num
  242.     # 迷路の大きさを拡大
  243.     maze_num += 2
  244.     # 迷路の初期化
  245.     maze = []
  246.     for y in range(maze_num):
  247.         maze.append([0] * maze_num)
  248. # ******************** 迷路の自動生成 ********************
  249. def make_maze():
  250.     # 迷路の初期化
  251.     init_maze()
  252.     # 方向:上、右、下、左
  253.     XP = [0, 1, 0, -1]
  254.     YP = [-1, 0, 1, 0]
  255.     # ボードの周囲を壁にする
  256.     for x in range(maze_num):
  257.         maze[0][x] = WALL
  258.         maze[maze_num - 1][x] = WALL
  259.     for y in range(maze_num - 1):
  260.         maze[y][0] = WALL
  261.         maze[y][maze_num - 1] = WALL
  262.     # ボードの中を全て通路にする
  263.     for y in range(1, maze_num - 1):
  264.         for x in range(1, maze_num - 1):
  265.             maze[y][x] = ROAD
  266.     # 【棒倒し方で迷路を作成】
  267.     # 等間隔に壁を作る
  268.     for y in range(2, maze_num - 2, 2):
  269.         for x in range(2, maze_num - 2, 2):
  270.             maze[y][x] = WALL
  271.     # 等間隔に作った壁の隣に、壁を作る
  272.     for y in range(2, maze_num - 2, 2):
  273.         for x in range(2, maze_num - 2, 2):
  274.             d = random.randint(0, 3)
  275.             if x > 2:
  276.                 d = random.randint(0, 2)
  277.             maze[y + YP[d]][x + XP[d]] = WALL
  278. # ============================================================
  279. # PLAYER
  280. # ============================================================
  281. # ******************** プレイヤーの移動 ********************
  282. def move_player(key):
  283.     global pl_x, pl_y, pl_d
  284.     # プレイヤーの移動速度
  285.     if pl_fast == False:
  286.         if tmr % 2 == 0:
  287.             return
  288.     # キー入力:上方向
  289.     if key[pygame.K_UP] == True:
  290.         pl_d = DIR_UP
  291.         # 移動方向が壁以外
  292.         if maze[pl_y - 1][pl_x] != WALL:
  293.             pl_y -= 1
  294.         # 壁 + 茶色のパックマン
  295.         else:
  296.             if pl_col == COLOR_BROWN:
  297.                 snd_break_wall.play()
  298.                 maze[pl_y - 1][pl_x] = ROAD
  299.                 pl_y -= 1
  300.                 item_effect_off()
  301.     # キー入力:右方向
  302.     if key[pygame.K_RIGHT] == True:
  303.         pl_d = DIR_RIGHT
  304.         # 移動方向が壁以外
  305.         if maze[pl_y][pl_x + 1] != WALL:
  306.             pl_x += 1
  307.         # 壁 + 茶色のパックマン
  308.         else:
  309.             if pl_col == COLOR_BROWN:
  310.                 snd_break_wall.play()
  311.                 maze[pl_y][pl_x + 1] = ROAD
  312.                 pl_x += 1
  313.                 item_effect_off()
  314.     # キー入力:下方向
  315.     if key[pygame.K_DOWN] == True:
  316.         pl_d = DIR_DOWN
  317.         # 移動方向が壁以外
  318.         if maze[pl_y + 1][pl_x] != WALL:
  319.             pl_y += 1
  320.         # 壁 + 茶色のパックマン
  321.         else:
  322.             if pl_col == COLOR_BROWN:
  323.                 snd_break_wall.play()
  324.                 maze[pl_y + 1][pl_x] = ROAD
  325.                 pl_y += 1
  326.                 item_effect_off()
  327.     # キー入力:左方向
  328.     if key[pygame.K_LEFT] == True:
  329.         pl_d = DIR_LEFT
  330.         # 移動方向が壁以外
  331.         if maze[pl_y][pl_x - 1] != WALL:
  332.             pl_x -= 1
  333.         # 壁 + 茶色のパックマン
  334.         else:
  335.             if pl_col == COLOR_BROWN:
  336.                 snd_break_wall.play()
  337.                 maze[pl_y][pl_x - 1] = ROAD
  338.                 pl_x -= 1
  339.                 item_effect_off()
  340. # ============================================================
  341. # ENEMY
  342. # ============================================================
  343. # ******************** 敵の初期化 ********************
  344. def init_enemy():
  345.     global emy_f, emy_col, emy_x, emy_y, emy_d, emy_s
  346.     emy_f = [False] * emy_max
  347.     emy_col = [0] * emy_max
  348.     emy_x = [0] * emy_max
  349.     emy_y = [0] * emy_max
  350.     emy_d = [0] * emy_max
  351.     emy_s = [0] * emy_max
  352. # ******************** 敵を出す ********************
  353. def bring_enemy():
  354.     # 敵の配置:ランダム選択
  355.     while True:
  356.         emy_x = random.randint(1, maze_num - 2)
  357.         emy_y = random.randint(1, maze_num - 2)
  358.         # 位置が通路(コインを含む)場合 -> ok
  359.         if maze[emy_y][emy_x] == ROAD or maze[emy_y][emy_x] == COIN:
  360.             # プレイヤーと離れている -> ok
  361.             if (emy_x < pl_x - 5 or pl_x + 5 < emy_x) and (emy_y < pl_y - 5 or pl_y + 5 < emy_y):
  362.                 break
  363.     # 敵の色:ランダム選択
  364.     emy_col = random.randint(COLOR_BLACK, COLOR_BROWN)
  365.     # 敵の移動スピード(敵の色で判別)
  366.     if emy_col == COLOR_BLACK: # 黒
  367.         emy_s = ENEMY_HIGH_SPEED
  368.     elif emy_col == COLOR_RED: # 赤
  369.         emy_s = ENEMY_NORMAL_SPEED
  370.     else: # 青、黄、緑、茶
  371.         emy_s = ENEMY_LOW_SPEED
  372.     # 敵を配置
  373.     set_enemy(emy_x, emy_y, emy_s, emy_col)
  374. # ******************** 敵をセット ********************
  375. def set_enemy(x, y, s, col):
  376.     global emy_no
  377.     while True:
  378.         if emy_f[emy_no] == False:
  379.             emy_f[emy_no] = True
  380.             emy_col[emy_no] = col
  381.             emy_x[emy_no] = x
  382.             emy_y[emy_no] = y
  383.             emy_s[emy_no] = s
  384.             break
  385.         emy_no = (emy_no + 1) % emy_max
  386. # ******************** 敵の移動 ********************
  387. def move_enemy():
  388.     for n in range(emy_max):
  389.         # 敵が存在しない(要素の)場合はとばす
  390.         if emy_f[n] == False:
  391.             continue
  392.         # 敵の移動スピード
  393.         if tmr % emy_s[n] != 0:
  394.             continue
  395.         # 敵の色:黒 -> 移動方向:プレイヤーのいる方向 or ランダム
  396.         if emy_col[n] == COLOR_BLACK:
  397.             # 移動方向:プレイヤーの方向
  398.             if emy_y[n] > pl_y:
  399.                 emy_dir = DIR_UP # 上方向
  400.             if emy_y[n] < pl_y:
  401.                 emy_dir = DIR_DOWN # 下方向
  402.             if emy_x[n] < pl_x:
  403.                 emy_dir = DIR_RIGHT # 右方向
  404.             if emy_x[n] > pl_x:
  405.                 emy_dir = DIR_LEFT # 左方向
  406.             # 移動できたかどうか -> 移動可能ならば移動(Trueを返す)
  407.             move_ok = move_check_to_move(emy_dir, n)
  408.             # 移動できていない場合 -> ランダム
  409.             if move_ok == False:
  410.                 while True:
  411.                     emy_dir = random.randint(DIR_UP, DIR_LEFT) # 移動方向:ランダム選択
  412.                     move_ok = move_check_to_move(emy_dir, n) # 移動できたかどうか -> 移動可能ならば移動(Trueを返す)
  413.                     # 移動できるまで繰り返す
  414.                     if move_ok == True:
  415.                         break
  416.         # 敵の色:青、赤、黄、緑、茶 -> 移動方向:目標へ移動(追尾)
  417.         else:
  418.             # 青、赤 -> プレイヤーを追尾
  419.             if emy_col[n] == COLOR_BLUE or emy_col[n] == COLOR_RED:
  420.                 BFS(emy_x[n], emy_y[n], pl_x, pl_y) # 幅優先探索法でプレイヤーの位置までの最短ルートを算出
  421.                 next_dir = next_direction(emy_x[n], emy_y[n], pl_x, pl_y) # 幅優先探索法で求めたルートから次の移動方向を取得
  422.             # 黄 -> ゴールへ移動 or プレイヤーを追尾
  423.             elif emy_col[n] == COLOR_YELLOW:
  424.                 # ゴールが存在する:ゴールへ移動
  425.                 if search_target(GOAL) == True:
  426.                     goal_x, goal_y = get_target_coordinate(GOAL) # ゴールのx,y座標を取得
  427.                     BFS(emy_x[n], emy_y[n], goal_x, goal_y) # 幅優先探索法でゴールの位置までの最短ルートを算出
  428.                     next_dir = next_direction(emy_x[n], emy_y[n], goal_x, goal_y) # 幅優先探索法で求めたルートから次の移動方向を取得
  429.                 # ゴールが存在しない:プレイヤーを追尾
  430.                 else:
  431.                     BFS(emy_x[n], emy_y[n], pl_x, pl_y) # 幅優先探索法でプレイヤーの位置までの最短ルートを算出
  432.                     next_dir = next_direction(emy_x[n], emy_y[n], pl_x, pl_y) # 幅優先探索法で求めたルートから次の移動方向を取得
  433.             # 緑:コイン
  434.             elif emy_col[n] == COLOR_GREEN:
  435.                 # コインが存在する:コインへ移動
  436.                 if search_target(COIN) == True:
  437.                     coin_x, coin_y = get_target_coordinate(COIN) # コインのx,y座標を取得
  438.                     BFS(emy_x[n], emy_y[n], coin_x, coin_y) # 幅優先探索法でコインの位置までの最短ルートを算出
  439.                     next_dir = next_direction(emy_x[n], emy_y[n], coin_x, coin_y) # 幅優先探索法で求めたルートから次の移動方向を取得
  440.                 # コインが存在しない:プレイヤーを追尾
  441.                 else:
  442.                     BFS(emy_x[n], emy_y[n], pl_x, pl_y) # 幅優先探索法でプレイヤーの位置までの最短ルートを算出
  443.                     next_dir = next_direction(emy_x[n], emy_y[n], pl_x, pl_y) # 幅優先探索法で求めたルートから次の移動方向を取得
  444.             # 茶:アイテム
  445.             elif emy_col[n] == COLOR_BROWN:
  446.                 # アイテムが存在する:アイテムへ移動
  447.                 if search_target(ITEM) == True:
  448.                     item_x, item_y = get_target_coordinate(ITEM) # アイテムのx,y座標を取得
  449.                     BFS(emy_x[n], emy_y[n], item_x, item_y) # 幅優先探索法でコインの位置までの最短ルートを算出
  450.                     next_dir = next_direction(emy_x[n], emy_y[n], item_x, item_y) # 幅優先探索法で求めたルートから次の移動方向を取得
  451.                 # アイテムが存在しない:プレイヤーを追尾
  452.                 else:
  453.                     BFS(emy_x[n], emy_y[n], pl_x, pl_y) # 幅優先探索法でプレイヤーの位置までの最短ルートを算出
  454.                     next_dir = next_direction(emy_x[n], emy_y[n], pl_x, pl_y) # 幅優先探索法で求めたルートから次の移動方向を取得
  455.             # 移動
  456.             if next_dir == DIR_UP: # 上方向
  457.                 emy_y[n] -= 1
  458.                 emy_d[n] = DIR_UP
  459.             elif next_dir == DIR_RIGHT: # 右方向
  460.                 emy_x[n] += 1
  461.                 emy_d[n] = DIR_RIGHT
  462.             elif next_dir == DIR_DOWN: # 下方向
  463.                 emy_y[n] += 1
  464.                 emy_d[n] = DIR_DOWN
  465.             elif next_dir == DIR_LEFT: # 左方向
  466.                 emy_x[n] -= 1
  467.                 emy_d[n] = DIR_LEFT
  468. # ******************** 取得した移動方向に移動可能か確認 -> 可能ならば移動(True) ********************
  469. def move_check_to_move(emy_dir, no):
  470.     # 移動可能か確認 -> 移動
  471.     move_ok = False
  472.     # 上方向に移動 + 移動可否の確認
  473.     if emy_dir == DIR_UP and maze[emy_y[no] - 1][emy_x[no]] != 0:
  474.         emy_d[no] = DIR_UP
  475.         emy_y[no] -= 1
  476.         move_ok = True
  477.     # 右方向に移動 + 移動可否の確認
  478.     if emy_dir == DIR_RIGHT and maze[emy_y[no]][emy_x[no] + 1] != 0:
  479.         emy_d[no] = DIR_RIGHT
  480.         emy_x[no] += 1
  481.         move_ok = True
  482.     # 下方向に移動 + 移動可否の確認
  483.     if emy_dir == DIR_DOWN and maze[emy_y[no] + 1][emy_x[no]] != 0:
  484.         emy_d[no] = DIR_DOWN
  485.         emy_y[no] += 1
  486.         move_ok = True
  487.     # 左方向に移動 + 移動可否の確認
  488.     if emy_dir == DIR_LEFT and maze[emy_y[no]][emy_x[no] - 1] != 0:
  489.         emy_d[no] = DIR_LEFT
  490.         emy_x[no] -= 1
  491.         move_ok = True
  492.     return move_ok
  493. # ******************** ゲーム上に敵が最大数いるか調べる ********************
  494. def enemy_num_max_check():
  495.     global emy_num_max, emy_time
  496.     # 敵の最大数分を繰り返す
  497.     for n in range(emy_max):
  498.         # 敵が最大数分いない場合
  499.         if emy_f[n] == False:
  500.             emy_num_max = False
  501.             emy_time = FPS * 20
  502.             break
  503. # ******************** 敵を生成するか判定 -> 生成を行う ********************
  504. def check_enemy_to_generate():
  505.     global emy_time, emy_num_max
  506.     # 敵の最大数いる -> 最大数いるか判定
  507.     if emy_num_max == True:
  508.         enemy_num_max_check()
  509.     # 敵が最大数いない + 敵の再生成時間が0より大きい
  510.     elif emy_num_max == False and emy_time > 0:
  511.         emy_time -= 1
  512.     # 敵が最大数いない + 敵の際生成時間が0 -> 敵を生成
  513.     elif emy_num_max == False and emy_time == 0:
  514.         bring_enemy()
  515.         emy_num_max = True
  516. # ============================================================
  517. # ITEM
  518. # ============================================================
  519. # ******************** アイテムの使用 ********************
  520. def use_item(key):
  521.     global pl_col, pl_scope, pl_fast
  522.     global item_use, item_time
  523.     # 青色のパックマン
  524.     if key[pygame.K_1] == True and pl_item[COLOR_BLUE] > 0:
  525.         snd_pacman_blue.play()
  526.         item_effect_off()
  527.         pl_item[COLOR_BLUE] -= 1
  528.         pl_col = COLOR_BLUE
  529.         pl_fast = True
  530.         item_use = True
  531.         item_time = FPS * 18
  532.     # 赤色のパックマン
  533.     if key[pygame.K_2] == True and pl_item[COLOR_RED] > 0:
  534.         snd_pacman_red.play()
  535.         item_effect_off()
  536.         pl_item[COLOR_RED] -= 1
  537.         pl_col = COLOR_RED
  538.         item_use = True
  539.         item_time = FPS * 8
  540.     # 黄色のパックマン
  541.     if key[pygame.K_3] == True and pl_item[COLOR_YELLOW] > 0:
  542.         snd_pacman_yellow.play()
  543.         item_effect_off()
  544.         pl_item[COLOR_YELLOW] -= 1
  545.         pl_col = COLOR_YELLOW
  546.         pl_scope = 1
  547.         item_use = True
  548.         item_time = FPS * 13
  549.     # 緑色のパックマン
  550.     if key[pygame.K_4] == True and pl_item[COLOR_GREEN] > 0:
  551.         snd_pacman_green.play()
  552.         item_effect_off()
  553.         pl_item[COLOR_GREEN] -= 1
  554.         pl_col = COLOR_GREEN
  555.         item_use = True
  556.         item_time = FPS * 23
  557.     # 茶色のパックマン
  558.     if key[pygame.K_5] == True and pl_item[COLOR_BROWN] > 0:
  559.         snd_pacman_brown.play()
  560.         item_effect_off()
  561.         pl_item[COLOR_BROWN] -= 1
  562.         pl_col = COLOR_BROWN
  563.         item_use = True
  564.         item_time = FPS * 33
  565. # ******************** アイテムの効果を解除 ********************
  566. def item_effect_off():
  567.     global pl_col, pl_scope, pl_fast
  568.     global item_use, item_time
  569.     # アイテムの使用中:False / 使用時間:0
  570.     item_use = False
  571.     item_time = 0
  572.     # パックマンの色:黒 / 移動速度:通常 / 視野の範囲:通常
  573.     pl_col = COLOR_BLACK
  574.     pl_fast = False
  575.     pl_scope = 0
  576. # ******************** アイテムを生成するか判定 -> 生成を行う ********************
  577. def check_item_to_generate():
  578.     global item_generate_time
  579.     # 迷路上のアイテムの数をカウント
  580.     count_item = 0
  581.     for y in range(maze_num):
  582.         for x in range(maze_num):
  583.             if maze[y][x] == ITEM:
  584.                 count_item += 1
  585.     # アイテムが最大数までない + アイテムの再生成時間がある
  586.     if count_item < item_max and item_generate_time:
  587.         item_generate_time -= 1
  588.     # アイテムが最大数までない + アイテムの再生成時間が0 -> アイテムの生成
  589.     elif count_item < item_max and item_generate_time == 0:
  590.         set_target(ITEM)
  591.         item_generate_time = FPS * 15
  592. # ============================================================
  593. # GOAL
  594. # ============================================================
  595. # ******************** ゴールを生成するか判定 -> 生成を行う ********************
  596. def check_goal_to_generate():
  597.     global goal_generate_time, goal_f
  598.     # ゴールがない + ゴールの再生成時間がある
  599.     if goal_f == False and goal_generate_time > 0:
  600.         goal_generate_time -= 1
  601.     # ゴールがない + ゴールの再生成時間が0 -> ゴールの生成
  602.     elif goal_f == False and goal_generate_time == 0:
  603.         set_target(GOAL)
  604.         goal_f = True
  605. # ============================================================
  606. # BFS
  607. # ============================================================
  608. # ******************** distの初期化 ********************
  609. def init_dist():
  610.     global dist
  611.     # distの初期化
  612.     dist = []
  613.     for y in range(maze_num):
  614.         dist.append([0] * maze_num)
  615. # ******************** 幅優先探索法より、目的地のルートをマッピングするために使用(mazeのコピー) ********************
  616. def set_dist():
  617.     # distの初期化
  618.     init_dist()
  619.     # 迷路をコピー(WALL or ROADのみ)
  620.     for y in range(maze_num):
  621.         for x in range(maze_num):
  622.             if maze[y][x] == WALL:
  623.                 dist[y][x] = WALL
  624.             else:
  625.                 dist[y][x] = ROAD
  626. # ******************** 幅優先探索法 ********************
  627. def BFS(start_x, start_y, end_x, end_y):
  628.     global q
  629.     # 迷路のコピーを作成
  630.     set_dist()
  631.     # ナンバリング用の数字
  632.     dist_num = 1
  633.     # x,y方向
  634.     dy = (1, 0, -1, 0)
  635.     dx = (0, 1, 0, -1)
  636.     # キュー:初期値の追加
  637.     q = deque()
  638.     q.append((start_x, start_y))
  639.     # スタート位置をナンバリング
  640.     dist[start_y][start_x] = dist_num
  641.     # 目標の位置まで探索したら、True
  642.     target_search = False
  643.     while len(q) > 0:
  644.         # 現在地(x,y)を取得
  645.         now_pos = q.popleft()
  646.         x, y = now_pos
  647.         # ナンバリング
  648.         dist_num += 1
  649.         # 上下左右の4方向
  650.         for di in range(4):
  651.             nx = x + dx[di]
  652.             ny = y + dy[di]
  653.             # 迷路の範囲外はとばす
  654.             if (nx < 0 or nx >= maze_num or ny < 0 or ny >= maze_num): continue
  655.             # 壁とナンバリング済みのマスはとばす
  656.             if (dist[ny][nx] >= WALL): continue
  657.             # 探索終了:目標の位置にたどり着いた場合
  658.             if nx == end_x and ny == end_y:
  659.                 # ナンバリング
  660.                 dist[ny][nx] = dist_num
  661.                 target_search = True
  662.                 break
  663.             # ナンバリング
  664.             dist[ny][nx] = dist_num
  665.             # 次の探索
  666.             q.append((nx, ny))
  667.         # while文を抜ける:プレイヤーの探索をした場合
  668.         if target_search == True:
  669.             break
  670. # ******************** 幅優先探索法(BFS)から次の移動方向を取得 ********************
  671. def next_direction(start_x, start_y, end_x, end_y):
  672.     dist_x = end_x
  673.     dist_y = end_y
  674.     dist_num = dist[end_y][end_x]
  675.     # 次の移動方向
  676.     next_dir = 0
  677.     while True:
  678.         # 次の移動方向
  679.         dist_num -= 1
  680.         # 上方向
  681.         if dist[dist_y - 1][dist_x] == dist_num:
  682.             dist_y -= 1
  683.             next_dir = DIR_DOWN
  684.         # 右方向
  685.         elif dist[dist_y][dist_x + 1] == dist_num:
  686.             dist_x += 1
  687.             next_dir = DIR_LEFT
  688.         # 下方向
  689.         elif dist[dist_y + 1][dist_x] == dist_num:
  690.             dist_y += 1
  691.             next_dir = DIR_UP
  692.         # 左方向
  693.         elif dist[dist_y][dist_x - 1] == dist_num:
  694.             dist_x -= 1
  695.             next_dir = DIR_RIGHT
  696.         # 敵の位置まで来たらループを抜ける
  697.         if dist_x == start_x and dist_y == start_y:
  698.             break
  699.     return next_dir
  700. # ============================================================
  701. # SEARCH / GET / SET
  702. # ============================================================
  703. # ******************** 指定のターゲットが存在するか探す ********************
  704. def search_target(target):
  705.     # 指定のターゲットが存在するか
  706.     result = False
  707.     # 指定のターゲットを探す
  708.     for y in range(maze_num):
  709.         for x in range(maze_num):
  710.             if maze[y][x] == target:
  711.                 result = True
  712.     return result
  713. # ******************** 指定のターゲットのx,y座標の取得 ********************
  714. def get_target_coordinate(target):
  715.     # 指定のターゲットのx,y座標
  716.     target_x = 0
  717.     target_y = 0
  718.     # 指定のターゲットの座標を探す
  719.     for y in range(maze_num):
  720.         for x in range(maze_num):
  721.             if maze[y][x] == target:
  722.                 target_x = x
  723.                 target_y = y
  724.     return target_x, target_y
  725. # ******************** 目標をセット ********************
  726. def set_target(target):
  727.     # 取得するx,y座標
  728.     x = 0
  729.     y = 0
  730.     # プレイヤーから離す距離
  731.     dis = maze_num // 4
  732.     while True:
  733.         # x,y座標 -> ランダム選択
  734.         x = random.randint(1, maze_num - 2)
  735.         y = random.randint(1, maze_num - 2)
  736.         # x,y座標 -> 通路 or コイン
  737.         if maze[y][x] == ROAD or maze[y][x] == COIN:
  738.             maze[y][x] = target
  739.             break
  740. # ============================================================
  741. # CALC
  742. # ============================================================
  743. # ******************** プレイヤーとゴールの位置の角度を算出(緑色のパックマンの効果で使用) ********************
  744. def calc_angle_of_goal_from_player():
  745.     # 計算:プレイヤーのx,y座標
  746.     x_pl = pl_x * maze_size + maze_size / 2
  747.     y_pl = pl_y * maze_size + maze_size / 2
  748.     # 計算:ゴールのx,y座標
  749.     x_goal = 0
  750.     y_goal = 0
  751.     for y in range(maze_num):
  752.         for x in range(maze_num):
  753.             if maze[y][x] == GOAL:
  754.                 x_goal = x * maze_size + maze_size / 2
  755.                 y_goal = y * maze_size + maze_size / 2
  756.     # 計算:プレイヤーとゴールのx,y方向の距離
  757.     x_dis = x_goal - x_pl
  758.     y_dis = y_goal - y_pl
  759.     # 角度を計算
  760.     ang = math.degrees(math.atan2(y_dis, x_dis))
  761.     return ang
  762. # ============================================================
  763. # HIT CHECK
  764. # ============================================================
  765. # ******************** ヒットチェック ********************
  766. def hit_check():
  767.     global pl_life, pl_coin, pl_muteki
  768.     global goal_f, goal_generate_time
  769.     # プレイヤー:コインを拾う
  770.     if maze[pl_y][pl_x] == COIN:
  771.         snd_get_coin.play()
  772.         maze[pl_y][pl_x] = ROAD
  773.         pl_coin += 1
  774.         # コインが100枚 -> ライフが1増える
  775.         if pl_coin >= 100:
  776.             pl_life += 1
  777.             pl_coin -= 100
  778.     # プレイヤー:アイテムを拾う
  779.     if maze[pl_y][pl_x] == ITEM:
  780.         snd_get_item.play()
  781.         maze[pl_y][pl_x] = ROAD
  782.         # 取得するアイテムの種類をランダムに選定
  783.         item = random.randint(1, 5)
  784.         pl_item[item] += 1
  785.     # 敵
  786.     for n in range(emy_max):
  787.         # 敵が存在しない場合はとばす
  788.         if emy_f[n] == False:
  789.             continue
  790.         # 敵:プレイヤーと衝突
  791.         if emy_x[n] == pl_x and emy_y[n] == pl_y:
  792.             # プレイヤー:赤色のパックマンの時 -> 敵を倒す
  793.             if pl_col == COLOR_RED:
  794.                 snd_player_attack.play()
  795.                 emy_f[n] = False
  796.             # プレイヤー:赤色のパックマン以外
  797.             else:
  798.                 # プレイヤーが無敵状態ではない場合
  799.                 if pl_muteki == 0:
  800.                     snd_player_damage.play()
  801.                     pl_muteki = FPS * 3
  802.                     pl_life -= 1
  803.                     emy_f[n] = False
  804.         # 敵:黄 -> ゴールへ到達
  805.         if emy_col[n] == COLOR_YELLOW and maze[emy_y[n]][emy_x[n]] == GOAL:
  806.             maze[emy_y[n]][emy_x[n]] = ROAD # ゴールをなくす
  807.             goal_f = False # ゴールがないフラグ
  808.             goal_generate_time = FPS * 15 # ゴールを再生成するまでの時間
  809.         # 敵:緑 -> コインへ到達
  810.         if emy_col[n] == COLOR_GREEN and maze[emy_y[n]][emy_x[n]] == COIN:
  811.             maze[emy_y[n]][emy_x[n]] = ROAD # コインをなくす
  812.         # 敵:茶 -> アイテムへ到達
  813.         if emy_col[n] == COLOR_BROWN and maze[emy_y[n]][emy_x[n]] == ITEM:
  814.             maze[emy_y[n]][emy_x[n]] = ROAD # アイテムをなくす
  815. # ============================================================
  816. # GAME
  817. # ============================================================
  818. # ******************** ゲームの初期化 ********************
  819. def init_game():
  820.     global maze_num, course
  821.     global pl_life, pl_item, pl_coin, pl_muteki
  822.     # 迷路の数
  823.     maze_num = 17
  824.     # コースの階層
  825.     course = 0
  826.     # プレイヤー情報
  827.     pl_life = 2
  828.     pl_item = [2] * 6
  829.     pl_coin = 0
  830.     pl_muteki = 0
  831.     # アイテムの効果を無効
  832.     item_effect_off()
  833. # ******************** ゲームの初期配置/設定 ********************
  834. def init_game_place():
  835.     global pl_x, pl_y
  836.     global emy_d, emy_x, emy_y, emy_max, emy_num_max, emy_time
  837.     global item_n, item_max, item_generate_time
  838.     global goal_f
  839.     # 敵
  840.     emy_max = maze_num // 5 # 敵の最大数
  841.     emy_num_max = False # 敵が最大数いるか(初期時はいない)
  842.     emy_time = FPS * 20 # 敵を再生成するまでの時間
  843.     init_enemy() # 敵の初期化
  844.     # アイテム
  845.     item_max = maze_num // 5 # アイテムの最大数
  846.     item_generate_time = FPS * 60 # アイテムを再生成するまでの時間
  847.     # プレイヤーの配置
  848.     while True:
  849.         pl_x = random.randint(1, maze_num - 2)
  850.         pl_y = random.randint(1, maze_num - 2)
  851.         if maze[pl_y][pl_x] == ROAD:
  852.             break
  853.     # 敵の配置
  854.     for i in range(maze_num // 10):
  855.         bring_enemy()
  856.     # ゴールの配置
  857.     set_target(GOAL)
  858.     goal_f = True
  859.     # アイテムの配置
  860.     for n in range(maze_num // 10):
  861.         set_target(ITEM)
  862.     # コインの配置
  863.     for y in range(maze_num):
  864.         for x in range(maze_num):
  865.             if maze[y][x] == ROAD:
  866.                 maze[y][x] = COIN
  867. # ============================================================
  868. # MAIN
  869. # ============================================================
  870. # ******************** メインループ ********************
  871. def main():
  872.     global idx, tmr, course
  873.     global snd_pacman_blue, snd_pacman_red, snd_pacman_yellow, snd_pacman_green, snd_pacman_brown
  874.     global snd_player_attack, snd_player_damage, snd_break_wall
  875.     global snd_arrive_goal, snd_get_coin, snd_get_item
  876.     global pl_col, pl_muteki
  877.     global item_use, item_time
  878.     # pygameモジュールの初期化 / タイトル設定
  879.     pygame.init()
  880.     pygame.display.set_caption("PAC-MAN")
  881.     # スクリーンの初期化 / クロックオブジェクト作成
  882.     screen = pygame.display.set_mode((SCREEN_SIZE + 300, SCREEN_SIZE))
  883.     clock = pygame.time.Clock()
  884.     # 効果音
  885.     snd_pacman_blue = pygame.mixer.Sound("sound/pacman_blue.mp3")
  886.     snd_pacman_red = pygame.mixer.Sound("sound/pacman_red.mp3")
  887.     snd_pacman_yellow = pygame.mixer.Sound("sound/pacman_yellow.mp3")
  888.     snd_pacman_green = pygame.mixer.Sound("sound/pacman_green.mp3")
  889.     snd_pacman_brown = pygame.mixer.Sound("sound/pacman_brown.mp3")
  890.     snd_player_attack = pygame.mixer.Sound("sound/player_attack.mp3")
  891.     snd_player_damage = pygame.mixer.Sound("sound/player_damage.mp3")
  892.     snd_break_wall = pygame.mixer.Sound("sound/break_wall.mp3")
  893.     snd_arrive_goal = pygame.mixer.Sound("sound/arrive_goal.mp3")
  894.     snd_get_coin = pygame.mixer.Sound("sound/get_coin.mp3")
  895.     snd_get_item = pygame.mixer.Sound("sound/get_item.mp3")
  896.     while True:
  897.         tmr = tmr + 1
  898.         # プログラムの終了
  899.         for event in pygame.event.get():
  900.             if event.type == pygame.QUIT:
  901.                 pygame.quit()
  902.                 sys.exit()
  903.         # スクリーン / キー入力
  904.         screen.fill(BLACK)
  905.         key = pygame.key.get_pressed()
  906.         # タイトル
  907.         if idx == 0:
  908.             # 音楽をかける
  909.             if tmr == 1:
  910.                 pygame.mixer.music.load("music/Stellar_Wind-Unicorn_Heads.mp3")
  911.                 pygame.mixer.music.play(-1)
  912.             screen.fill(WHITE)
  913.             if key[pygame.K_SPACE] == 1:
  914.                 # 音楽をかける
  915.                 pygame.mixer.music.load("music/Zoom_Vibe_Tracks.mp3")
  916.                 pygame.mixer.music.play(-1)
  917.                 # ゲームの初期化
  918.                 init_game()
  919.                 idx = 1
  920.                 tmr = 0
  921.             draw_text(screen, "PUSH [ SPACE ] TO START", (SCREEN_SIZE + 300) / 2, SCREEN_SIZE / 2, 80, BLACK, True)
  922.         # ゲームプレイ
  923.         elif idx == 1:
  924.             # 迷路の生成/ゲームの初期配置
  925.             if tmr == 1:
  926.                 course += 1
  927.                 make_maze()
  928.                 init_game_place()
  929.             # プレイ中
  930.             else:
  931.                 move_player(key) # プレイヤーの動き
  932.                 move_enemy() # 敵の動き
  933.                 use_item(key) # アイテムの使用
  934.                 hit_check() # ヒットチェック
  935.                 check_enemy_to_generate() # 敵を生成するか判定 -> 生成を行う
  936.                 check_goal_to_generate() # ゴールを生成するか判定 -> 生成を行う
  937.                 check_item_to_generate() # アイテムを生成するか判定 -> 生成を行う
  938.                 # アイテムを使用中の場合
  939.                 if item_use == True:
  940.                     item_time -= 1
  941.                     # アイテムの使用時間が切れた場合
  942.                     if item_time == 0:
  943.                         item_effect_off()
  944.                 # プレイヤーが無敵状態の場合
  945.                 if pl_muteki > 0:
  946.                     pl_muteki -= 1
  947.                 # プレイヤーのライフがなくなるとゲームオーバー
  948.                 if pl_life <= 0:
  949.                     idx = 2
  950.                     tmr = 0
  951.                 # ゴールすると次のコースへ
  952.                 if maze[pl_y][pl_x] == GOAL:
  953.                     snd_arrive_goal.play()
  954.                     tmr = 0
  955.         # ゲームオーバー
  956.         elif idx == 2:
  957.             draw_text(screen, "GAME OVER", (SCREEN_SIZE + 300) / 2, SCREEN_SIZE / 2, 100, RED, True)
  958.             if tmr == FPS * 3:
  959.                 idx = 0
  960.                 tmr = 0
  961.         # 描画:迷路
  962.         if idx == 1 and tmr > 0:
  963.             draw_maze(screen)
  964.         pygame.display.update()
  965.         clock.tick(FPS)
  966. if __name__ == '__main__':
  967.     main()