一つ前のチャプターでは画面にゾンビを出現させ、銃で撃てるようにしました。
今回は ゾンビとプレイヤーの当たり判定を実装 し、ゲームオーバーを設定しましょう。
Chapter1:pygame入門|画面を表示しよう
Chapter2:簡単なノベルゲームを作ろう
Chapter3:簡単なアクションゲームを作ろう
Chapter4:ブロック崩しを作ろう
Chapter5:シューティングゲームを作ろう
・Chapter5-1:画面にゾンビを出現させよう
・Chapter5-2:ゲームオーバーを設定しよう ◁今回はここ
・Chapter5-3:プレイ時間を表示しよう
・Chapter5-4:スコアを表示しよう
Chapter6:pygameのお役立ち情報
前回の記事「Chapter5-1」では、ゾンビを出現させることでゲームらしさが一気にアップしましたね!
この章ではさらに本格的なゲームらしい要素、「ゲームオーバー」を追加します。プレイヤーがゾンビにぶつかってしまったら、ゲームが終了するようにしてみましょう。
この処理を実装することで、プレイヤーに緊張感が生まれ、より夢中になれるゲームになりますよ!
本記事は会員向けの有料記事ですが、現在は期間限定で無料公開中です。
ゲームオーバーの考え方
本格的なゲームにおいて、「プレイヤーがミスをしたらゲームが終了する」という仕組みは欠かせません。
たとえば敵にぶつかってしまったり、制限時間を超えてしまったりすることでゲームオーバーになるシーンを、多くのゲームで見かけると思います。
この章では、プレイヤーがゾンビにぶつかったときにゲームを終了する処理を追加していきます。
今回の目的は以下の3つです。
プレイヤーとゾンビが衝突したときに:
- ゲームを停止して、背景を再描画する
- 「GAMEOVER」という文字を画面中央に表示する
- リプレイ(再挑戦)できるように、エンターキーでゲームを初期状態に戻す
この3つを組み合わせることで、プレイヤーが「ゲームに失敗した」という状況を自然に感じられるようになります。
プレイヤーとゾンビの衝突を検出しよう
まず最初に取り組むのは、プレイヤーとゾンビがぶつかったときに「ゲームオーバー状態」に切り替える処理です。
これを実現するためには、pygameのRect
(長方形)の当たり判定機能を使います。
pygameでは、Rect
オブジェクト同士の接触を判定するために、colliderect()
というメソッドが用意されています。
この関数は、あるRect
が別のRect
に重なっているかどうかを調べるもので、ぶつかっていたらTrue、ぶつかっていなければFalseを返してくれます。
この一文が意味しているのは、「もしゾンビとプレイヤーがぶつかったら、page
変数の値を2に変更する」ということです。
つまりゾンビとプレイヤーがぶつかるとpage
が2になり、このあと定義するgameover()
という関数が呼び出されてゲームオーバー画面が表示される、という流れになります。
このようにして、ぶつかったらゲームを終了させるという基本的な仕組みが作られるわけです。
ゲームオーバーの画面を作ろう
プレイヤーとゾンビがぶつかったときにpage
の値を2に変更する処理を追加しました。
今度は、このpage == 2
の状態になったときに、実際に「ゲームオーバー画面」を表示する処理を作っていきましょう。
この処理は、gameover()
という関数を定義することで実現します。
この関数が実行されるように、mainループ
の中でもpage == 2
のときにgameover()
を呼ぶ必要がありますが、それは記事の後半で詳しく見ていきます。
リプレイ機能の実装
ゲームオーバー画面を表示できるようになったので、次は**「もう一度プレイしたい!」というプレイヤーのために、リプレイ(再挑戦)機能を実装**していきましょう。
ここで実現したいのは、「ゲームオーバー画面でEnterキーを押すと、ゲームがリセットされて最初からやり直せる」という流れです。
この処理を行うのが、次の button_to_jump()
関数です。
pygame.key.get_pressed()
を使って、現在押されているキーを調べ、K_RETURN
(Enterキー)が押されていた場合に、次の2つの処理を行います。
reset()
関数を呼び出してゲームを最初の状態に戻すpage = 1
とすることで、再びゲームプレイ状態に遷移する
このように、ゲームオーバーからシームレスに再スタートできるようになることで、プレイヤーはテンポよく何度も挑戦できるようになります。
ゲームを初期化するリセット関数
ゲームをリプレイできるようにするには、前のプレイのデータをすべてリセットし、最初の状態に戻す処理が必要です。
その役割を担うのが、reset()
という関数です。
この関数ではスコアやプレイヤーの位置、ゾンビの配置、弾の位置など、プレイに関わるすべての情報を初期状態に戻します。
このように、ゲームのスタート地点と同じ状態に戻すことで、リプレイ時にまったく新しいゲームとして遊べるようになります。
メインループへの追加
これまでに実装してきたゲームオーバー処理をきちんと動かすためには、メインループの中でゲームの状態を監視し、それに応じた関数を呼び出す必要があります。
すでにpage
という変数を使ってゲームの状態(プレイ中、ゲームオーバーなど)を管理しているため、このpage
の値に応じて処理を切り替える構文をメインループに追加しましょう。
この構造によって、ゲームの状態に応じて適切な画面を表示し続けることができます。
まとめ
今回はプレイヤーがゾンビにぶつかったときにゲームが終了する「ゲームオーバー」処理を実装しました。
ゲームを作るうえで、「ゲームに終わりがある」というのはとても大切な要素です。
それにより、プレイヤーは「失敗しないようにがんばろう」「次はもっと上手にやろう」と思えるようになります。
次回はさらに進んで、「プレイ時間の表示」に挑戦します。どれくらいの時間倒されずにゲームを続けられたかを画面に表示できるようにすることで、プレイヤーのモチベーションがさらにアップしますよ!
少しずつですが、確実にゲームが形になってきています。ここまで作り上げてきたあなたは、もう立派なpygame開発者の仲間入りです。
この調子で、次のステップも一緒に進んでいきましょう!
- 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()
質問用コンタクトフォーム
この記事を書くにあたりAIを活用しています。
人間の目による確認も行っていますが、もし間違い等ありましたらご指摘頂けると大変助かります。