Pythonでゲームのようなものを作った話
はじめに
本noteでは最近私が作成したプログラムについて備忘録の意味も含めて記述する。
タイトルのとおりプログラミング言語はPythonを採用し、プログラムの内容はゲームのようなものである。ゲームのようなもの、と表現している訳は読者がよく想像するであろうものからはクオリティの面でかけ離れているためだ。
目次にもあるように、プログラムの実行結果、構造、実際のコードに関する具体的な記述内容について述べていく。
実行結果
百聞は一見にしかず、ということで実行結果をgifとして下記に示す。
本プログラムは端的に言えば「数字当てゲーム」である。
2桁の数字「10X+Y」を与えられたヒントと過去の入力ログから数字を当てることを目的としている。X,Yは0~9の重複なしで、入力した数字が当たっていたらHit、当たってはいないがXかYに当てはまるならTouchとなり、入力ログに記載される。つまり2つHitさせればクリアである。
ゲームなのでクリア条件だけでなく失敗条件もある。プレイ時にはHPとして10ポイント与えられ、HPが0以下になると失敗となる。HPは数字を入力した際にHitsしなかった数だけ減る。つまりHitが0ならHPは2減り、Hitが1ならHPは1減る。このことから最長でも10ターンでクリアしなければならない。
そんなゲームである。
構造
本プログラムのフローチャートを下記に示す。
本プログラムは主に2つの状態からなる。「ゲーム中」状態と「notゲーム中」状態である。3つのボタン「START(RESTART)」、「END」、「ENTER」のクリックによりゲーム中の処理の実行と状態の遷移が行われる。
初めに示しておくと「END」ボタンを押すとどの状態であってもゲームが終了し、GUI(ゲームウィンドウ)が閉じる。
ゲーム開始直後は「notゲーム中」状態である。この状態で「START」ボタンを押すと「ゲーム中」状態へ遷移する。「ゲーム中」状態では「START」ボタンが「RESTART」ボタンに変わり、「RESTART」ボタンを押すと現在のゲーム状態がリセットされる。なお、フローチャートにもあるとおり「START(RESTART)」ボタンで「ゲーム中」状態へ遷移する際はゲーム開始前の処理が行われる。その処理は解答となる「X」と「Y」、ヒントの決定と画面更新である。
最後のボタン、「ENTER」ボタンは「ゲーム中」状態でのみ機能する。「ENTER」ボタンが押された時の機能はフローチャート中の「入力値の処理」の部分である。ゲーム画面にある2つの文字入力部「X=」、「Y=」の中に一桁の数字が入力された状態で「ENTER」ボタンが押された場合のみ、「ENTER」ボタンの処理は正常に機能する。「入力値の処理」でのメインの処理は入力値が解答と一致しているかの判定(Hit判定、Touch判定)、HPの減点処理、勝敗判定、前述の3処理に対応する画面変更である。本処理にて、ゲーム勝敗が決まれば「notゲーム中」状態へ、決まっていなければ「ゲーム中」状態へ遷移する。
本プログラムは上記のとおり、「END」ボタンが押されウィンドウが閉じられるまで「START」、「ENTER」のボタンでプログラム処理を行い、状態遷移していく構成となっている。
実際のコード
実際のコーディングに関して、簡単にまとめると下記のような構成でコーディングした。
すべて一つのソースファイルの中に構成している。
最初に行っているのがパッケージのインストールである。今回インストールしたパッケージは下記の2つである。
import tkinter
import datetime
いずれも標準でインストールされているパッケージである。tkinterはGUI作成用のパッケージで、datetimeは時刻取得用のパッケージである。GUI作成はともかく時刻取得のパッケージをインストールしているのは乱数生成用である。あるタイミングでのマイクロ秒を乱数に用いている。後々になって気づいたが、乱数モジュールが標準であるのでそちらを使用すればよかった。なお、そのdatetimeパッケージ唯一の出番が下記のとおりで、所望のマイクロ秒を取得するまでマイクロ秒を取り続けている。
while(1):
TimeValue = str(datetime.datetime.now().microsecond)
if len(TimeValue) >2 and TimeValue[0] != TimeValue[1]:
break
また、もっと他にいいパッケージがありそうな気もするが、「可能な限り標準パッケージで作成する」をさりげない目標にしていたため今回はこの2つのみを用いた。
次に変数の定義。ここは特に語ることはない。必要な関数を適宜定義するだけである。ゲーム状態を示す変数やHP、解答であるX,Yを格納する変数などを定義した。
次に関数の定義について。ここでは共通的な処理、ボタンを押した際の処理を関数として定義した。今回定義したのは下記の関数である。
1. ログテキストの初期化
2. ログテキスト生成
3. HPテキスト生成
4. Hintテキスト生成
5. Enterボタン処理
6. STARTボタン処理
7. ENDボタン処理
テキストの処理は変数を渡してお決まりの文章をつくる共通的な部分が多いためまとめている。ログテキストは10つのstr型リストを一つに結合して生成しているので初期化と生成を関数化している。
各ボタンの処理関数は上記の構造で述べた処理を行っている。
最後にGUIの定義について。上図に示した通り、4種のGUIアイテムを定義した。
ウィンドウはGUIそのものの大枠で
window = tkinter.Tk()
window.title(u"Twin Attack")
window.geometry("400x300")
と記述した。何も特別なことはない。
ラベルはGUI上のテキストで
Message_Text = tkinter.StringVar()
Message_Text.set("TwinAttak")
Message = tkinter.Label(textvariable=Message_Text,font=("",20),width=20)
Message['background'] ='#bbbbbb'
Message.place(x=60,y=20)
というように定義した。3行目の処理でラベルを一度定義しておけば、上記コード中の2行目、4行目のような処理でラベルの情報を書き換え可能である。この記述を用いて、ボタン処理などでのラベル更新を行う。
エントリーは文字入力用のアイテムで
Command_x = tkinter.Entry(font=("",14),width=2)
Command_x.place(x=55,y=125)
というように定義した。エントリーに入力したデータの取得、削除は下記コマンドで行う。
CommandValue_x = Command_x.get()
Command_x.delete(0, tkinter.END)
ボタンはそのままボタンで
EnterButton = tkinter.Button(text=u'Enter', width=3,background='#eeeeee')
EnterButton.place(x=150,y=125)
EnterButton.bind("<Button-1>",Enter_event)
というように定義した。3行目のコードにより、ボタンを左クリック時Enter_eventという関数を処理する。
上記のようなコードをネット情報をあれこれあさり、実際にデバックしながらコーディングした。
exe化
最後にプログラム完成した後に、ソースコードをexe化し、python環境がなくとも実行できるようにした。exe化にはpyinstallerを用いた。最後の最後で標準外のパッケージをインストールである。パッケージのインストールはコマンドプロンプトにて
py -m pip install pyinstaller
と打って実行した。pythonのインストール場所が悪いのかよく分からないが、"py -m"を先頭に付けないと上手くインストールできなかった。
肝心のexe化はコマンドプロンプト上でソースファイル(.py)のあるディレクトリまで移動し、
py -m PyInstaller TwinAttack.py --onefile --noconsole
と打って実行した。こちらも"py -m"を付けて実行している。上記コマンドによりPyInstallerがTwinAttack.pyというソースファイルを元にexeファイルを生成する。"--onefile"と付けることでexeファイル1つにソースファイルをまとめることができる。"--onefile"を付けないと実行時に必要なファイルがexe以外に複数生成される。また"--noconsole"はexe実行時にコンソールを出さないようにするためのものである。
おわりに
今回は私が自己啓発も若干含んだ趣味の範囲で作成したプログラムについてnoteにまとめました。
pythonは無料だし様々なパッケージがあるしexe化できるしで軽い気持ちで触れるにはいいなと感じた。使っているIDEが悪いのか実行時の変数が未だに参照できないなどの使いこなせていない部分が多々ありますが。
今後もプログラムで作りたいものが浮かんできたら、コーディングしてみようと思います。その何を作るかが一番浮かばないのだけどね。
この記事が気に入ったらサポートをしてみませんか?