Pygame Zeroでシューティングゲーム
Pythonでゲームを作ってみたいけど、何から始めればいいかわからない。そんな人にぴったりなのが「Pygame Zero」。今回は、AI(Copilot)との対話を通して、自機と敵だけのシンプルな縦シューティングゲームを作り上げた過程を紹介します。
この記事は、Python初心者でもできるようなゲーム制作を学ぶための実践記として、Copilotとのやりとりをベースに構成しています。コードの工夫や改善のポイントも含めて、読みながら一緒に学べる内容になっています。
忙しい人のために:この記事のまとめ
- Pygame Zeroは、Pythonでゲームを作る最短ルートのひとつ。
- Copilotとの対話で、ゲーム制作初心者でも完成度の高いゲームが作れる。
- 音・画像・動きの工夫で、シンプルなゲームが“化ける”。
- 自動発射や星の演出など、少しの工夫でゲーム性が大きく向上。
- 完成コード付きで、すぐに試せる!
以下のリンク先からたどれるReleasesページに、すぐにプレイできるよう必要なファイル等を一式にして置いています。
https://github.com/sueyoshiryosuke/shooting-game_on_pygamezero/releases/tag/Ver.20250830
対話の始まり:まずはシンプルな縦シューティング
私:
pygame zeroで、自機と敵1体だけの縦シューティングのコードを教えて。練習用にできるだけシンプルなコードでお願い。
Copilot:
了解!まずは基本的な構造から始めましょう。自機、敵、弾の管理、そして画面描画の流れを押さえれば、シンプルなシューティングはすぐに動きますよ。
import pgzrun
# 画面サイズ
WIDTH = 400
HEIGHT = 600
# プレイヤーと敵の初期位置
player = Actor('player', (200, 500)) # プレイヤー画像を 'player.png' に置き換え
enemy = Actor('enemy', (200, 100)) # 敵画像を 'enemy.png' に置き換え
# ゲームの更新処理
def update():
# プレイヤーの移動
if keyboard.left and player.x > 0:
player.x -= 5
if keyboard.right and player.x < WIDTH:
player.x += 5
if keyboard.up and player.y > 0:
player.y -= 5
if keyboard.down and player.y < HEIGHT:
player.y += 5
# 敵の移動
enemy.y += 2
if enemy.y > HEIGHT: # 画面の下に消えたら上に戻る
enemy.y = 0
# ゲームの描画処理
def draw():
screen.clear()
player.draw()
enemy.draw()
pgzrun.go()
必要な準備
- このコードを実行するためには、
player.pngとenemy.pngという名前の画像ファイルをimagesフォルダに入れてください。 - プレイヤーは矢印キーで自由に動きます。
- 敵は画面上部から下に向かって移動し、画面外に出ると再び上部に戻る簡単な動きをします。
次のステップ
このコードは基本的な構成なので、以下のような要素を追加して練習するのがおすすめです:
- 弾を発射する機能
- 敵に当たると得点が増える仕組み
- ライフやゲームオーバーの処理
シンプルながら実験しやすいコードなので、ぜひカスタマイズして楽しんでみてください!他に相談したいことがあれば、いつでもどうぞ。 🚀🎮
改善の連続:音を入れるとゲームは“化ける”
私:
BGMの音量調整できる?
効果音の音量も設定したいな。どんな音声ファイルを使っているか、バラバラにならないように管理したい。
Copilot:
もちろんできます!set_volume()で音量調整可能ですし、音声ファイルは辞書で管理するとスッキリします。音が入ると、ゲームの印象がガラッと変わりますよ。
星の演出で宇宙感を出す
私:
宇宙空間を飛んでいるように、複数の星の輝き(1ピクセル)が上から下へ流れる感じにしたい。
Copilot:
それ、めちゃくちゃ良い演出です!星をリストで管理して、ランダムな位置と速度で流すようにすれば、宇宙感が一気に出ます。
敵の動きにランダム性を加える
私:
敵が端に行ったときしか左右を反転させなくなったの?端に行った以外にも、ランダムにしてたよね?
Copilot:
確かに!ランダム反転を復活させるには、random.random() < 0.02 などで確率的に方向を変える処理を追加すればOKです。
敵が増えると星が速くなる
私:
敵が増えるごとに、星の動きを速くしたい。
Copilot:
ゲームの緊張感が増す良いアイデアです!敵追加のタイミングで star_speed += 1 を入れれば、星の流れも加速して宇宙が“荒れてくる”感じになります。
星のサイズと色をランダムに
私:
星の大きさを一回り大きくしたい。縦横を1~3でランダムにするのはどうかな?
あと、(200, 200, 255)って青っぽい光?
Copilot:
そう、それは淡い青の輝きです!星のサイズをランダムにして、色も白・赤・青などにすると、画面が一気に幻想的になります。
弾の色と発射方法の工夫
私:
自機の弾の色だよね?white(白)以外に、どんな色が設定できるの?
スペースキーで弾を発射しているけど、やっぱり自動で発射するように変更したい。
Copilot:
色は 'red', 'cyan', (255, 165, 0) など自由に設定できます。自動発射は clock.schedule_interval() を使えば簡単に実装できますよ!
最終コードと完成の喜び
私:
最終的に、以下にしたよ。
import os
import random
import pgzrun
# ウィンドウの位置を設定(スクリーン中央に配置)
os.environ['SDL_VIDEO_CENTERED'] = '1'
# 画面サイズ
WIDTH = 600
HEIGHT = 900
# プレイヤーの初期設定
player = Actor('player', (200, 800)) # プレイヤー画像を 'player.png' に置き換え
# 敵のリスト
enemies = [Actor('enemy', (random.randint(0, WIDTH), 100))] # 初期敵は1体
# 弾のリスト
bullets = []
# 星のリストを作成(星50個。幅と高さをランダムに設定)
stars = [{"x": random.randint(0, WIDTH), "y": random.randint(0, HEIGHT), "width": random.randint(1, 2), "height": random.randint(1, 2)} for _ in range(50)]
# 星が下に動く速度を管理する変数。数字が増えると星の動きが速くなる。
star_speed = 2 # 初期速度
# スコアを初期化
score = 0
# ゲームオーバーフラグ
game_over = False
# 敵の左右移動用フラグ
enemy_directions = [random.choice([-1, 1])]
# 追加された敵の数を追跡
added_enemies = 0
# ゲームの更新処理
def update():
global game_over, score, added_enemies, star_speed
if game_over:
return # ゲームオーバー時は何もしない
# 星の移動
for star in stars:
star["y"] += star_speed # 星の移動速度を反映
if star["y"] > HEIGHT: # 画面下に到達したら再び上部に戻る
star["y"] = 0
star["x"] = random.randint(0, WIDTH) # ランダムなX座標
# プレイヤーの移動
if keyboard.left and player.x > 0:
player.x -= 5
if keyboard.right and player.x < WIDTH:
player.x += 5
# 弾の移動
for bullet in bullets:
bullet['y'] -= 10
if bullet['y'] < 0:
bullets.remove(bullet)
# 敵の移動
for i, enemy in enumerate(enemies):
enemy.y += 2
if enemy.y > HEIGHT: # 下に到達したら上部に戻る
enemy.y = 0
enemy.x = random.randint(0, WIDTH)
# 左右移動
enemy.x += enemy_directions[i] * 3
if enemy.x <= 0 or enemy.x >= WIDTH: # 画面端で方向を反転
enemy_directions[i] *= -1
# ランダムに左右を反転
if random.random() < 0.02: # 一定の確率で反転
enemy_directions[i] *= -1
# プレイヤーと敵の衝突判定
if player.colliderect(enemy):
sounds.crash.play() # 衝突時の効果音を再生
game_over = True
# 弾と敵の衝突判定
for bullet in bullets:
for i, enemy in enumerate(enemies):
if enemy.colliderect(Rect((bullet['x'], bullet['y']), (5, 10))):
bullets.remove(bullet)
enemy.y = 0 # 敵を上部に戻す
enemy.x = random.randint(0, WIDTH)
enemy_directions[i] = random.choice([-1, 1]) # ランダムな移動方向に変更
score += 1 # スコア加算
# 敵を倒したときの音
sounds.hit.play()
break
# 敵を増やす(3体倒すごとに1体追加。敵の数の上限あり)
# スコアから計算される段階が上がったら敵を追加
if score // 3 > added_enemies and added_enemies < 15 :
new_enemy = Actor('enemy', (random.randint(0, WIDTH), 0)) # 新しい敵を追加
enemies.append(new_enemy)
enemy_directions.append(random.choice([-1, 1])) # 新しい敵の移動方向を追加
added_enemies += 1 # 追加された敵の数を更新
# 敵が増えるたびに星の速度を上げる(速度上限あり)
if star_speed < added_enemies:
star_speed += 1
# 弾を発射する処理を関数に分離
def fire_bullet():
if not game_over: # ゲームオーバー中は発射しない
bullets.append({'x': player.x, 'y': player.y - 20}) # 弾を追加
sounds.shoot.play() # 弾発射音を再生
# ゲームの描画処理
def draw():
screen.clear()
# 星を描画
# 3色(白、赤、青)で、ランダムなサイズのピクセルで描画
for star in stars:
color = random.choice([(255, 255, 255), (255, 200, 200), (200, 200, 255)])
screen.draw.filled_rect(Rect((star["x"], star["y"]), (star["width"], star["height"])), color) # ランダムなサイズで描画
if game_over:
# ゲームオーバー画面
screen.draw.text("GAME OVER", center=(WIDTH // 2, HEIGHT // 2), fontsize=60, color="red")
screen.draw.text(f"SCORE: {score}", center=(WIDTH // 2, HEIGHT // 2 + 50), fontsize=40, color="white")
sounds.bgm.stop() # ゲームオーバー時にBGMを停止
else:
# ゲーム画面
player.draw()
for enemy in enemies:
enemy.draw()
for bullet in bullets:
screen.draw.filled_rect(Rect((bullet['x'], bullet['y']), (5, 10)), 'cyan')
# スコア表示(左上)
screen.draw.text(f"SCORE: {score}", topleft=(10, 10), fontsize=30, color="white")
# 自動発射のタイマーを設定
clock.schedule_interval(fire_bullet, 0.25) # 何秒ごとに弾を発射するか
# 効果音の音量設定
sounds.shoot.set_volume(0.3) # 弾の発射音
sounds.hit.set_volume(0.2) # 敵を倒した音
sounds.crash.set_volume(0.3) # ゲームオーバー音
# BGMの音量調整と再生
sounds.bgm.set_volume(0.1) # 音量を設定
sounds.bgm.play(-1) # -1はループ再生を意味します
# Pygame Zeroのメインループを開始
pgzrun.go()
Copilot:
これは素晴らしい仕上がりです!音・演出・操作性がバランスよく整っていて、初心者とは思えない完成度です。
Copilotが間違えたかも?と思ったら
Pygame Zero用のコードをお願いしても、たまにPygame用のコードが出てくることがあります。
でも、初心者がその違いを全部覚える必要はありません。
まずは「動かない」ときにこう考えてみよう
- 「このコード、Pygame Zeroじゃなくて、Pygame用かも?」とCopilotに聞いてみる
- 「Pygame Zeroでは自動で画面が出るはずなのに、なんか設定が多すぎるな…」と違和感を持つ
- エラーが出たら、“自分が悪い”と思う前に、Copilotのコードを疑ってみる
まとめ:シンプルでも“化ける”ゲームは作れる
私:
思ったよりもいい感じになった。音と画像が入ると、ゲームは化けるね。
ちなみに、このシンプルなシューティングの良い点は何かな?褒めてほしいね。
Copilot:
もちろん!操作の心地よさ、視覚演出、音の没入感、そして進化する難易度。どれも素晴らしいです。あなたの工夫が詰まった、魅力的なゲームです!
Pygame Zeroは、AI時代の“学びの入り口”
私:
でも、Pygame Zeroって、思っているよりもコードが簡単な気がする。すごいね。
Copilot:
まさにその通り!Pygame Zeroは、Pythonでゲームを作る最短ルート。AIと組み合わせれば、初心者でも驚くほど完成度の高いゲームが作れます。
最後に
私:
ありがと!コードを読んで勉強するよ。
Copilot:
こちらこそありがとう!この経験が、あなたの次の創作の一歩になりますように。またいつでも相談してくださいね!
最後までお読みいただきありがとうございました。
この記事が少しでもお役に立ちましたら、今後の励みになりますので『いいね』をいただけると嬉しいです!
