【Python】パックマン風スネークゲームを作ろう メモ帳でプログラミング

GAME工場

パックスネークゲーム

今回の記事は以前作成しました「【C#】パックマン風スネークゲームを作ろう メモ帳でプログラミング」のPython版を作成します。用意する画像は不要です。プログラミングでパックマンやエサやスコア表示を描画します。コード全文ご紹介しますのでぜひ昔懐かしのレトロ風ゲームで遊んでみてください!

遊び方

プログラムを実行するとスタート画面が表示されます。

ゲームがスターとすると中央にパックマンが止まったまま表示されます。
キー操作は「↑」「→」「↓」「←」でパックマンを移動させます。
なにかキーをクリックするとパックマンがその方向に進みゲームが開始されます。
大きいエサを食べるとパックマンが後ろに増えていきます。
小さいエサを全部食べるとラウンドクリアです。次のラウンドに進むたびに小さいエサが増えていきます。
パックマンが画面四方の壁に激突するか自分自身にぶつかるとゲームオーバーです。
ゲームオーバすると「REPLAY」ボタンがクリックでるようになりクリックするとゲームが最初から開始されます。

準備

pythonはスクリプト言語ですのでコンパイルは行いません。プログラムを一行一行逐次筆耕します。それではPythonがインストールされているフォルダに移動します。
次にプログラム実行に必要なライブラリをインストールします。次のコマンドを実行しインストールします。「pip install pygame」

このように表示されたらインストールは成功です。

randomとsysは標準ライブラリなのでインストール不要です。

今のフォルダ内にメモ帳で「pacsnake.py」という名前のファイルを作成し次の全文コードをコピーしペーストします。

「py pacSnake.py」コマンドを実行をするとゲーム画面が表示されます。

全コード

下記がプログラムの全コードです。コードの詳細説明はしませんがコメントアウトで簡単に処理の説明を記述してあります。

import pygame
import random
import sys

# 定数
SIZE = 24
WIDTH = 26
HEIGHT = 26
SCORE_WIDTH = SIZE * 7
TIMER = 150
MINIFOOD = 30

# 色
BLACK = (0, 0, 0)
YELLOW = (255, 255, 0)
CYAN = (0, 255, 255)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GRAY = (128, 128, 128)

# 初期化
pygame.init()
screen = pygame.display.set_mode((SIZE * WIDTH + SCORE_WIDTH, SIZE * HEIGHT + SIZE * 2))
pygame.display.set_caption(“PACSNAKE”)
clock = pygame.time.Clock()
font = pygame.font.SysFont(“meiryo”, 18)
big_font = pygame.font.SysFont(“meiryo”, 40)

# リプレイボタン
button_rect = pygame.Rect(SIZE * WIDTH + SIZE, SIZE * 10, SIZE * 5, SIZE * 2)

def reset_game():
global mapX, mapY, mapDX, mapDY, pacBody, miniFoods, restFoods, getFoods, roundNum
global mapFoodX, mapFoodY, gameFlag, mouth_open

mapX, mapY = WIDTH // 2, HEIGHT // 2
mapDX, mapDY = 0, 0
pacBody = [(mapX, mapY)]
miniFoods = []
restFoods = MINIFOOD
getFoods = 0
roundNum = 1
gameFlag = True
mouth_open = True
mapFoodX, mapFoodY = add_big_food()

for _ in range(MINIFOOD):
add_mini_food()

def add_big_food():
return random.randint(0, WIDTH – 2), random.randint(0, HEIGHT – 2)

def add_mini_food():
while True:
x = random.randint(0, WIDTH – 1)
y = random.randint(0, HEIGHT – 1)
if (x, y) not in miniFoods and (x, y) != (mapFoodX, mapFoodY):
miniFoods.append((x, y))
break

# 口アニメーション用フラグ
mouth_open = True
frame_count = 0

