色ブロックを表示する
色ブロックを表示する
次の「color.py」「main.py」ファイルをコーディングして「main.py」を「▷」で実行し、タイトル画像をクリックすると図4のように色ブロックが現れます。
Colorクラスを実装する
新たにcolor.pyファイルを新規作成します。color.pyファイルでは色ブロック1個ずつの「Color」クラスを実装します。まずはコンストラクタだけ実装します。
・サンプルコード「color.py」ファイル
import random
# 色ブロック1つ分のクラス
class Color():
image_id = -1
def __init__(self,color,width,height):
self.x = random.randint(100,width-100)
self.y = random.randint(100,height-100)
self.dx = random.choice([-3,-2,-1,1,2,3])
self.dy = random.choice([-3,-2,-1,1,2,3])
self.color = color
【サンプルコードの解説】
乱数のrandomモジュールを読み込みます。
ユニークな(一意の)image_idプロパティを宣言します。ただしデフォルトではユニークではない-1です。
コンストラクタで色ブロック1つのランダムな(x,y)座標プロパティ、増分(Delta)のランダムな(dx,dy)プロパティ、色番号のcolorプロパティをセットします。
メインコードをコーディングする
赤緑青の色ブロック画像を読み込んで表示します。色ブロックは画像ですが、ラベルではなく1つのキャンバスの中に複数表示します。まだ色ブロックは移動しませんが、クリックして背景色に色を混ぜて真っ白になったらステージクリアです(図5)。
・サンプルコード「main.py」ファイル
import tkinter as tk
import random
from color import Color
(中略)
# ゲームクラス
class Game():
# コンストラクタ
def __init__(self):
self.stage = 2
# タイトル表示
def title(self):
(中略)
# ゲーム開始
def on_start(self,event):
self.label.destroy()
# 画像読み込み
files = ["images/0.png", "images/1.png", "images/2.png"]
self.colors = []
# PhotoImage保持
self.images = []
# CanvasアイテムID
self.image_ids = []
self.canvas = tk.Canvas(root, bg="white")
self.canvas.pack(fill="both", expand=True)
for i in range(self.stage*3):
self.colors.append(Color(i%3,width,height))
self.img = tk.PhotoImage(file=files[i%3])
self.images.append(self.img)
self.colors[i].image_id = self.canvas.create_image(self.colors[i].x, self.colors[i].y, image=self.img)
self.image_ids.append(self.colors[i].image_id)
self.canvas.tag_bind(self.colors[i].image_id,"<Button-1>", self.on_click)
self.rgb = [0,0,0]
num = self.stage-1
while self.rgb[0] == self.rgb[1]:
self.rgb = [random.randint(0,num),random.randint(0,num),random.randint(0,num)]
self.bg_color()
self.update()
# 背景色
def bg_color(self):
(中略)
if self.rgb[0] == self.rgb[1] and self.rgb[0] == self.rgb[2]:
self.stage_clear()
# ゲームのメインループ
def update(self):
if not self.canvas.winfo_exists():
return
# 色ブロックのクリック
def on_click(self,event):
item_id = event.widget.find_withtag("current")
if item_id:
for c in self.colors:
if c.image_id == item_id[0]:
self.rgb[c.color] += 1
c.x += c.dx*width
break
self.bg_color()
# ステージクリア
def stage_clear(self):
self.canvas.destroy()
self.stage += 1
img = tk.PhotoImage(file="images/StageClear.png")
self.label = tk.Label(root, image=img)
self.label.pack(expand=True)
self.label.image = img
self.label.bind("<Button-1>", self.on_start)
# ゲームクラスのインスタンス生成
game = Game()
# ゲームクラスのタイトル画面へ
game.title()
# tkinterのメインループ
root.mainloop()【サンプルコードの解説】
色ブロックごとにColorクラスのインスタンスを生成し、colorsプロパティ(配列)に追加します。
PhotoImageクラスで色ブロック画像を読み込み、参照をimagesプロパティに保持しておくことで画像が表示されなくなるのを防ぎます。
image_idプロパティで画像のユニークなイメージID(整数)を取得します。
イメージIDの画像がクリックされたら「on_click」メソッドを呼び出します。
bg_colorメソッドではrgb配列の3要素がすべて同じ値になった場合、真っ白になったと判定してステージクリアとします。
on_clickメソッドではクリックされたブロックのアイテム番号を取得し、colors配列からimage_idが一致する要素を特定します。該当する色の値をインクリメントして背景色に反映させます。あわせて、クリックされたブロックは画面外へ移動させ非表示にします。
stage_clearメソッドはtitleメソッドと同様にラベルへステージクリア画像を表示します。画像をクリックするとメインゲームが再開されます。
色ブロックを移動しゲームを完成させる
色ブロックを移動させるようにし、色ブロックが1個もなくなったらゲームオーバーです(図6)。これでゲームは完成です。サウンドがないのは寂しかったでしょうか?
色ブロックの移動
Colorクラスのupdateメソッドで色ブロックの座標を増分だけ加算し、画面外に出たら戻り値として0を返します。それ以外は1を返します。
・サンプルコード「color.py」ファイル
import random
# 色ブロック1つ分のクラス
class Color():
image_id = -1
def __init__(self,color,width,height):
(中略)
# 毎フレーム更新
def update(self,width,height):
self.x += self.dx
self.y += self.dy
if self.x < -50 or self.y < -50 or self.x > width+50 or self.y > height+50:
return 0
return 1毎フレームupdateメソッドを呼び出す
毎フレームupdateをメインループで呼び出すには、afterメソッドで50ミリ秒後に自分自身(updateメソッド)を再度呼び出すだけです。
・サンプルコード「main.py」ファイル
(前略)
# ゲームクラス
class Game():
# コンストラクタ
def __init__(self):
self.stage = 2
# タイトル表示
def title(self):
(中略)
# ゲーム開始
def on_start(self,event):
(中略)
# 背景色
def bg_color(self):
(中略)
# ゲームのメインループ
def update(self):
if not self.canvas.winfo_exists():
return
flg = 0
for i in range(len(self.image_ids)):
flg += self.colors[i].update(width,height)
self.canvas.coords(self.image_ids[i], self.colors[i].x, self.colors[i].y)
if flg == 0:
self.game_over()
else:
# 約20FPS
root.after(50, self.update)
# 色ブロックのクリック
def on_click(self,event):
(中略)
# ステージクリア
def stage_clear(self):
(中略)
# ゲームオーバー
def game_over(self):
self.canvas.destroy()
img = tk.PhotoImage(file="images/GameOver.png")
self.label = tk.Label(root, image=img)
self.label.pack(expand=True)
self.label.image = img
self.label.bind("<Button-1>", self.on_title)
# タイトル画像クリック時
def on_title(self,event):
self.label.destroy()
self.title()
# ゲームクラスのインスタンス生成
game = Game()
# ゲームクラスのタイトル画面へ
game.title()
# tkinterのメインループ
root.mainloop()【サンプルコードの解説】
ゲームのメインループのupdateメソッドでColorクラスのupdateを呼び出して移動し、画面外に出ていなければ戻り値でflg変数に加算して0より大きくなります。
coordsメソッドでイメージIDの色ブロックをその位置に配置します。
flgが0なら全ての色ブロックが画面外に出ているのでゲームオーバー処理し、そうでなければupdateメソッドをループします。
「game_over」メソッドではtitleメソッドと似たようなことをします。「GameOver.png」を表示し、それをクリックしたら「on_title」メソッドを呼び出し、ラベルを削除してタイトル画面に遷移します。
スマホは電話番号で個人を特定して認証できるSMSなどがあります。そこでパソコンにも電話機能があれば? スマホアプリをパソコンで使えるAndroid PCが出るそうですが電話機能なしです。SIMが入れられるノートパソコンもありますがSMS的なことはできないようです。
おわりに
今回は2026年で最も人気のあるプログラミング言語の1つであるPythonでデスクトップのColorゲームをプログラミングしました。Pythonが使えたら様々な用途に使えるのでとても便利です。
