6
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

【Python】Tkinterによる150行で作るGUIアプリ「じゃんけんゲーム」

Last updated at Posted at 2019-04-20

はじめに

こんにちは。今回は「GUIじゃんけんゲーム」を制作しました。
完成するとこんな感じに動きます!
じゃんけんゲーム.gif

以前作った英単語ソフトの記事で、プログラムの構成について、アドバイスとプログラムの見直までしていただきました。本当にありがとうございます。そこで、この「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で制作しました。

グー.png     チョキ.png     パー.png


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

上記がボタンをクリックすると、それぞれに対応する関数が反応するようなコードになります。

完成したプログラム

こちらが完成したプログラムになります。

じゃんけんゲーム.py
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モデルで実装を目指して制作しました。単なるじゃんけんのゲームですが、初めての挑戦だったので、時間はかかりました。しかし、ここ最近で一番成長を実感しています。

6
14
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?