見出し画像

【Python入門】PyGameでPongゲームを作る

1年ほど前に地元のボランティア活動の一環で(という名目で自分が楽しむために)Python入門講座を始めました.その講座で使っているネタを紹介していきます.
受講者のみなさんがある程度Scratchに慣れているということなので、文法説明などはうっちゃって、いきなりゲーム開発をしながら、Scratchとの違いを説明しつつPythonを学んでもらう作戦です.

前提環境

Python 3, PyGameを使います.

ミニマルなPongゲーム

PyGame入門としてテニスの壁打ちのような、ミニマルなPongゲームを作ります.
画面左側のパドルを上下矢印キーで操作してボールを跳ね返します.
PyGameを使ったプログラムの骨格構造を理解することがこのプロジェクトの目的です.

ミニマルなPongゲーム

PyGameを使ったプログラムの骨格構造

Scratchの場合は新しいプロジェクトを立ち上げると、「ステージ」やネコの「スプライト」が用意されていますが、PyGameでのプログラム開発は、完全に白紙の状態から始めます.
新しいプログラムファイル(例えばpong.pyのような名前のファイル)を作成したらプログラムの骨格部分を入力してみましょう.

import sys
import pygame as pg

WIDTH, HEIGHT = 400, 300
FPS = 30
pg.init()
pg.display.set_mode((WIDTH, HEIGHT))
screen = pg.display.get_surface()
clock = pg.time.Clock()

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

    screen.fill('darkgreen')
    pg.display.update()
    clock.tick(FPS)

この時点で、Scratchでいうところのステージがようやく出来たという状態です.実行すると濃い緑色のウィンドウが表示されるだけです.
一番わかりにくいのは、メインループ(while True以下)の中で、forループを使って何かをしているところですね.PyGameでは、膨大なイベントがリアルタイムに発生していて、本当に必要なもの(上の例ではウィンドウの閉じるボタンが押されたイベント)以外は刈り取って捨てないと、イベントがたまり続けるためこのようにします.
screen.fill('darkgreen')で画面を塗りつぶし、pg.display.update()で塗りつぶした画面を表示に反映します.
clock.tick(FPS)でメインループが1秒間に何回まわるか制御します.

パドルとボールを登場させる

メインループで、背景を塗りつぶしたあとに、パドルとボールを新しい位置に描いてからpg.display.update()することを高速に繰り返すと、画面上でパドルやボールが動いているように見えます.
今回は単純化のため、パドルもボールも長方形で表現します.

PyGameで長方形を描く

長方形の位置と大きさを保持するための「pg.Rectオブジェクト」と、screenの指定位置に指定の色と大きさで長方形を描画する「pg.draw.rect()」関数を使います.pg.Rectオブジェクトを使ってボールやパドルの位置を管理し、その情報に基づいてpg.draw.rect()関数で実際に長方形を描きます.

paddle = pg.Rect(x, y, 10, 40)          # パドルの位置とサイズ
pg.draw.rect(screen, 'skyblue', ball)   # paddleの示す場所に水色の長方形を描く

PyGameでキー入力を受け取る

パドル操作に使う上下矢印キーが押されているかどうかチェックする方法です.下のコードでは押されたキーに応じてパドルの位置を変えています.

keys = pg.key.get_pressed()           # キーの状態一覧を取得
if keys[pg.K_UP]:                     # 上矢印キーが押されていれば
    paddle.move_ip(0, -10)            # paddleのY座標を-10
if keys[pg.K_DOWN]:                   # 下矢印キーが押されていれば
    paddle.move_ip(0, 10)             # paddleのY座標を+10

ボールとパドルの衝突を検出する

PyGameにはpg.Rect同士(今回はパドルとボール)の衝突を検出するための関数が用意されています.下のコードではパドルとボールがぶつかったらX軸方向の移動速度を符号反転させて跳ね返るようにしています.

if paddle.colliderect(ball):
    vx = -vx

あとはボールが壁で跳ね返る処理と、パドルで打ち返せずに左のラインを越えてしまったときの処理を追加すれば、ミニマルなPongゲームが完成です!
コード全体を載せておきます.

import sys
import pygame as pg

WIDTH, HEIGHT = 400, 300
FPS = 30
pg.init()
pg.display.set_mode((WIDTH, HEIGHT))
screen = pg.display.get_surface()
clock = pg.time.Clock()
# パドルとボールの初期化
paddle = pg.Rect(10, HEIGHT // 2, 10, 40)
ball = pg.Rect(WIDTH // 2, HEIGHT // 2, 5, 5)
vx, vy = 4, 6

while True:
    for e in pg.event.get():
        if e.type == pg.QUIT:
            pg.quit()
            sys.exit()
    # パドルの位置を更新
    keys = pg.key.get_pressed()
    if keys[pg.K_UP]:
        paddle.move_ip(0, -10)
    if keys[pg.K_DOWN]:
        paddle.move_ip(0, 10)
    # ボールの位置を更新
    if ball.top + vy <= 0 or ball.bottom + vy >= HEIGHT:
        vy = -vy
    if ball.right + vx >= WIDTH:
        vx = -vx
    if ball.left + vx <= 0:
        pg.time.wait(1000)
        ball = pg.Rect(WIDTH // 2, HEIGHT // 2, 5, 5)
        vx, vy = 4, 6
    ball.move_ip(vx, vy)
    # パドルとボールの衝突判定
    if paddle.colliderect(ball):
        vx = -vx
    # ゲーム画面の更新
    screen.fill('darkgreen')
    pg.draw.rect(screen, 'skyblue', paddle)
    pg.draw.rect(screen, 'white', ball)
    pg.display.update()
    clock.tick(FPS)

#Python #PyGame #ゲーム開発 #プログラミング #Scratch #スクラッチ


この記事が気に入ったらサポートをしてみませんか?