ながみえ

一つ前のチャプターでは画面にゾンビを出現させ、銃で撃てるようにしました。

今回は ゾンビとプレイヤーの当たり判定を実装 し、ゲームオーバーを設定しましょう。

Chapter1:pygame入門|画面を表示しよう
Chapter2:簡単なノベルゲームを作ろう
Chapter3:簡単なアクションゲームを作ろう
Chapter4:ブロック崩しを作ろう
Chapter5:シューティングゲームを作ろう
 ・Chapter5-1:画面にゾンビを出現させよう
 ・Chapter5-2:ゲームオーバーを設定しよう ◁今回はここ
 ・Chapter5-3:プレイ時間を表示しよう
 ・Chapter5-4:スコアを表示しよう
Chapter6:pygameのお役立ち情報

前回の記事「Chapter5-1」では、ゾンビを出現させることでゲームらしさが一気にアップしましたね!

この章ではさらに本格的なゲームらしい要素、「ゲームオーバー」を追加します。プレイヤーがゾンビにぶつかってしまったら、ゲームが終了するようにしてみましょう。

この処理を実装することで、プレイヤーに緊張感が生まれ、より夢中になれるゲームになりますよ!

注意点

チャプター5を通してシューティングゲームを制作するにあたり、ベースとなるコードや使用する画像をまとめた「Chapter5_set.zip」を無料配布しています。

まだ入手していない人は、まずは pygameのトップページ に移動し、チャプター5の章から ダウンロード してください。

本記事は会員向けの有料記事ですが、現在は期間限定で無料公開中です。

<<前のページ

pygameの記事一覧

Pythonのゲームライブラリ pygame を使ってゲームアプリを制作するページのアイキャッチ画像

次のページ>>

ゲームオーバーの考え方

本格的なゲームにおいて、「プレイヤーがミスをしたらゲームが終了する」という仕組みは欠かせません。

たとえば敵にぶつかってしまったり、制限時間を超えてしまったりすることでゲームオーバーになるシーンを、多くのゲームで見かけると思います。

この章では、プレイヤーがゾンビにぶつかったときにゲームを終了する処理を追加していきます。

今回の目的は以下の3つです。

プレイヤーとゾンビが衝突したときに:

  1. ゲームを停止して、背景を再描画する
  2. 「GAMEOVER」という文字を画面中央に表示する
  3. リプレイ(再挑戦)できるように、エンターキーでゲームを初期状態に戻す

この3つを組み合わせることで、プレイヤーが「ゲームに失敗した」という状況を自然に感じられるようになります。

チャレンジ!

このサイトのチャプター1から順番に学習してきた人は、ゲームオーバーの追加処理 はもう何度も経験しています。

この記事ではこれまで同様 丁寧に解説しますが、それを見ずに挑戦するのもお勧めです^^

その場合は「zombie_shooting.py」に以下の内容を追加しましょう。

  • ゲームオーバー関数
  • リセット関数
  • ジャンプ関数
  • メインループ内の関数選択処理
【Python】勉強猫がノートパソコンを前にして学習を始める様子。記事内の学習スタート用イラスト

プレイヤーとゾンビの衝突を検出しよう

まず最初に取り組むのは、プレイヤーとゾンビがぶつかったときに「ゲームオーバー状態」に切り替える処理です。

これを実現するためには、pygameのRect(長方形)の当たり判定機能を使います。

pygameでは、Rectオブジェクト同士の接触を判定するために、colliderect()というメソッドが用意されています。

この関数は、あるRectが別のRectに重なっているかどうかを調べるもので、ぶつかっていたらTrue、ぶつかっていなければFalseを返してくれます。

コードを書いてみよう

「## ゲームステージ関数」の中の「# ゾンビの処理」のところに、以下のコードを書き足しましょう。

# プレイヤーとの衝突判定
if zombie.colliderect(player_rect):
    page = 2

この一文が意味しているのは、「もしゾンビとプレイヤーがぶつかったら、page変数の値を2に変更する」ということです。

つまりゾンビとプレイヤーがぶつかるとpageが2になり、このあと定義するgameover()という関数が呼び出されてゲームオーバー画面が表示される、という流れになります。

このようにして、ぶつかったらゲームを終了させるという基本的な仕組みが作られるわけです。

ゲームオーバーの画面を作ろう

プレイヤーとゾンビがぶつかったときにpageの値を2に変更する処理を追加しました。

今度は、このpage == 2の状態になったときに、実際に「ゲームオーバー画面」を表示する処理を作っていきましょう。

この処理は、gameover()という関数を定義することで実現します。

コードを書いてみよう

「## ゲームステージ関数」の下に以下のコードを書き足しましょう。

## ゲームオーバー関数
def gameover():
    screen.blit(haikei_img, (0, 0))  # 背景画像を表示
    btn1 = screen.blit(replay_img, (320, 480))  # リプレイボタン画像を表示
    font1 = pygame.font.Font(None, 150)  # フォントサイズ150で設定
    text = font1.render("GAMEOVER", True, pygame.Color("RED"))  # 「GAMEOVER」の赤い文字を描画
    screen.blit(text, (100, 200))  # テキストを画面中央に描画
    button_to_jump()  # ジャンプ関数の呼び出し

