見出し画像

Step84 pygame入門⑫:(完成)BGMとリトライ機能を追加して、ゲームを完成させる

ここまで本当にお疲れさまでした~(^^)/
このシリーズでは、

  • キャラクターを動かす

  • ジャンプ・当たり判定

  • アイテム獲得

  • スコア管理

  • 制限時間

  • ランダム要素

と、ゲームとして必要な要素を一つずつ積み上げてきました。

最終回となる STEP84 では、いよいよ仕上げとなります!


1. 追加するもの

今回追加するのは次の2つ。

  1. BGMを流す(bgm.mp3)

  2. ゲームオーバー後にリトライできる機能

これでなんとなく「完成品っぽい」ものが出来上がりです!(*'▽')


2. BGMを鳴らす

pygameには、音楽専用の機能がありますので、今回はこれを利用しましょう。

2.1 BGM用の初期化

pygame.mixer.init()

これは、

  • 音を扱う準備をする

  • ゲーム開始時に1回だけ呼ぶ

ためのものです。


2.2 BGMファイルを読み込む

今回使うBGMのファイル名は、

bgm.mp3

です。例えば下のサイトなどから好きなゲーム用BGMを探し出して、ファイル名を変え、「Pythonスクリプトと同じ場所に保存」しておきましょう!


pygame.mixer.music.load("bgm.mp3")
pygame.mixer.music.play(-1)

解説

  • load() → 音楽ファイルを読み込む

  • play(-1) → 無限ループ再生

この2だけで、ゲーム中ずっとBGMが流れます。


3. リトライ機能の考え方

次の追加はリトライです!
やっぱりゲームは何度でも楽しめるといいですよね!( *´艸`)

ちなみにリトライとはここでは、

ゲームの状態を最初に戻す

こととしています。

そのために必要なのは、

  • キャラクターの位置

  • スコア

  • タイマー

  • ゲームオーバーフラグ

「まとめて初期化する」ことになります。


3.1 リセット用の関数を作る

def reset_game():
    global score, start_time, game_over, dy
    player_rect.topleft = (100, 200)
    dy = 0
    score = 0
    start_time = pygame.time.get_ticks()
    game_over = False
    respawn_item()

解説

  • 同じ初期化処理を何度も書かない

  • 関数にまとめることで、コードが読みやすくなる


4. リトライ操作を追加する

今回はシンプルに、

Rキーを押すとリトライ

にします。

if game_over and event.type == pygame.KEYDOWN:
    if event.key == pygame.K_r:
        reset_game()

これで、

  • ゲームオーバー

  • Rキーを押す

  • 最初から再スタート

が可能になります。


5. 完成コード

import pygame
import sys
import random

pygame.init()
pygame.mixer.init()

WIDTH, HEIGHT = 640, 480
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("STEP84: CatFood Game")

clock = pygame.time.Clock()

font = pygame.font.SysFont(None, 32)
big_font = pygame.font.SysFont(None, 56)

# BGM
pygame.mixer.music.load("bgm.mp3")
pygame.mixer.music.play(-1)

# キャラクター
player_image = pygame.image.load("neko.png")
player_rect = player_image.get_rect()

speed = 5
gravity = 1
jump_power = -15

dx = 0
dy = 0
on_ground = False
facing_right = True

# 足場
blocks = [
    pygame.Rect(0, 400, 640, 40),
    pygame.Rect(200, 320, 120, 20),
    pygame.Rect(380, 260, 120, 20),
    pygame.Rect(100, 200, 100, 20),
]

# アイテム
item_image = pygame.image.load("catfood.png")
item_rect = item_image.get_rect()

def respawn_item():
    item_rect.topleft = (
        random.randint(50, WIDTH - 50),
        random.randint(70, 320)
    )

# スコア・タイマー
score = 0
TIME_LIMIT = 60
start_time = pygame.time.get_ticks()
game_over = False

def reset_game():
    global score, start_time, game_over, dy
    player_rect.topleft = (100, 200)
    dy = 0
    score = 0
    start_time = pygame.time.get_ticks()
    game_over = False
    respawn_item()

reset_game()

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

        if not game_over:
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE and on_ground:
                    dy = jump_power
                    on_ground = False
        else:
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_r:
                    reset_game()

    keys = pygame.key.get_pressed()

    if not game_over:
        dx = 0
        if keys[pygame.K_RIGHT]:
            dx = speed
            facing_right = True
        if keys[pygame.K_LEFT]:
            dx = -speed
            facing_right = False

        player_rect.x += dx
        for block in blocks:
            if player_rect.colliderect(block):
                player_rect.x -= dx

        dy += gravity
        player_rect.y += dy

        on_ground = False
        for block in blocks:
            if player_rect.colliderect(block):
                if dy > 0:
                    player_rect.bottom = block.top
                    dy = 0
                    on_ground = True

        if player_rect.colliderect(item_rect):
            score += 1
            respawn_item()

    elapsed = (pygame.time.get_ticks() - start_time) // 1000
    remaining = TIME_LIMIT - elapsed
    if remaining <= 0:
        remaining = 0
        game_over = True

    screen.fill((180, 220, 255))

    for block in blocks:
        pygame.draw.rect(screen, (100, 100, 100), block)

    screen.blit(item_image, item_rect.topleft)

    if facing_right:
        screen.blit(player_image, player_rect.topleft)
    else:
        screen.blit(pygame.transform.flip(player_image, True, False),
                    player_rect.topleft)

    screen.blit(font.render(f"Time: {remaining}", True, (0, 0, 0)), (10, 10))
    screen.blit(font.render(f"Score: {score}", True, (0, 0, 0)), (10, 40))

    if game_over:
        result = big_font.render(f"Score: {score}", True, (0, 0, 0))
        rect = result.get_rect(center=(WIDTH // 2, HEIGHT // 2))
        screen.blit(result, rect)
        retry = font.render("Press R to Retry", True, (0, 0, 0))
        screen.blit(retry, (WIDTH // 2 - 80, HEIGHT // 2 + 40))

    pygame.display.update()
    clock.tick(60)

6. まとめ

  • BGMは music.load → play(-1)

  • ゲームの状態は変数で管理する

  • リトライ=初期化を関数にまとめる

  • 小さな積み重ねで、ゲームやアプリは完成する


7. シリーズを通して

このシリーズでは、

  • Pythonの基本

  • pygameの考え方

  • ゲーム構造の作り方

を、「完成まで」 体験しました。

ここから先は、

  • エフェクト

  • 敵キャラ

  • ステージ切り替え

など、いくらでも発展させられますので、ぜひチャレンジしてみてくださいね(=゚ω゚)ノ

・・・
それに、画面の端に行くと落っこちて戻れないという大変重大なミスもありますしwww

次の記事(新シリーズ)


いいなと思ったら応援しよう!

DOI@日々学びの本質を考え続ける探求者 よろしければ応援お願いします! いただいたチップは引き続きプログラミングや学びについて、皆さんの利益になるようなよい記事を書くことで恩返しをさせていただきます!