5. 今回のまとめと完成コード
今回は、自機と敵の当たり判定、そしてゲームの状態を管理する「ゲームオーバーフラグ」について学びました。
game_over というフラグ変数を導入し、ゲームの状態を管理しました。
update() 関数内で自機と敵の当たり判定を行い、衝突したら game_over フラグを True にしました。
update() 関数と draw() 関数の冒頭で game_over フラグをチェックし、True の場合はその後の処理を return でスキップするようにしました。
draw() 関数でゲームオーバー時の専用画面とスコア表示を実装しました。
ゲームの状態を管理するフラグの概念は、ゲーム開発だけでなく、様々なプログラミングで応用できる大切な考え方です。
ぜひ実際にコードを動かして、ゲームオーバーを体験してみてください!
豆知識
今はゲームオーバーになったらリスタートできませんが、今後のステップで「タイトル画面に戻る」「もう一度プレイする」といった機能を追加すると、より本格的なゲームになります。これは game_over フラグを False に戻したり、ゲームの状態を初期化したりすることで実現できます。
3-7_game_over.py
import pyxel
import random
# =========================================================
# ASTRO SURVIVOR
# - 宇宙シューティングゲーム -
# =========================================================
# --- 定数設定 ---
SCREEN_WIDTH = 160
SCREEN_HEIGHT = 120
GAME_TITLE = "ASTRO SURVIVOR"
STAR_COUNT = 40
# キャラクターのサイズ
PLAYER_W = 8
PLAYER_H = 8
PLAYER_SPEED = 3
ENEMY_W = 8 # この行を追加
ENEMY_H = 8 # この行を追加
# 色の定義
COL_BLACK = 0
COL_NAVY = 1
COL_PURPLE = 2
COL_GREEN = 3
COL_BROWN = 4
COL_DBLUE = 5
COL_LBLUE = 6
COL_WHITE = 7
COL_RED = 8
COL_ORANGE = 9
COL_YELLOW = 10
COL_L_GREEN = 11
COL_CYAN = 12
COL_GRAY = 13
COL_PINK = 14
COL_PEACH = 15
# --- Pyxelの初期化と音の定義 ---
pyxel.init(SCREEN_WIDTH, SCREEN_HEIGHT, title=GAME_TITLE)
# --- 変数の初期化 ---
# プレイヤー
player_x = SCREEN_WIDTH // 2 - PLAYER_W // 2
player_y = SCREEN_HEIGHT - 20
# ゲームオブジェクト
bullets = [] # [x, y, vx, vy]
enemies = [] # Dictionary {'x', 'y', 'type', ...}
stars = [] # [x, y, speed]
# 星空の準備
for _ in range(STAR_COUNT):
stars.append([
random.randint(0, SCREEN_WIDTH),
random.randint(0, SCREEN_HEIGHT),
random.randint(1, 3)
])
# ゲーム進行状況
score = 0
game_over = False
# =========================================================
# 関数定義 (エフェクト生成など)
# =========================================================
# 敵を出現させる
def spawn_enemy():
enemies.append({
'x': random.randint(0, SCREEN_WIDTH - ENEMY_W),
'y': -10,
'vx': 0,
'vy': 1.0,
'hp': 1,
'w': ENEMY_W, 'h': ENEMY_H,
'score': 10
})
# 矩形同士の当たり判定
def check_collision(x1, y1, w1, h1, x2, y2, w2, h2):
return (x1 < x2 + w2 and x1 + w1 > x2 and
y1 < y2 + h2 and y1 + h1 > y2)
# =========================================================
# メインループ (Update & Draw)
# =========================================================
# 毎フレーム実行される更新処理 (計算などはここで行う。描画は禁止)
def update():
global player_x, player_y, score, game_over
global bullets, enemies
# --- 1. ゲームオーバー / クリアチェック ---
if game_over:
return
# --- 3. プレイヤー操作 ---
if pyxel.btn(pyxel.KEY_LEFT): player_x = max(player_x - PLAYER_SPEED, 0)
if pyxel.btn(pyxel.KEY_RIGHT): player_x = min(player_x + PLAYER_SPEED, SCREEN_WIDTH - PLAYER_W)
if pyxel.btn(pyxel.KEY_UP): player_y = max(player_y - PLAYER_SPEED, 0)
if pyxel.btn(pyxel.KEY_DOWN): player_y = min(player_y + PLAYER_SPEED, SCREEN_HEIGHT - PLAYER_H)
# 弾の発射
if pyxel.btnp(pyxel.KEY_SPACE):
bullets.append([player_x + 3, player_y - 4, 0, -5])
# --- 4. オブジェクト更新 ---
# 弾の移動
surviving_bullets = []
for b in bullets:
b[0] += b[2] # vx
b[1] += b[3] # vy
# 画面外でなければ残す
if b[1] >= -10 and b[0] >= -10 and b[0] <= SCREEN_WIDTH + 10:
surviving_bullets.append(b)
bullets = surviving_bullets
# 敵の出現
if pyxel.frame_count % 30 == 0:
spawn_enemy()
# 敵の更新
surviving_enemies = []
for e in enemies:
e['y'] += e['vy']
if e['y'] > SCREEN_HEIGHT:
continue
hit_w = ENEMY_W
if check_collision(player_x, player_y, PLAYER_W, PLAYER_H, e['x'], e['y'], hit_w, hit_w):
game_over = True
hit = False
for b_idx in reversed(range(len(bullets))):
bx, by = bullets[b_idx][0], bullets[b_idx][1]
if (e['x'] < bx < e['x'] + ENEMY_W and
e['y'] < by < e['y'] + ENEMY_H):
del bullets[b_idx]
hit = True
break
if hit:
score += e['score']
continue
surviving_enemies.append(e)
enemies = surviving_enemies
# 毎フレーム実行される描画処理 (結果を画面に表示する。計算はしない)
def draw():
pyxel.cls(COL_BLACK)
# 背景
for star in stars:
pyxel.pset(star[0], star[1], COL_WHITE if star[2] > 1 else COL_GRAY)
# ゲームオーバー
if game_over:
pyxel.text(55, 50, "GAME OVER", COL_RED)
pyxel.text(45, 60, f"SCORE: {score}", COL_WHITE)
return
# プレイヤー
pyxel.rect(player_x, player_y, PLAYER_W, PLAYER_H, COL_ORANGE)
pyxel.rect(player_x+3, player_y-2, 2, 2, COL_YELLOW)
# 弾
for b in bullets:
pyxel.rect(b[0], b[1], 2, 4, COL_L_GREEN)
# 敵
for e in enemies:
pyxel.rect(e['x'], e['y'], e['w'], e['h'], COL_GRAY)
pyxel.rect(e['x']+2, e['y']+2, 4, 4, COL_CYAN)
# UI
pyxel.text(5, 5, f"SCORE:{score}", COL_WHITE)
pyxel.run(update, draw)
上記のコードを実際にブラウザで動かしてみてください。
<div class="my-16 max-w-full">
<div class="bg-gradient-to-br from-purple-50 to-blue-50 border-4 border-purple-200 rounded-2xl p-6 md:p-8 shadow-xl">
<div class="flex items-center gap-3 mb-6">
<img src="/icons/icon-denkyu.png" alt="" class="w-8 h-8 flex-shrink-0" />
<h4 class="font-black text-purple-900 text-xl">実際に動かしてみよう!</h4>
</div>
<div class="bg-white rounded-xl overflow-hidden border-2 border-purple-100 shadow-inner">
<iframe
src="/dev-snapshots/run/3-7_game_over"
class="w-full aspect-[4/3] border-0"
title="Pyxel Game: 3-7_game_over.py"
loading="lazy"
></iframe>
</div>
<p class="text-sm text-purple-700 font-bold mt-4 text-center">
矢印キーで自機を操作します。
敵に当たるとゲームオーバーです。

最後まで読んでくれてありがとう!🌱
ノートみたいに、いつでも見返してね。