一つ前のページでは画面に敵を配置する方法について学習しました。
今回は ゲームオーバーの設定方法 について見ていきましょう。
Chapter1:pygame入門|画面を表示しよう
Chapter2:簡単なノベルゲームを作ろう
Chapter3:簡単なアクションゲームを作ろう
・Chapter3-1:衝突判定に基本を理解しよう
・Chapter3-2:画面に敵を配置しよう
・Chapter3-3:ゲームオーバーを設定しよう ◁今回はここ
・Chapter3-4:ゲームクリアを設定しよう
・Chapter3-5:追跡してくる敵を実装しよう
Chapter4:ブロック崩しを作ろう
Chapter5:シューティングゲームを作ろう
Chapter6:pygameのお役立ち情報
前回の記事では、ゲーム画面に敵キャラクターである犬を表示する処理を学びました。
猫が動き回る中で、画面内に配置された複数の犬が存在することで、ゲームに緊張感が生まれましたね。
今回の目標は、プレイヤーが敵にぶつかったときにゲームオーバーの画面を表示するという仕組みを作ることです。プレイヤーにとっての「失敗条件」が明確になることで、ゲームとしての完成度がさらに高まります。
ゲームオーバーになったあとの画面表示、そして再挑戦ができる仕組みもあわせて作っていきますので、一つひとつ丁寧に確認しながら進めていきましょう。
ページ状態でゲームの流れを管理しよう
これからゲームオーバー画面を作っていくうえで、「今ゲームがどの状態にあるのか」を判断する必要があります。
たとえば、以下のような状態が考えられます。
- ゲームをプレイしている状態
- 敵にぶつかってゲームオーバーになった状態
- ゴールに到達してゲームクリアした状態(※次回以降に扱います)
これらの状態を一つの変数で管理する方法として、「ページ(page)」という変数を使う方法があります。
今回のプログラムでは、以下のようにpage
という変数に数値を設定して、それによって表示を切り替えています。
page = 1 # ゲーム画面(プレイ中) page = 2 # ゲームオーバー画面 page = 3 # ゲームクリア画面(今回はまだ未使用)
このpage
の値をもとに、メインループの中で現在表示すべき画面を切り替えていく仕組みを作ることで、状態ごとの処理を明確に分けられるようになります。
このように「状態を変数で管理する」という考え方は、今後より複雑なゲームやアプリを作るときにも非常に役立ちますので、しっかりと理解しておきましょう。
敵と接触したときにゲームオーバー判定
ゲームオーバーになる条件として、今回は「猫が敵の犬にぶつかったとき」とします。
このように、プレイヤーと敵との衝突(コリジョン)を判定する処理を追加することで、ゲームに失敗条件を導入することができます。
ここで使うのは、pygame.Rect
が持つcollidelist()
というメソッドです。これは、ある矩形(四角い領域)がリスト内のどれかの矩形とぶつかっているかを調べるための便利な関数です。
このコードは猫と犬の衝突を判定し、ぶつかった場合にページを「2(ゲームオーバー画面)」に切り替える処理です。
neko_rect
: 猫のキャラクターの位置と大きさを示す矩形enemys
: 複数の犬の矩形が入っているリストcollidelist(enemys)
: 猫がリスト内のどれかの犬とぶつかっているかを調べる。衝突があればそのインデックス(0以上)が返り、なければ-1
が返る
この条件文により、猫が敵にぶつかっている場合だけ page = 2
が実行され、次のループでゲームオーバー画面に切り替わるようになります。
ゲームにおいて「敵にぶつかったらアウト」という仕組みはよく使われます。今回学んだこの方法を理解しておけば、今後さまざまなゲームに応用できるでしょう。
ゲームオーバー画面を表示する処理
猫が敵にぶつかったときに、page = 2
に切り替わるようにしました。
では、実際にページの値が「2」になったときに、どのような画面を表示するかを考えていきましょう。
今回は「GAMEOVER」と大きく表示された画面を用意し、その下にリセットボタンを置いて再挑戦できるようにします。
- reset()関数を呼び出す
ゲームオーバーになったとき、キャラクターの位置などを初期状態に戻します。(reset関数はこのあと作ります) - 背景色の設定とテキスト表示
ゲームオーバー画面であることを明確に伝えるため、中央に「GAMEOVER」という赤い文字を大きく表示します。 - リセットボタンの描画と判定
再挑戦できるように、画面下部にボタン画像(replay_img
)を表示します。
このボタンが押されたかをbutton_to_jump
関数(このあと作ります)で判定し、押されたらゲームを再開できるようにしています。
このように、見た目を変えるだけでなく、リセット処理やボタンとの連携まで一つの関数の中で行うことで、ゲームオーバー時の演出と操作性をまとめて制御できるようになります。
リセットボタンを追加しよう
前の章では、ゲームオーバー画面にリセットボタンを表示しました。
このボタンが押されたときにゲームを再開できるようにするためには、「ボタンの判定処理」が必要です。
そこで登場するのが、button_to_jump()
という関数です。
この関数はマウスでボタンがクリックされたときに、page
の値を別の画面に切り替えるために使います。
btn
はボタンの矩形(Rect)情報です。newpage
はボタンが押されたときに切り替えたいページの番号です。pushFlag
を使って、押しっぱなしによる連続判定を防ぐ工夫がされています。
この関数によって、ボタンをクリックしたタイミングだけでページが切り替わるように制御できるため、意図しない挙動を防ぐことができます。
このような仕組みを一度作っておけば、他の画面(ゲームクリア画面など)でも再利用することができ、コードの見通しも良くなります。
これらの仕組みが良く分からない人は↓↓の記事を復習しましょう。
ゲームの初期状態へ戻す方法
ゲームオーバー時やゲームクリア時に、次のプレイをスムーズに始められるようにするには、ゲーム内の各キャラクターやオブジェクトを「初期状態に戻す」必要があります。
この処理を一括で行うreset()
関数を定義しましょう。
- 猫(プレイヤー)の位置を初期地点(x=50, y=50)に戻す
- 犬(敵キャラ)の位置を横一列に再配置し、縦位置はランダムにするす。これにより、毎回違う犬の配置でプレイでき、ゲームに変化が生まれます。
- 幽霊はこの段階では未実装
このようにリセット処理をひとつの関数にまとめておくことで、ゲームオーバー時だけでなく、クリア後の再挑戦や、何らかの理由で再スタートしたいときにも再利用できます。
コードの見通しもよくなり、管理しやすくなるというメリットがあります。
メインループを改良しよう
これまでに「ゲームプレイ画面」「ゲームオーバー画面」をそれぞれ関数として用意してきました。
しかし、これらの関数は呼び出さない限り画面に表示されません。では、いつどの関数を呼び出せばよいのでしょうか?
その答えは「ページ(page)の値」によって判断することです。
メインループの中で、今のページに応じて呼び出す関数を切り替えることで、画面表示をコントロールできます。
以下のように、while True
で繰り返されるゲームのメインループ内にif文
を追加していきます。
page
が1ならgamestage()
が呼ばれ、ゲーム中の処理が行われるpage
が2に変わった瞬間からgameover()
が呼ばれ、ゲームオーバー画面になる
この仕組みによってゲームの状態を管理し、どの画面を表示するかを制御することができるようになります。
それぞれの関数の役割が明確になることで、コード全体が読みやすくなり、今後の拡張も容易になります。
まとめ
今回はゲームに「ゲームオーバー」の概念を導入し、プレイヤーが敵にぶつかったときに専用の画面が表示されるようにしました。
また、リセットボタンを押すことで再挑戦できるようにし、繰り返し遊べるゲームとしての基本的な仕組みを整えることができました。
これらを一つひとつ理解しながら組み合わせていくことで、少しずつ本格的なゲームに近づいていることを実感できたのではないでしょうか。
次回はゲームに「クリア条件」を追加し、目標にたどり着いたときの演出を実装していきます。
プレイヤーが目指すゴールがあることで、ゲームに達成感や目的が加わります。ぜひ次も楽しみにしていてください!
お疲れさまでした!
- Chapter3-3の完成コード
-
今回の記事での完成するコード全体は↓↓の通りです。
必要な方は開いて確認しましょう。
# 初期化(ゲームの準備をする) import pygame, sys, random pygame.init() screen = pygame.display.set_mode((800,600)) ## 背景画像の設定 haikei_img = pygame.image.load("images/shibafu.png") haikei_img = pygame.transform.scale(haikei_img, (800, 600)) ## プレイヤーの猫の設定 neko_imgR = pygame.image.load("images/neko.png") neko_imgR = pygame.transform.scale(neko_imgR, (50,50)) neko_imgL = pygame.transform.flip(neko_imgR, True, False) neko_rect = pygame.Rect(50,50,50,50) # 猫のRect ## 敵の犬の設定 enemy_img = pygame.image.load("images/inu.png") # 犬の画像を読み込む enemy_img = pygame.transform.scale(enemy_img, (50, 50)) # 画像サイズを50x50ピクセルに変更 enemys = [] # 犬の位置情報を格納する空のリストを作る for i in range(13): # 13体の敵を生成 wx = 100 + i * 50 # 横方向に等間隔で配置 wy = random.randint(20, 550) # 縦の位置はランダムに enemys.append(pygame.Rect(wx, wy, 50, 50)) # リストに敵のRect(位置と大きさ)を追加 ## 敵の幽霊の設定 ## ゴールの設定 # 壁の設定(四辺に配置) walls = [ pygame.Rect(0, 0, 800, 20), # 上の壁 pygame.Rect(0, 0, 20, 600), # 左の壁 pygame.Rect(780, 0, 20, 600), # 右の壁 pygame.Rect(0, 580, 800, 20) # 下の壁 ] ## リセットボタンの設定 replay_img = pygame.image.load("images/replaybtn.png") ## メインループ内で使う変数 rightFlag = True # 猫の向き pushFlag = False # リセットボタンが押されたか page = 1 # 表示するページ(1:ゲーム画面、2:ゲームオーバー画面、3、ゲームクリア画面) # ここから関数の定義 ## ゲームステージ def gamestage(): global rightFlag global page # 画面の初期化 screen.blit(haikei_img, (0,0)) # 猫の移動量 vx = 0 vy = 0 #ユーザー入力 key = pygame.key.get_pressed() if key[pygame.K_RIGHT]: # 右キーが押されたら右へ移動 vx = 4 rightFlag = True if key[pygame.K_LEFT]: # 左キーが押されたら左へ移動 vx = -4 rightFlag = False if key[pygame.K_UP]: # 上キーが押されたら上へ移動 vy = -4 if key[pygame.K_DOWN]: # 下キーが押されたら下へ移動 vy = 4 # 猫の処理 neko_rect.x += vx neko_rect.y += vy # 猫と壁との衝突判定 if neko_rect.collidelist(walls) != -1: # もし猫が壁と衝突していたら neko_rect.x -= vx neko_rect.y -= vy # 猫の向きの指定 if rightFlag: screen.blit(neko_imgR, neko_rect) else: screen.blit(neko_imgL, neko_rect) ## 犬の処理 for enemy in enemys: # enemysリストの全要素(敵のRect)を順に取り出す screen.blit(enemy_img, enemy) # 敵画像を対応する位置に表示 if neko_rect.collidelist(enemys) != -1: page = 2 ## 幽霊の処理 ## ゴールの処理 ## 壁の処理 for wall in walls: # wallsリストの全要素(壁のRect) pygame.draw.rect(screen, pygame.Color("DARKGREEN"),wall) ## ジャンプ関数(ボタンが押されたらnewpageへジャンプする) def button_to_jump(btn, newpage): global page, pushFlag # ユーザーのマウス操作を取得 mdown = pygame.mouse.get_pressed() # クリック状態 (mx, my) = pygame.mouse.get_pos() # マウスカーソルの座標 if mdown[0]: # 左クリックが押されていたら if btn.collidepoint(mx, my) and pushFlag == False: page = newpage # ページを切り替える pushFlag = True else: pushFlag = False # 離したときにフラグを戻す ## リセット関数(リセットボタンが押されたらゲームをリセットする) def reset(): # 猫を再配置 neko_rect.x = 50 neko_rect.y = 50 # 犬を再配置 for i in range(13): enemys[i].x = 100 + i * 50 enemys[i].y = random.randint(20,550) # 幽霊を再配置(後の章で実装) ## ゲームオーバー関数 def gameover(): reset() # リセット関数の呼び出し screen.fill(pygame.Color("NAVY")) # 背景色を濃い青にする font = pygame.font.Font(None, 150) # フォントサイズ150で設定 text = font.render("GAMEOVER", True, pygame.Color("RED")) # 赤文字で「GAMEOVER」と表示 screen.blit(text, (100,200)) # テキストを画面に表示(x=100, y=200) btn1 = screen.blit(replay_img, (320,480)) # リセットボタンを描画 button_to_jump(btn1, 1) # ジャンプ関数の呼び出し ## ゲームクリア関数 # メインループ 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()
FAQ|ゲームオーバーの設定方法【pygame】
- Q1. ゲームオーバーになったら画面を切り替えるにはどうすればいい?
-
状態管理用の変数(たとえば
page
など)を使って、メインループ内で表示内容を分岐させる方法が一般的です。
- Q2. ゲームオーバーから再スタートする方法は?
-
変数を初期化して、プレイヤーの位置や敵の配置などを再設定することでリスタートできます。ボタンから関数を呼び出す設計がおすすめです。
- Q3. 衝突後すぐにゲームオーバー画面が表示されない場合の対処法は?
-
条件分岐が適切に機能しているか、描画処理が更新されているかなどを確認しましょう。画面更新の順序ミスもよくある原因です。
質問用コンタクトフォーム
この記事を書くにあたりAIを活用しています。
人間の目による確認も行っていますが、もし間違い等ありましたらご指摘頂けると大変助かります。