ここ数回、TkinterというGUIライブラリを利用して、ゲーム制作に挑戦している。今回作るのは、レトロ感溢れるゲーム『ブロック崩し』だ。100行程度のプログラムで実現できるので挑戦してみよう。
ブロック崩しのゲーム(GIFアニメ) |
ブロック崩しとは?
ブロック崩しというのは、1970年から1980年にかけて登場したゲームのジャンル。壁にぶつかると反射するボールを、画面下部に落とさないように、バーを左右に移動させるゲームだ。画面にはブロックが配置されており、ボールでブロックを崩していく。
まずはボールを反射させるだけのプログラムから作ってみよう
ボールを画面下部に落とさないようにするという簡単なルールのゲームだが、一度に全部を実装しようとすると、どのようにプログラムを組み立てて良いのか悩むかもしれない。ゲームのプログラムを作る場合、その核となる部分を少しずつ組み立てて行くと良い。そこで、まずは、ボールを反射させるだけのプログラムから作ってみよう。
ボールが反射して動くだけのプログラム |
以下はボールが反射して動くだけのプログラムだ。以下のプログラムを「ball-move.py」(ソースコード:ball-move.lzh)という名前で保存しよう。
# ブロック崩し
from tkinter import *
# ボールを表す辞書型データ --- (*1)
ball = {
"dirx": 15, # X方向のボールの速さ
"diry": -15, # Y方向のボールの速さ
"x": 350, # ボールの位置
"y": 300,
"w": 10, # ボールの幅
}
# ウィンドウの作成 --- (*2)
win = Tk()
cv = Canvas(win, width = 600, height = 400)
cv.pack()
# 画面を描画する --- (*3)
def draw_objects():
cv.delete('all') # 既存の描画を破棄
# ボールを描画
cv.create_oval(
ball["x"] - ball["w"], ball["y"] - ball["w"],
ball["x"] + ball["w"], ball["y"] + ball["w"],
fill="green")
# ボールの移動 --- (*4)
def move_ball():
# 仮の変数に移動後の値を記録
bx = ball["x"] + ball["dirx"]
by = ball["y"] + ball["diry"]
# 上左右の壁に当たった?
if bx < 0 or bx > 600: ball["dirx"] *= -1
if by < 0 or by > 400: ball["diry"] *= -1
# 移動内容を反映
if 0 <= bx <= 600: ball["x"] = bx
if 0 <= by <= 400: ball["y"] = by
# ゲームループ --- (*5)
def game_loop():
draw_objects()
move_ball()
win.after(50, game_loop)
game_loop()
win.mainloop() # ゲームウィンドウを表示
プログラムを実行するには、PowerShellやターミナルを起動し、プログラムをカレントディレクトリに保存したら、次のコマンドを実行する。Windowsでは、「python」コマンドを、macOSでは「python3」コマンドを実行する。
# Windowsの場合
python ball-move.py
# macOSの場合
python3 ball-move.py
それでは、プログラムを一つずつ見てみよう。プログラムの(*1)の部分では、ボールを表す辞書型のデータを定義している。これは、辞書型(dict型)の変数だ。辞書型の変数を使うと、複数の値を一つの変数で管理できるのが良い。ここでは、ボールの位置(x, y)、幅(w)、ボールの速さと進行方向(dirx, diry)を一つの変数で管理する。
ゲームの中では、さまざまな変数を利用するので、このように、辞書型変数を使って、特定の目的で利用する変数をまとめておくと管理しやすくなる。
プログラムの(*2)では、ウィンドウを作成する。ここでは、幅600、高さ400ピクセルのウィンドウを作成する。(*3)では、画面を描画する。ここでは、毎回、全ての描画内容をクリアして、そこに新たに描画内容を書き込むという処理を記述している。cv.delete('all')と記述すると、全ての描画内容をクリアできる。そして、create_oval()メソッドで、(x1, y1, x2, y2)のサイズの楕円を描画する。ここでは、ボールの左上(x1, y1)と右下(x2, y2)の座標を指定する。
プログラムの(*4)では、ボールの座標を移動させる。このとき、X座標とY座標を確認して、上下左右の壁に当たったことが分かれば、ボールの進行方向に-1をかけて、反射させる処理を行う。
そして、プログラムの(*5)の部分で、繰り返し、画面の描画とボールの移動を行うように指定する。
ブロック崩しを完成させよう
そして、ボール移動のプログラムにブロックとバーの描画、そして、マウスの座標を調べて、バーの移動処理を追加すると、ブロック崩しのゲームが完成する。
それらの処理の中で、ブロックに関する扱いを紹介しよう。ブロックの各座標を管理するblocksという配列変数を用意し、その中に各ブロックの座標や色を設定することにしよう。その場合、以下のようなプログラムを用意し、5x8で合計40個のブロックを生成する。
blocks = [] # ブロックを管理する配列
# ... 省略 ...
# ブロックを配置する
for iy in range(0, 5):
for ix in range(0, 8):
color = "red"
if (iy + ix) % 2 == 1: color = "blue"
x1 = 4 + ix * block_size["x"]
x2 = x1 + block_size["x"]
y1 = 4 + iy * block_size["y"]
y2 = y1 + block_size["y"]
blocks.append([x1, y1, x2, y2, color])
ブロックを描画するために、create_rectangle()メソッドを使って、以下のように、矩形を描画できる。このようにして、複数のブロックを用意したら、繰り返し構文のforを使うなら、数行のプログラムで描画できる。
# ブロックを一つずつ描画
for w in blocks:
x1, y1, x2, y2, c = w
cv.create_rectangle(x1, y1, x2, y2, fill=c, width=0)
あとは、ボールがブロックに当たったかどうか、また、ボールが画面下部に落ちたかどうかを一つずつ確認すればゲームが完成だ。
実際のプログラムは、こちら(block-ball.lzh)からダウンロードできる。100行程度のプログラムで、それほど長くないので、ダウンロードしたプログラムを、一行ずつ確認してみて欲しい。基本となる部分は、ボールの反射プログラムとほとんど同じなので、何が付け加えられたのか、見比べながら確認してみると理解しやすいだろう。
なお、プログラムを実行するには、ターミナルから以下のコマンドを実行する。
# Windowsの場合
python block-ball.py
# macOSの場合
python3 block-ball.py
まとめ
以上、今回は、懐かしのレトロゲームのブロック崩しを作ってみた。ゲームを作ってみると、プログラミング力がぐっとアップする。ゲーム開発は、楽しくプログラミング能力を向上させることができる、素晴らしい題材だ。Pythonの基礎構文が身についたら、ぜひ、ゲーム開発に挑戦してみよう。なお、レトロゲームは、それほど難しい処理や豪華なグラフィック処理が不要なので、オススメだ。
自由型プログラマー。くじらはんどにて、プログラミングの楽しさを伝える活動をしている。代表作に、日本語プログラミング言語「なでしこ」 、テキスト音楽「サクラ」など。2001年オンラインソフト大賞入賞、2004年度未踏ユース スーパークリエータ認定、2010年 OSS貢献者章受賞。技術書も多く執筆している。