この関数が実行されるように、mainループの中でもpage == 2のときにgameover()を呼ぶ必要がありますが、それは記事の後半で詳しく見ていきます。

【Python】勉強猫がノートパソコンを見ながら考え込む様子。記事内の休憩用イラスト

リプレイ機能の実装

ゲームオーバー画面を表示できるようになったので、次は**「もう一度プレイしたい!」というプレイヤーのために、リプレイ(再挑戦)機能を実装**していきましょう。

ここで実現したいのは、「ゲームオーバー画面でEnterキーを押すと、ゲームがリセットされて最初からやり直せる」という流れです。

この処理を行うのが、次の button_to_jump() 関数です。

コードを書いてみよう

「## ゲームステージ関数」の下に以下のコードを書き足しましょう。

## ジャンプ関数
def button_to_jump():
    global page
    key = pygame.key.get_pressed()  # キーの入力状態を取得
    if key[pygame.K_RETURN]:  # もしEnterキーが押されたら
        reset()               # リセット関数の呼び出し
        page = 1              # 再びゲームプレイ画面に切り替え

pygame.key.get_pressed()を使って、現在押されているキーを調べ、K_RETURN(Enterキー)が押されていた場合に、次の2つの処理を行います。

  1. reset()関数を呼び出してゲームを最初の状態に戻す
  2. page = 1 とすることで、再びゲームプレイ状態に遷移する

このように、ゲームオーバーからシームレスに再スタートできるようになることで、プレイヤーはテンポよく何度も挑戦できるようになります。

ゲームを初期化するリセット関数

ゲームをリプレイできるようにするには、前のプレイのデータをすべてリセットし、最初の状態に戻す処理が必要です。

その役割を担うのが、reset()という関数です。

この関数ではスコアやプレイヤーの位置、ゾンビの配置、弾の位置など、プレイに関わるすべての情報を初期状態に戻します。

コードを書いてみよう

「## ゲームステージ関数」の下に以下のコードを書き足しましょう。

## リセット関数
def reset():
    global score, mx, hit, start_time, freeze_time
    score = 0             # スコアをリセット
    mx = 400              # プレイヤーの初期X座標
    # Chapter5-4でここにヒット数リセットを追加
    bullet_rect.y = -100  # 弾の位置をリセット(非表示位置へ)
    # Chapter5-3でここに時間に関するリセットを追加
    for i in range(10):
        zombies[i] = pygame.Rect(random.randint(0, 800), -100*i, 50, 50)  # ゾンビの位置を再設定

このように、ゲームのスタート地点と同じ状態に戻すことで、リプレイ時にまったく新しいゲームとして遊べるようになります。

【Python】勉強猫がコーヒーを片手にリラックスしている様子。記事内の休憩用イラスト

メインループへの追加

これまでに実装してきたゲームオーバー処理をきちんと動かすためには、メインループの中でゲームの状態を監視し、それに応じた関数を呼び出す必要があります。

すでにpageという変数を使ってゲームの状態(プレイ中、ゲームオーバーなど)を管理しているため、このpageの値に応じて処理を切り替える構文をメインループに追加しましょう。

コードを書いてみよう

「# メインループ」の中に以下のコードを書き足し(書き換え)て下さい。

while True:
    if page == 1:
        gamestage()   # ゲームプレイ中の処理
    elif page == 2:
        gameover()    # ゲームオーバー時の処理

この構造によって、ゲームの状態に応じて適切な画面を表示し続けることができます。

まとめ

今回はプレイヤーがゾンビにぶつかったときにゲームが終了する「ゲームオーバー」処理を実装しました。

ゲームを作るうえで、「ゲームに終わりがある」というのはとても大切な要素です。

それにより、プレイヤーは「失敗しないようにがんばろう」「次はもっと上手にやろう」と思えるようになります。

次回はさらに進んで、「プレイ時間の表示」に挑戦します。どれくらいの時間倒されずにゲームを続けられたかを画面に表示できるようにすることで、プレイヤーのモチベーションがさらにアップしますよ!

少しずつですが、確実にゲームが形になってきています。ここまで作り上げてきたあなたは、もう立派なpygame開発者の仲間入りです。

この調子で、次のステップも一緒に進んでいきましょう!

Q
Chapter5-2の完成コード

今回の記事での完成するコード全体は↓↓の通りです。

必要な方は開いて確認しましょう。