def draw_pacman(x, y, dx, dy, open_mouth=True):
center = (x * SIZE + SIZE // 2, y * SIZE + SIZE // 2)
radius = SIZE // 2

if dx == 0 and dy == 0 or not open_mouth:
pygame.draw.circle(screen, YELLOW, center, radius)
return

if dx == 1: # 右
start_angle, end_angle = 30, 330
elif dx == -1: # 左
start_angle, end_angle = 210, 150
elif dy == 1: # 下
start_angle, end_angle = 300, 240
elif dy == -1: # 上
start_angle, end_angle = 120, 60
else:
pygame.draw.circle(screen, YELLOW, center, radius)
return

rect = pygame.Rect(center[0] – radius, center[1] – radius, radius * 2, radius * 2)
pygame.draw.arc(screen, BLACK, rect, start_angle * 3.14 / 180, end_angle * 3.14 / 180, 3)
pygame.draw.circle(screen, YELLOW, center, radius)
pygame.draw.polygon(screen, BLACK, [center,
(center[0] + radius * pygame.math.Vector2(1, 0).rotate(-start_angle).x,
center[1] + radius * pygame.math.Vector2(1, 0).rotate(-start_angle).y),
(center[0] + radius * pygame.math.Vector2(1, 0).rotate(-end_angle).x,
center[1] + radius * pygame.math.Vector2(1, 0).rotate(-end_angle).y)])

def draw_game():
screen.fill(BLACK)

# 壁の描画
pygame.draw.rect(screen, CYAN, (0, 0, SIZE * WIDTH, SIZE // 6))
pygame.draw.rect(screen, CYAN, (0, 0, SIZE // 6, SIZE * HEIGHT))
pygame.draw.rect(screen, CYAN, (0, SIZE * HEIGHT, SIZE * WIDTH, SIZE // 6))
pygame.draw.rect(screen, CYAN, (SIZE * WIDTH, 0, SIZE // 6, SIZE * HEIGHT))

# ミニエサ
for fx, fy in miniFoods:
pygame.draw.circle(screen, WHITE, (fx * SIZE + SIZE // 2, fy * SIZE + SIZE // 2), SIZE // 6)

# 大エサ
pygame.draw.circle(screen, YELLOW, (mapFoodX * SIZE + SIZE // 2, mapFoodY * SIZE + SIZE // 2), SIZE // 3)

# パックマンの体
for i, (x, y) in enumerate(pacBody[1:]):
pygame.draw.circle(screen, YELLOW, (x * SIZE + SIZE // 2, y * SIZE + SIZE // 2), SIZE // 2)

# パックマンの頭(口つき)
draw_pacman(mapX, mapY, mapDX, mapDY, open_mouth=mouth_open)

# スコア
screen.blit(font.render(f”ROUND {roundNum}”, True, YELLOW), (SIZE * WIDTH + WIDTH, SIZE * 1))
screen.blit(font.render(f”PACBODY {len(pacBody)}”, True, YELLOW), (SIZE * WIDTH + WIDTH, SIZE * 3))
screen.blit(font.render(f”GETFOOD {getFoods}”, True, YELLOW), (SIZE * WIDTH + WIDTH, SIZE * 4))
screen.blit(font.render(f”RESTFOOD {restFoods}”, True, YELLOW), (SIZE * WIDTH + WIDTH, SIZE * 6))

if not gameFlag:
screen.blit(big_font.render(“GAME OVER”, True, RED), (SIZE * WIDTH // 2 – 80, SIZE * HEIGHT // 2 – 20))
pygame.draw.rect(screen, GRAY, button_rect)
screen.blit(font.render(“REPLAY”, True, BLACK), (button_rect.x + 20, button_rect.y + 10))

pygame.display.update()

# ゲーム初期化
reset_game()

# メインループ
while True:
clock.tick(1000 // TIMER)
frame_count += 1
mouth_open = (frame_count % 4 < 2) # 口の開閉アニメーション for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() elif event.type == pygame.KEYDOWN and gameFlag: if event.key == pygame.K_LEFT and mapDX == 0: mapDX, mapDY = -1, 0 elif event.key == pygame.K_RIGHT and mapDX == 0: mapDX, mapDY = 1, 0 elif event.key == pygame.K_UP and mapDY == 0: mapDX, mapDY = 0, -1 elif event.key == pygame.K_DOWN and mapDY == 0: mapDX, mapDY = 0, 1 elif event.type == pygame.MOUSEBUTTONDOWN and not gameFlag: if button_rect.collidepoint(event.pos): reset_game() if gameFlag: mapX += mapDX mapY += mapDY if mapX < 0 or mapX >= WIDTH or mapY < 0 or mapY >= HEIGHT:
gameFlag = False

if (mapX, mapY) in pacBody[1:]:
gameFlag = False

if (mapX, mapY) == (mapFoodX, mapFoodY):
pacBody.insert(0, (mapX, mapY))
mapFoodX, mapFoodY = add_big_food()
else:
pacBody.pop()
pacBody.insert(0, (mapX, mapY))

for f in miniFoods:
if (mapX, mapY) == f:
miniFoods.remove(f)
getFoods += 1
restFoods -= 1
break

if restFoods == 0:
roundNum += 1
restFoods = MINIFOOD * roundNum
for _ in range(restFoods):
add_mini_food()

draw_game()

まとめ

いかがだったでしょうか。このようにPythonでミニゲームがつくることができました。今回のプログラムはC#で作成したプログラムを移植して作成してみました。皆さんも他のミニゲームをPythonで作ってみましょう!

コメント