Tkinterでドラクエ風の戦闘を作ってみたよ
どうもこんにちは〜。今回はpythonのtkinterでドラクエっぽい戦闘画面を作ったよの回です。
最近はpythonをぼちぼち触ってまして、まぁ何か作ってみようかなということでtkinterを使ったGUIでドラクエ1っぽい戦闘画面を作ってみました。
画面はこんな感じ。
画面左側に表示されているキャラクター。これがりゅうおうです。かわいいね。
最初はトレスしようかと思ったんですが怒られが発生したら嫌だなと思って自分で描きました。ドラゴンじゃなくてムラサキ色のカンガルーなので完全に大丈夫です。
プレイヤーは通常攻撃の[たたかう]、ベキラマ相当の[まほう]、ベホイミ相当の回復、絶対に逃げられない[にげる]コマンドを駆使してりゅうおうを倒す趣向です。DQ1の死闘がここにミニマムな形で再現されていますよこれは。
りゅうおうは絶対に先制で激しいほのお、火の息、鋭いツメ(通常攻撃)をローテで使ってくるようになってます。
遊び方
コードは以下の通り。テキストにコピペして[りゅうおう.py]で保存して、画像素材を[りゅうおう.jpg]で保存して任意の場所に置いて、ソースコード内の画像ファイルのパスを修正したのちにコマンドプロンプトから[python3 りゅうおう.py]で実行すれば遊べるよ!
※事前にpython3を使えるようにしておき、追加でPILのインストールも必要です。
#!/usr/bin/env python3 # -*- coding: utf-8 -*- import tkinter as tk import PIL #勇者のステータス hp = 138 mxhp = 138 mp = 123 power = 135 dif = 92 #敵のステータス en_hp = 350 en_pow = 127 en_dif = 154 en_act = 0 dmg = 0 root = tk.Tk() from PIL import Image, ImageTk #りゅうおうの画像 img1 = ImageTk.PhotoImage(file="/Users/ユーザー名/Desktop/りゅうおう.jpg")#画像を置いたパスに書き換えてね root.title("りゅうおう") root.geometry("470x380") #画像のキャンバス canvas = tk.Canvas(root,width=230,height=280,bg="white") canvas.place(x=0,y=0) canvas.create_image(120,150,image=img1,tag="illust") #ボタンのフレーム buttonFrame= tk.Frame(width=150,bg="white") buttonFrame.place(x=250,y=0) #メッセージのフレームを入れるキャンバス msgcanvas = tk.Canvas(root,width=250,height=200,bg="white") msgcanvas.place(x=220,y=130) #メッセージのフレーム msgFrame = tk.Frame(msgcanvas) #スクロールバー bar= tk.Scrollbar(root,orient=tk.VERTICAL) bar.pack(side=tk.RIGHT,fill=tk.Y) bar.config(command=msgcanvas.yview) msgcanvas.config(yscrollcommand=bar.set) msgcanvas.config(scrollregion=(0,0,5000,5000)) msgcanvas.create_window((0,0),window=msgFrame,anchor=tk.NW,width=msgcanvas.cget('width')) #勇者のステータス表示 def update_label(event): strings=("勇者(HP:"+ str(round(hp)) + "/MP:" + str(round(mp))+")") var.set(strings) var = tk.StringVar() var.set("勇者(HP:"+ str(hp) + "/MP:" + str(mp)+")") status = tk.Label(buttonFrame, textvariable=var,bg="white") status.pack() #各種ボタンのイベント def tatakau(): global hp,mp,power,dif,en_hp,en_pow,en_dif,en_act,dmg ryuoh() if hp <= 0: pass elif en_hp < 0: pass else: dmg = (power/2)-(en_dif/4) en_hp = en_hp - dmg if hp > mxhp: hp = mxhp if hp <= 0: result=tk.Label(msgFrame,text="勇者は倒れた!") result.pack() elif en_hp < 0: result=tk.Label(msgFrame,text="りゅうおうを倒した!") result.pack() else: result=tk.Label(msgFrame,text="勇者の攻撃!") result.pack() result=tk.Label(msgFrame,text="りゅうおうに"+str(round(dmg))+"のダメージ!") result.pack() strings=("勇者(HP:"+ str(round(hp)) + "/MP:" + str(round(mp))+")") var.set(strings) def mahou(): ryuoh() global hp,mp,power,dif,en_hp,en_pow,en_dif,en_act,dmg if hp <= 0: pass elif en_hp < 0: pass elif mp < 15: result=tk.Label(msgFrame,text="勇者は雷の呪文を唱えた!") result.pack() result=tk.Label(msgFrame,text="しかしMPが足りない!") result.pack() else: if hp <= 0: result=tk.Label(msgFrame,text="勇者は倒れた!") result.pack() elif en_hp < 0: result=tk.Label(msgFrame,text="りゅうおうを倒した!") result.pack() else: mp = mp - 15 dmg = 60 en_hp = en_hp - dmg if hp > mxhp: hp = mxhp if mp < 0: mp = 0 result=tk.Label(msgFrame,text="勇者は雷の呪文を唱えた!") result.pack() result=tk.Label(msgFrame,text="りゅうおうに"+str(round(dmg))+"のダメージ!",) result.pack() strings=("勇者(HP:"+ str(round(hp)) + "/MP:" + str(round(mp))+")") var.set(strings) def kaifuku(): ryuoh() global hp,mp,power,dif,en_hp,en_pow,en_dif,en_act,dmg if hp <= 0: pass elif en_hp < 0: pass elif mp < 10: result=tk.Label(msgFrame,text="勇者は癒しの呪文を唱えた!") result.pack() result=tk.Label(msgFrame,text="しかしMPが足りない!") result.pack() else: hp = hp + 80 mp = mp - 10 if hp > mxhp: hp = mxhp result=tk.Label(msgFrame,text="勇者は癒しの呪文を唱えた!") result.pack() result=tk.Label(msgFrame,text="勇者のHPが80回復!") result.pack() strings=("勇者(HP:"+ str(round(hp)) + "/MP:" + str(round(mp))+")") var.set(strings) def nigeru(): global hp,mp,power,dif,en_hp,en_pow,en_dif,en_act,dmg if hp <= 0: result=tk.Label(msgFrame,text="勇者は倒れた!") result.pack() elif en_hp < 0: result=tk.Label(msgFrame,text="りゅうおうを倒した!") result.pack() else: result=tk.Label(msgFrame,text="勇者は逃げ出した!") result.pack() result=tk.Label(msgFrame,text="しかし回り込まれてしまった!",) result.pack() ryuoh() strings=("勇者(HP:"+ str(round(hp)) + "/MP:" + str(round(mp))+")") var.set(strings) #りゅうおうの行動 def ryuoh(): global hp,mp,power,dif,en_hp,en_pow,en_dif,en_act,dmg if hp <= 0: result=tk.Label(msgFrame,text="勇者は倒れた!") result.pack() elif en_hp < 0: result=tk.Label(msgFrame,text="りゅうおうを倒した!") result.pack() elif en_act == 0: #激しいほのお(中ダメージ) dmg = 40 hp = hp - dmg if hp <= 0: hp = 0 en_act=en_act +1 result=tk.Label(msgFrame,text="りゅうおうは激しい炎を吐いた!") result.pack() result=tk.Label(msgFrame,text="勇者に"+str(dmg)+"のダメージ!") result.pack() elif en_act == 1: #火の息(小ダメージ) dmg = 20 hp = hp - dmg if hp <= 0: hp = 0 en_act=en_act +1 result=tk.Label(msgFrame,text="りゅうおうは火の息を吐いた!") result.pack() result=tk.Label(msgFrame,text="勇者に"+str(dmg)+"のダメージ!") result.pack() else: #鋭いツメ(通常攻撃・大ダメージ) dmg = (en_pow/2)-(dif/4) hp = hp - dmg if hp <= 0: hp = 0 en_act = 0 result=tk.Label(msgFrame,text="りゅうおうは鋭いツメで切りつけてきた!") result.pack() result=tk.Label(msgFrame,text="勇者に"+str(round(dmg))+"のダメージ!") result.pack() #初期メッセージ start = tk.Label(msgFrame,text="りゅうおうが現れた!") start.pack() #ボタン配置 Button1 = tk.Button(buttonFrame,text="たたかう",width=10,command=tatakau) Button1.pack() Button2 = tk.Button(buttonFrame,text="まほう",width=10,command=mahou) Button2.pack() Button3 = tk.Button(buttonFrame,text="かいふく",width=10,command=kaifuku) Button3.pack() Button4 = tk.Button(buttonFrame,text="にげる",width=10,command=nigeru) Button4.pack() root.mainloop()</span>
かいせつ
はい。とりあえず中身の解説をしますと勇者とりゅうおうのステータスを定義した後にTkinterでフレームとボタンを配置して、PILで画像表示して、メッセージ用フレームをスクロールさせるスクロールバーを配置して、各コマンドのボタンを押した時の戦闘処理とメッセージをdefで書いて終わり!って感じです。
ダメージ処理はだいたい固定値なんですが[たたかう]だけはドラクエ風に攻撃/2-守備/4にしてるのが小さなこだわり。
あとは勝利or敗北時のメッセージを複数箇所に書いちゃってやたら行数が増えているのがチャームポイントですね。絶対もっといい書き方あるでしょ。。と思いつつまぁ動くし別にいいやということで完成させました。
また、勝利or敗北後に[にげる]ボタンを押すと勝利/敗北のメッセージが2回流れる不具合もあります。(直すのが面倒だった)
そんな感じでtkinterでドラクエ風の戦闘作ったよの回でした。とりあえず動くもの作ってみよう、っていうのは勉強になりますね〜。次はDjangoで似たようなの作りたいかもしれない。
それではまた!シーユーネクスト!