# 初期化(ゲームの準備をする)
import pygame, sys, random
pygame.init()
screen = pygame.display.set_mode((800, 600))
haikei_img = pygame.image.load("images/hakaba.png")
haikei_img = pygame.transform.scale(haikei_img, (800, 600))
## プレイヤーデータ
player_img = pygame.image.load("images/Player.png")
player_img = pygame.transform.scale(player_img, (60, 100))
player_rect = pygame.Rect(370, 500, 60, 100)
## 銃弾データ
bullet_img = pygame.image.load("images/bullet.png")
bullet_img = pygame.transform.scale(bullet_img, (8, 16))
bullet_rect = pygame.Rect(0, -100, 8, 16)
## ゾンビデータ
zombie_img = pygame.image.load("images/Zombie.png")
zombie_img = pygame.transform.scale(zombie_img, (60, 100))
zombies = []  # ゾンビの位置情報を入れるためのゾンビリスト
for i in range(10):
    zombie_x = random.randint(0, 800)       # 横の位置をランダムに決定
    zombie_y = -100 * i                      # 縦方向に等間隔で並べる
    zombies.append(pygame.Rect(zombie_x, zombie_y, 60, 100))  # ゾンビ1体分の情報をリストに追加
## リプレイボタンデータ
replay_img = pygame.image.load("images/replaybtn.png")
## 変数
page = 1
mx = 370
hit = 0
score = 0
start_time = pygame.time.get_ticks()  # ゲーム開始時の時間
end_time = 0  # ゲーム終了時の時間
freeze_time = False  # 時間の停止状態


# ここから各関数の定義
## ゲームステージ関数
def gamestage():
    global mx, page, hit, score, start_time
    screen.blit(haikei_img, (0, 0))
    # ユーザー入力
    key = pygame.key.get_pressed()
    # プレイヤーの処理
    if key[pygame.K_RIGHT]:
        mx += 5
    if key[pygame.K_LEFT]:
        mx -= 5
    mx = max(0, min(740, mx)) # プレイヤーが画面端から出ていかないようにする
    player_rect.x = mx
    screen.blit(player_img, player_rect)
    # 銃弾の処理
    if key[pygame.K_SPACE] and bullet_rect.y < 0:
        bullet_rect.x = player_rect.x +30 - 4
        bullet_rect.y = player_rect.y
    if bullet_rect.y >= 0:
        bullet_rect.y += -30
        screen.blit(bullet_img, bullet_rect)
    # ゾンビの処理
    for zombie in zombies:
        zombie.y += 5  # ゾンビを毎フレームごとに5ピクセル下に移動
        screen.blit(zombie_img, zombie)  # ゾンビ画像を画面に描画
        if zombie.y > 600: # もし画面下に到達したら
            zombie.x = random.randint(0, 800)
            zombie.y = -100
        # プレイヤーとの衝突判定
        if zombie.colliderect(player_rect):
            page = 2
        # 銃弾との衝突判定
        if zombie.colliderect(bullet_rect): # もしゾンビが銃弾と衝突したら
	        # ゾンビを画面外に移動
            zombie.y = -100
            zombie.x = random.randint(0, 800)
            # 弾を画面外へ移動
            bullet_rect.y = -100
    # タイムとスコアの処理


## ゲームクリア関数

## ゲームオーバー関数
def gameover():
    screen.blit(haikei_img, (0, 0))  # 背景画像を表示
    btn1 = screen.blit(replay_img, (320, 480))  # リプレイボタン画像を表示
    font1 = pygame.font.Font(None, 150)  # フォントサイズ150で設定
    text = font1.render("GAMEOVER", True, pygame.Color("RED"))  # 「GAMEOVER」の赤い文字を描画
    screen.blit(text, (100, 200))  # テキストを画面中央に描画
    button_to_jump()  # ジャンプ関数の呼び出し
## ジャンプ関数
def button_to_jump():
    global page
    key = pygame.key.get_pressed()  # キーの入力状態を取得
    if key[pygame.K_RETURN]:  # もしEnterキーが押されたら
        reset()               # リセット関数の呼び出し
        page = 1              # 再びゲームプレイ画面に切り替え
## リセット関数
def reset():
    global score, mx, hit, start_time, freeze_time
    score = 0             # スコアをリセット
    mx = 400              # プレイヤーの初期X座標
    # Chapter5-4でここにヒット数リセットを追加
    bullet_rect.y = -100  # 弾の位置をリセット(非表示位置へ)
    # Chapter5-3でここに時間に関するリセットを追加
    for i in range(10):
        zombies[i] = pygame.Rect(random.randint(0, 800), -100*i, 50, 50)  # ゾンビの位置を再設定
## タイム表示関数

## スコア表示関数


# メインループ
while True:
    if page == 1:
        gamestage()   # ゲームプレイ中の処理
    elif page == 2:
        gameover()    # ゲームオーバー時の処理

    #画面描写
    pygame.display.update()
    pygame.time.Clock().tick(60)
    #終了処理
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

<<前のページ

pygameの記事一覧

Pythonのゲームライブラリ pygame を使ってゲームアプリを制作するページのアイキャッチ画像

次のページ>>

質問用コンタクトフォーム

この記事を書くにあたりAIを活用しています。

人間の目による確認も行っていますが、もし間違い等ありましたらご指摘頂けると大変助かります。

pygame記事一覧へ戻る
Python記事一覧へ戻る

記事URLをコピーしました