一つ前のチャプターではゲームオーバーの設定をしました。
今回はいよいよ ぶつかると消えるブロックを配置 し、ブロック崩しゲームを完成させましょう。
Chapter1:pygame入門|画面を表示しよう
Chapter2:簡単なノベルゲームを作ろう
Chapter3:簡単なアクションゲームを作ろう
Chapter4:ブロック崩しを作ろう
・Chapter4-1:ボールを壁に反射させよう
・Chapter4-2:反射させるバーを設置しよう
・Chapter4-3:ボールが画面下に落ちたらゲームオーバーにしよう
・Chapter4-4:ぶつかると消えるブロックを配置しよう ◁今回はここ
Chapter5:シューティングゲームを作ろう
Chapter6:pygameのお役立ち情報
ついにこのチャプターでブロック崩しゲームが完成します!
ここまでのステップで画面にボールを表示し、ランダムに動かし、バーで反射させる処理や、ボールが下に落ちるとゲームオーバーになる仕組みなどを学んできました。
一つひとつの要素を丁寧に作り上げてきたことで、ゲームとしての形が見えてきたのではないでしょうか。
そして今回の最終ステップでは、画面に「ブロック」を配置し、それにボールがぶつかるとブロックが消えるという、ブロック崩しゲームの一番の醍醐味を実装します。
すべてのブロックを壊せばゲームクリア!つまり、今回で1本のゲームが完成するのです。
それでは、いよいよ最後の仕上げに取りかかっていきましょう。
本記事は会員向けの有料記事ですが、現在は期間限定で無料公開中です。
ブロックってなに?
まずは今回追加する「ブロック」について確認しておきましょう。
ブロックは画面の上部に複数並べて配置される四角いオブジェクトで、ボールがぶつかると消える仕組みになっています。
ゲームの目的はこのブロックをすべて壊すことです。言い換えるとブロックは「ボールの当てる的(まと)」のような役割を持っています。
ブロック崩しの核となる要素、それがこの「ブロック」なのです。
ブロックを作るための準備
ゲームに登場する複数のブロックを一括で管理するには、「リスト」という仕組みを使います。
リストとは、複数のデータをひとまとめにして扱えるPythonの機能です。ブロックのようにたくさんのオブジェクトを扱うときには非常に便利です。
まず、以下のようにして空のリストを用意します。
blocks = []
このblocks
というリストに、画面に表示したいブロックの情報(位置やサイズ)を追加していきます。
ブロックはpygame.Rect()
という関数を使って作ります。たとえば次のように書くと、左上の位置が(40, 40)、サイズが横80ピクセル、縦30ピクセルのブロックを作ることができます。
pygame.Rect(40, 40, 80, 30)
しかしこのようなブロックを1つずつ手で書いていくのは大変なので、繰り返し処理(for文)を使って、縦5行・横8列の合計40個のブロックを一気に作成しましょう。
このコードではx方向に90ピクセル、y方向に50ピクセルずつずらしながら、整列されたブロックを作成しています。
各ブロックの位置を少しずつずらすことで、整ったグリッド状に配置されます。
これでゲーム内で扱う「ブロックのデータ」がリストの中にすべて入った状態になりました。
ブロックを画面に表示する
作成したブロックはまだ画面上には表示されていません。
ブロックを実際にゲーム画面に描画するためには、pygame.draw.rect()
という関数を使います。
これにより毎フレームごとにブロックが描画され、ゲーム画面に表示されるようになります。
実際にこの処理を加えると、ゲームを起動した際に画面の上部にグレーのブロックが縦5行・横8列で並んで表示されるようになります。
これでブロックが「見た目」としてゲーム内に登場しました。次のステップでは、これらのブロックにボールが当たると消える処理を実装していきます。
ボールがブロックにぶつかった時の処理
ブロックが画面に表示されるようになったら、次は「ボールがブロックにぶつかったら消える」処理を追加していきます。
ボールとブロックが衝突しているかどうかは、colliderect()
という関数を使って判定します。
この関数は二つの四角形がぶつかっているかどうかを調べて、ぶつかっていればTrue
、そうでなければFalse
を返してくれます。
ブロックとぶつかったときには、次の3つの処理を行います。
- ボールの向きを反転させる
- ブロックを消す
- スコアを加算する
ここで、blocks[n] = pygame.Rect(0, 0, 0, 0)
としているのは、ブロックを完全に削除するのではなく、サイズ0×0の見えない状態にして処理を簡単にするためです。
また、スコアが40になったときにpage = 3
とすることで、ゲームクリア画面へと切り替えられるようになっています。
スコアの管理とゲームクリア処理
ボールがブロックにぶつかるたびに、1点ずつスコアを加算する処理を追加しました。
では、そのスコアを使って「すべてのブロックを壊したらゲームクリア」とするにはどうすればよいのでしょうか?
このゲームでは、ブロックは全部で 40個 作られています。つまりスコアが40に到達したときに「ゲームクリア」画面を表示すればよいわけです。
ゲームクリア時の表示内容は、以下のような関数で定義されています。
この関数はゲームがクリアされたときに呼び出され、「GAMECLEAR」の文字とリプレイボタンを画面に表示します。
プレイヤーがリプレイボタンをクリックすると、ゲームが最初からやり直せるようになっています。
これで、プレイヤーが全ブロックを壊すことでゲームをクリアできるようになりました。
最後に、メインループを修正してクリア画面が表示されるようにしましょう。
これによりゲームの状態に応じた画面表示ができるようになります。
プレイヤーが全てのブロックを壊すとpage
が3になり、ゲームクリア画面へと切り替わるのです。
リセット関数でブロックを再生成する
ゲームオーバーやゲームクリアの後、リプレイボタンを押すことでゲームを最初からやり直せるようにするためには、リセット関数の中でブロックを再生成する処理が必要です。
ゲームをリスタートしたときに新しいブロックを表示できるようにしましょう。
このようにすることで、ゲームをリセットしたときに新しい40個のブロックが生成され、再びゲームを最初から遊ぶことができます。
これで、pygameを用いたブロック崩しゲームは完成しました。
まとめ
Chapter4では4つのチャプターを通して1つのブロック崩しゲームを作り上げました。ここまで本当にお疲れさまでした!
このゲームはただ「遊べる」だけではありません。プログラミングの基本的な考え方がぎゅっと詰まった教材でもあります。
この4記事を通じて、Pygameでのゲーム開発の流れを一通り体験することができました。
難しく感じるところもあったかもしれませんが、「自分で動くゲームを作れた!」という実感が、きっと大きな自信につながったのではないでしょうか。
プログラミングは「作って覚える」が一番の近道です。
今回のブロック崩しを土台にしてあなた自身のアレンジを加えてみるのもとても良い練習になります。後述の「チャレンジ!さらに面白いゲームに改造しよう!」にも是非挑戦してください^^
次のチャプターでは、いよいよ新しいジャンルのゲーム制作に挑戦していきます。ここで身につけた知識と経験を活かして、さらにレベルアップしていきましょう!
本当にお疲れさまでした。そして、これからのチャレンジも応援しています!
- Chapter4-4の完成コード
-
今回の記事での完成するコード全体は↓↓の通りです。
必要な方は開いて確認しましょう。
# 初期化(ゲームの準備をする) import pygame, sys, random pygame.init() screen = pygame.display.set_mode((800, 600)) ## 背景の設定 haikei_img = pygame.image.load(r"C:\Users\81909\Dropbox\01_アフィリエイト関係\09 初心者のためのプログラミング問題集\コード\Python\Chapter4\images\hoshizora.png") haikei_img = pygame.transform.scale(haikei_img, (800, 600)) # ボールの設定 ball_rect = pygame.Rect(400, 450, 30, 30) # x=400, y=450 の位置に、30x30の正方形を配置 vx = random.randint(-10, 10) # x方向の初期速度(ランダムに設定) vy = -5 # y方向の初期速度(上に向かって移動) ## バーの設定 bar_rect = pygame.Rect(400, 550, 100, 10) ## ブロックの設定 blocks = [] for block_y in range(5): # 縦に5行分繰り返す for block_x in range(8): # 横に8列分繰り返す blocks.append(pygame.Rect(40 + block_x * 90, 40 + block_y * 50, 80, 30)) ## リプレイボタンの設定 replay_img = pygame.image.load(r"C:\Users\81909\Dropbox\01_アフィリエイト関係\09 初心者のためのプログラミング問題集\コード\Python\Chapter4\images\replaybtn.png") ## メインループ内で使う変数 pushFlag = False page = 1 score = 0 # ここから各関数の定義 ## ゲームステージ関数 def gamestage(): # 画面の初期化 global vx, vy, page, score screen.blit(haikei_img, (0,0)) # ユーザー入力 (mx, my) = pygame.mouse.get_pos() # ボールの処理 if ball_rect.y < 0: # 画面の上下端に到達したら vy = -vy # 縦方向の速度を反転 if ball_rect.x < 0 or ball_rect.x > 800 - 30: # 画面の左右端に到達したら vx = -vx # 横方向の速度を反転 if ball_rect.y > 600: # もしボールが画面下に到達したら page = 2 # ゲームオーバー画面に切り替える if bar_rect.colliderect(ball_rect): # もしバーがボールと衝突したら vx = ((ball_rect.x + 15) - (bar_rect.x + 50)) / 4 vy = random.randint(-10, -5) ball_rect.x += vx # x方向に移動 ball_rect.y += vy # y方向に移動 pygame.draw.circle( screen, # 描画先の画面 pygame.Color("GOLD"), # ボールの色(GOLDに設定) ball_rect.center, # 円の中心座標(Rectの中心) ball_rect.width // 2 # 円の半径(Rectの幅の半分) ) # バーの処理 bar_rect.x = mx - 50 pygame.draw.rect(screen, pygame.Color("BLUE"), bar_rect) # ブロックの処理 n = 0 # インデックス番号(何番目のブロックか)を管理する変数 for block in blocks: pygame.draw.rect(screen, pygame.Color("GRAY"), block) ## ボールがブロックにぶつかった時の処理 if block.colliderect(ball_rect): vy = -vy # ボールの向きを反転 blocks[n] = pygame.Rect(0, 0, 0, 0) # ブロックを「見えない」状態にする score += 1 # スコアを1加算 if score == 40: # すべてのブロックを壊したら page = 3 # ゲームクリア画面へ n += 1 ## ジャンプ関数(ボタンが押されたら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: # ボタンの範囲内かつ1回だけ反応させる page = newpage # 指定されたページに切り替える pushFlag = True else: pushFlag = False # マウスを離したらフラグを戻す ## リセット関数(ゲームをリセットする) def reset(): global vx, vy, score, blocks vx = random.randint(-10, 10) # 横方向のスピードをランダムに vy = -5 # 縦方向のスピードは一定(上方向) ball_rect.x = 400 # ボールの位置を初期位置に戻す ball_rect.y = 450 # ブロックの初期化 score = 0 blocks = [] # 空のリストで初期化 for block_y in range(5): # 5行分のブロック for block_x in range(8): # 各行に8個のブロック blocks.append(pygame.Rect(40 + block_x * 90, 40 + block_y * 50, 80, 30)) ## ゲームオーバー関数 def gameover(): reset() # リセット関数の呼び出し screen.fill(pygame.Color("YELLOW")) # 画面を黄色で塗りつぶす font = pygame.font.Font(None, 150) # フォントを設定 text = font.render("GAMEOVER", True, pygame.Color("RED")) # GAMEOVERの文字を赤色で描画 screen.blit(text, (100, 200)) # 画面に文字を表示 btn1 = screen.blit(replay_img, (320, 480)) # リプレイボタンを表示 button_to_jump(btn1, 1) # ジャンプ関数の呼び出し ## ゲームクリア関数 def gameclear(): reset() # リセット関数の呼び出し screen.blit(haikei_img, (0,0)) # 背景画像を描画 font = pygame.font.Font(None, 150) text = font.render("GAMECLEAR", True, pygame.Color("SKYBLUE")) screen.blit(text, (60, 200)) btn1 = screen.blit(replay_img, (320, 480)) button_to_jump(btn1, 1) # ジャンプ関数の呼び出し # メインループ while True: if page == 1: gamestage() # プレイ中の画面 elif page == 2: gameover() # ゲームオーバー画面 elif page == 3: gameclear() # ゲームクリア画面 # 画面表示 pygame.display.update() pygame.time.Clock().tick(60) # 終了処理 for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit()
チャレンジ!さらに面白いゲームに改造しよう!
ブロック崩しゲームの製作講座はここで終了ですが、このゲームはまだまだ面白くできる余地があるとおもいませんか?
以下のアイディアをベースにして、あなたの手でより面白いゲームへ作り変えてみて下さい。
- ボールやブロックなどの色やデザインを変える
- 背景画像を変更し、ブロックを崩すことでだんだん見えるようにする
- バーに耐久値をつけ、一定回数以上ボールがあたると壊れるようにする
- バーの耐久値によってデザインが変わる
- タイミングよくキーを押すことで周囲のブロックを破壊(ボールのRectを大きくする)
質問用コンタクトフォーム
この記事を書くにあたりAIを活用しています。
人間の目による確認も行っていますが、もし間違い等ありましたらご指摘頂けると大変助かります。