はじめに
こんにちは。今回は「GUIじゃんけんゲーム」を制作しました。
完成するとこんな感じに動きます!
以前作った英単語ソフトの記事で、プログラムの構成について、アドバイスとプログラムの見直までしていただきました。本当にありがとうございます。そこで、この「GUIじゃんけんゲーム」でそれを実践しようと思い、作り始めました。
アドバイスの内容は以下の通りになります。
GUIアプリは、処理を層に分けると可読性が高くなると思います。
有名な分け方にMVC(Model-View-Controller)があります。
Modelはデータ、Viewはデータ表示、Controllerはデータ操作と表示との橋渡しを担当します。
GUI部品はModelでもありViewでもありControllerでもあったりするので、分離が難しいのですが、Viewでデータ処理しないように気を付けることはできます。
アドバイスの内容通り、MVCモデルで実装していきたいと思います。初めてのことなので、うまくできていない部分があったらすみません。
環境
- Windows 10 home
- Python 3.7.1
ファイルの構成は以下のようになります。
├──じゃんけんゲーム/
├── 素材/
│ ├── グー.png
│ ├── チョキ.png
│ └── パー.png
└── じゃんけんゲーム.py
GUIじゃんけんゲーム
ここから、ウィンドウの作成、データ、データ表示、データ操作の順に記載していきます。
最後の方に完成したプログラムを載せるので、まず実行したい方は一気にそっちを見てください!
import tkinter as tk
import random as rd
使うライブラリはこの二つになります。
ウィンドウの作成
まず、ウィンドウの作成からになります。
雛形の記事を基本に作っていきます。
import tkinter as tk
class Application(tk.Frame):
def __init__(self,master):
super().__init__(master)
master.geometry("350x300")
master.title("じゃんけんゲーム")
self.pack()
def main():
win = tk.Tk()
app = Application(master = win)
app.mainloop()
if __name__ == "__main__":
main()
このプログラムでウィンドウを作っていきます。
ウィンドウサイズは300×350。
タイトルはじゃんけんゲームにしています。
データ
次に、グー、チョキ、パーの画像を入れます。
この素材に関してはPiskelで制作しました。
Player = []
Enemy = []
Player.append(Image("グー.png", 25, 220, 3))
Player.append(Image("チョキ.png", 120, 205, 3))
Player.append(Image("パー.png", 200, 220, 3))
Enemy.append(Image("グー.png", 100, 25, 2))
Enemy.append(Image("チョキ.png", 100, 15, 2))
Enemy.append(Image("パー.png", 100, 25, 2))
それぞれ、main関数内で、PlayerとEnemyのリストに入れていきます。
データ表示
データの表示に関してはApplicationクラスが処理をします。
main関数でインスタンスappを生成しています。
app = Application(Player, Enemy, master = win)
データ操作
データ操作はmain関数で処理していきます。
app.RButton["command"] = RJudge
app.SButton["command"] = SJudge
app.PButton["command"] = PJudge
app.RetryButton["command"] = RetryJudge
上記がボタンをクリックすると、それぞれに対応する関数が反応するようなコードになります。
完成したプログラム
こちらが完成したプログラムになります。
import tkinter as tk
import random as rd
class Image():
def __init__(self, image, x, y, z):
self.image = tk.PhotoImage(file = "素材/" + image).subsample(z)
self.x = x
self.y = y
class Application(tk.Frame):
def __init__(self, player, enemy, master):
super().__init__(master)
master.geometry("300x350")
master.title("じゃんけんゲーム")
self.Player = player
self.Enemy = enemy
self.RandCounter = 0
self.JudgeNumber = 0
self.EnemyLabel = []
for i in range(3):
tk.Label(master, image = self.Player[i].image).place(x = self.Player[i].x, y = self.Player[i].y)
for i in range(3):
self.EnemyLabel.append(tk.Label(master, image = self.Enemy[i].image))
self.RButton = tk.Button(master, text = "グー")
self.RButton.place(x = 45, y = 300)
self.SButton = tk.Button(master, text = "チョキ")
self.SButton.place(x = 130, y = 300)
self.PButton = tk.Button(master, text = "パー")
self.PButton.place(x = 225, y = 300)
self.RetryButton = tk.Button(master, text = "リトライ!")
self.RetryButton.place(x = 220, y = 160)
self.WinText = tk.Label(master, text = "勝ち!", fg = "red", font = ("Impact", 20, "bold"))
self.LoseText = tk.Label(master, text = "負け!", fg = "black", font = ("Impact", 20, "bold"))
self.DrowText = tk.Label(master, text = "引き分け!", fg = "green", font = ("Impact", 20, "bold"))
master.after(50, self.Update)
self.pack()
def Update(self):
if self.JudgeNumber == 0:
self.EnemyLabel[self.RandCounter].place_forget()
self.RandCounter = rd.randint(0,2)
self.PrintEnemy(self.RandCounter)
self.master.after(50, self.Update)
def PrintEnemy(self, randCounter):
if randCounter == 0:
self.EnemyLabel[randCounter].place(x = self.Enemy[randCounter].x, y = self.Enemy[randCounter].y)
elif randCounter == 1:
self.EnemyLabel[randCounter].place(x = self.Enemy[randCounter].x, y = self.Enemy[randCounter].y)
else:
self.EnemyLabel[randCounter].place(x = self.Enemy[randCounter].x, y = self.Enemy[randCounter].y)
def Win(self):
self.WinText.place(x = 50, y = 150)
def Lose(self):
self.LoseText.place(x = 50, y = 150)
def Drow(self):
self.DrowText.place(x = 50, y = 150)
def main():
win = tk.Tk()
Player = []
Enemy = []
Player.append(Image("グー.png", 25, 220, 3))
Player.append(Image("チョキ.png", 120, 205, 3))
Player.append(Image("パー.png", 200, 220, 3))
Enemy.append(Image("グー.png", 100, 25, 2))
Enemy.append(Image("チョキ.png", 100, 15, 2))
Enemy.append(Image("パー.png", 100, 25, 2))
app = Application(Player, Enemy, master = win)
def RJudge():
app.JudgeNumber = 1
if app.RandCounter == 0:
app.Drow()
elif app.RandCounter == 1:
app.Win()
elif app.RandCounter == 2:
app.Lose()
def SJudge():
app.JudgeNumber = 1
if app.RandCounter == 0:
app.Lose()
elif app.RandCounter == 1:
app.Drow()
elif app.RandCounter == 2:
app.Win()
def PJudge():
app.JudgeNumber = 1
if app.RandCounter == 0:
app.Win()
elif app.RandCounter == 1:
app.Lose()
elif app.RandCounter == 2:
app.Drow()
def RetryJudge():
app.DrowText.place_forget()
app.WinText.place_forget()
app.LoseText.place_forget()
app.JudgeNumber = 0
app.RButton["command"] = RJudge
app.SButton["command"] = SJudge
app.PButton["command"] = PJudge
app.RetryButton["command"] = RetryJudge
app.mainloop()
if __name__ == "__main__":
main()
終わりに
ここまで、読んでいただいてありがとうございます。ご参考になれば嬉しいです。
今回はMVCモデルで実装を目指して制作しました。単なるじゃんけんのゲームですが、初めての挑戦だったので、時間はかかりました。しかし、ここ最近で一番成長を実感しています。