疑似ターン制バトル

#なんちゃってRPGの戦闘画面の全貌

```python:疑似ターン制バトル
#coding:utf-8
import tkinter as tk
import tkinter.messagebox as tmsg

#Tkを定める
root = tk.Tk()

#タイトル画面設定
root.geometry("400x300")
root.title("RPG")
canvas = tk.Canvas(root,width = 390, height = 290, bg = "black")
canvas.place(x=4,y=5)
#タイトル文字
canvas.create_rectangle(20,10,370,200,outline="white",width=5,fill="blue")
label=tk.Label(root,font=("System",65),text="CIRCLE!!",)
label.place(x=50,y=50)
label=tk.Label(root,font=("System",10),text="PRESENTED BY SUNBOY",)
label.place(x=50,y=146)
label=tk.Label(root,font=("System",10),text="疑似ターン制RPG",)
label.place(x=50,y=174)


    #戦闘画面移行
def ButtonClick():

    #背景
    canvas=tk.Canvas(root,width=390,height=210,bg="black")
    canvas.place(x=3,y=0)

    #敵の描写
    x=200
    y=100
    canvas.create_oval(x-50,y-50,x+50,y+50,outline="white",width=3)
    x=180
    y=85
    canvas.create_oval(x-10,y-10,x+10,y+10,outline="white",width=15)
    x=220
    y=85
    canvas.create_oval(x-10,y-10,x+10,y+10,outline="white",width=15)

    #メッセージ
    messabox = tk.Text(root ,font=("System"))
    messabox.place(x=5, y=215, width=290, height=80)
    messabox.insert(tk.END,"CIRCLEが現れた"+"\n")

    #攻撃ボタンがクリックされたときの処理
    def ButtonClick1():
        messabox.insert(tk.END,"___________________________________"+"\n")
        messabox.insert(tk.END,"あなたの攻撃"+"\n")
        messabox.insert(tk.END,"CIRCLEに10のダメージ！！"+"\n")
        messabox.insert(tk.END,"___________________________________"+"\n")
        messabox.insert(tk.END,"CIRCLEの攻撃"+"\n")
        messabox.insert(tk.END,"あなたに5のダメージ"+"\n")
        
        #ここで背景を作り直さないとダメージエフェクトが出ない
        canvas=tk.Canvas(root,width=390,height=210,bg="black")
        canvas.place(x=3,y=0)
        x=200
        y=100
        canvas.create_oval(x-50,y-50,x+50,y+50,fill="black",width=3)
        
        #通常攻撃判定システム準備
        import random
        a = random.randint(0,9)
        
        #敗北判定
        if a==1:
            canvas=tk.Canvas(root,width=390,height=210,bg="red")
            canvas.place(x=3,y=0)

            x=200
            y=100
            canvas.create_oval(x-50,y-50,x+50,y+50,outline="black",width=3)
            x=180
            y=85
            canvas.create_oval(x-10,y-10,x+10,y+10,outline="black",width=2)
            x=220
            y=85
            canvas.create_oval(x-10,y-10,x+10,y+10,outline="black",width=2)
            
            tmsg.showinfo("敗北", "GAMEOVER")    
            root.destroy()     

        #勝利判定
        if (a%2==0) and (a%3==0):
            tmsg.showinfo("勝利", "あなたはCIRCLEを倒した")
            root.destroy()
        
        #その他
        else:
            def damageb():
                x=200
                y=100
                canvas.create_oval(x-50,y-50,x+50,y+50,outline="white",width=3)
                x=180
                y=85
                canvas.create_oval(x-10,y-10,x+10,y+10,outline="white",width=15)
                x=220
                y=85
                canvas.create_oval(x-10,y-10,x+10,y+10,outline="white",width=15)

            #タイマー
            root.after(200,damageb)

    #ボタン設置
    button1 = tk.Button(root,text = "攻撃", font=("System", 5),command = ButtonClick1)
    button1.place(x = 297, y = 220)

    #魔法攻撃判定
    def ButtonClick3():
        messabox.insert(tk.END,"___________________________________"+"\n")
        messabox.insert(tk.END,"あなたの魔法攻撃：ファイア！！"+"\n")        
        messabox.insert(tk.END,"CIRCLEに20のダメージ！！"+"\n")
        messabox.insert(tk.END,"___________________________________"+"\n")
        messabox.insert(tk.END,"CIRCLEの強攻撃"+"\n")
        messabox.insert(tk.END,"あなたに10のダメージ"+"\n")
        
        #炎上エフェクト
        canvas=tk.Canvas(root,width=390,height=210,bg="black")
        canvas.place(x=3,y=0)
        x=200
        y=100
        canvas.create_oval(x-50,y-50,x+50,y+50,fill="red",width=3)
        
        #敵を倒した判定魔法
        import random
        a = random.randint(0,9)
        
        #敗北判定
        if a==7:
            canvas=tk.Canvas(root,width=390,height=210,bg="red")
            canvas.place(x=3,y=0)

            x=200
            y=100
            canvas.create_oval(x-50,y-50,x+50,y+50,outline="black",width=3)
            x=180
            y=85
            canvas.create_oval(x-10,y-10,x+10,y+10,outline="black",width=2)
            x=220
            y=85
            canvas.create_oval(x-10,y-10,x+10,y+10,outline="black",width=2)
            tmsg.showinfo("敗北", "GAMEOVER")    
            root.destroy()        
        
        #勝利判定
        if (a%3==0):
            tmsg.showinfo("勝利", "あなたはCIRCLEを倒した")
            root.destroy()
        
        #その他
        else:
            def damageb():
                x=200
                y=100
                canvas.create_oval(x-50,y-50,x+50,y+50,fill="black",outline="white",width=3)
                x=180
                y=85
                canvas.create_oval(x-10,y-10,x+10,y+10,outline="white",width=15)
                x=220
                y=85
                canvas.create_oval(x-10,y-10,x+10,y+10,outline="white",width=15)
                    
            #タイマー
            root.after(700,damageb)

    button3 = tk.Button(root,text = "魔法", font=("System", 5),command = ButtonClick3)
    button3.place(x = 346, y = 220)

    #逃走ボタンがクリックされたときの処理
    def ButtonClick2():
        tmsg.showinfo("逃走", "あなたは逃げ出した.....")
        root.destroy()

    button2 = tk.Button(root,text = "逃走", font=("System", 5),command=ButtonClick2)
    button2.place(x = 297, y = 253)

    #敵の情報確認
    def ButtonClick4():
        messabox.insert(tk.END,"___________________________________"+"\n")
        messabox.insert(tk.END,"CIRCLE"+"\n")
        messabox.insert(tk.END,"攻撃力：５/防御力：？？？/HP：？？？"+"\n")
        messabox.insert(tk.END,"謎の球体　じっとこちらを見つめてくる"+"\n")

    button4 = tk.Button(root,text = "情報", font=("System", 5),command = ButtonClick4)
    button4.place(x = 346, y = 253)

#スタートボタン
button = tk.Button(root,text = "始める", font=("System", 5),command = ButtonClick)
button.place(x = 130, y = 220)

#終了ボタン
def ButtonClickfin():
    tmsg.showinfo("終わり", "ゲームを終了します")
    root.destroy()
button5 = tk.Button(root,text = "終わる", font=("System", 5),command = ButtonClickfin)
button5.place(x = 210, y = 220)


root.mainloop()
```
#　タイトル画面作成
今回参考にした**いちばんやさしいPython入門教室：大澤文孝［著］**であるが
以下**入門教室**と呼ぶ

```python:大事な設定
#coding:utf-8
import tkinter as tk
import tkinter.messagebox as tmsg
```

今回は主に**GUIツールキット**を使用している。なので、一番最初に**tkinter**と**messagebox**を**import**しておく。さもないと、のちの**tmsg**や**tk**が意味をなさない。

```python:タイトル画面設定
#タイトル画面設定
root.geometry("400x300")
root.title("RPG")
canvas = tk.Canvas(root,width = 390, height = 290, bg = "black")
canvas.place(x=4,y=5)
#タイトル文字
canvas.create_rectangle(20,10,370,200,outline="white",width=5,fill="blue")
label=tk.Label(root,font=("System",65),text="CIRCLE!!",)
label.place(x=50,y=50)
label=tk.Label(root,font=("System",10),text="PRESENTED BY SUNBOY",)
label.place(x=50,y=146)
label=tk.Label(root,font=("System",10),text="疑似ターン制RPG",)
label.place(x=50,y=174)
```
タイトル画面は初代マリオを少し意識したものになっている。
これらは全て入門教室の6章でふれられていた**labelメソッド**と**Buttonメソッド**、7章の**canvasメソッド**の応用で作られている。
##タイトルの画像
<img width="298" alt="コメント 2020-07-10 015348.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638189/b2d3d130-e8eb-051c-a235-18f97290200b.png">
画面下にボタンが2つついている。
**始める**を押すと戦闘画面に
<img width="296" alt="コメント 2020-07-10 015811.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638189/0244a223-8d4c-bf3a-0577-ebf450afbde2.png">
**終わる**を押すとゲームが終了しウィンドウが閉じるようになっている。

#戦闘システム
```python:基本戦闘画面 
#背景
    canvas=tk.Canvas(root,width=390,height=210,bg="black")
    canvas.place(x=3,y=0)

    #敵の描写
    x=200
    y=100
    canvas.create_oval(x-50,y-50,x+50,y+50,outline="white",width=3)
    x=180
    y=85
    canvas.create_oval(x-10,y-10,x+10,y+10,outline="white",width=15)
    x=220
    y=85
    canvas.create_oval(x-10,y-10,x+10,y+10,outline="white",width=15)

    #メッセージ
    messabox = tk.Text(root ,font=("System"))
    messabox.place(x=5, y=215, width=290, height=80)
    messabox.insert(tk.END,"CIRCLEが現れた"+"\n")
```
敵の姿は入門教室7章でもあった**create_oval**というメソッドを使用した簡単な円で構成されている。

## 戦闘画面の画像

<img width="296" alt="コメント 2020-07-10 021236.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638189/50da3b17-e185-e953-e268-b6b2ee5779a6.png">
<img width="296" alt="コメント 2020-07-10 021319.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638189/8c4e59c3-3b8a-85ea-a19d-1fa8caa82def.png">
右下にあるのボタンを押すと、テキストボックスにそれぞれメッセージが表示される。
テキストボックスは入門教室6章最後にある、履歴ボックスの**insertメソッド**を応用して作成した。なので、メッセージは自動スクロールができないのでいちいち自分でスクロールする必用があるので少し不便だ。
<img width="452" alt="コメント 2020-07-10 022301.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638189/2f261368-84fd-6914-9581-ca857817dd8a.png">
<img width="413" alt="コメント 2020-07-10 022418.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/638189/5a295c5d-469f-f746-e815-f84c35530631.png">

## 勝敗の決め方

また、勝利や敗北の条件は、一番最初はきちんと数値通りのダメージを反映して一定のダメージで勝敗が決まるようにしたかったがいろいろ工夫したり、ネットで調べたりしてもやり方がよくわからなかった。なので、入門教室4章にある**If構文**による条件分岐と**randomモジュール**を利用した。具体的には1～9までの数字の中でランダムに数字を決め、通常攻撃の場合6の倍数、魔法攻撃の場合3の倍数が出たら勝利にしてある。
ちなみに通常攻撃は１、魔法攻撃なら7が出たら敗北である。

## 攻撃システム

```python:攻撃システム
 #攻撃ボタンがクリックされたときの処理
    def ButtonClick1():
        messabox.insert(tk.END,"___________________________________"+"\n")
        messabox.insert(tk.END,"あなたの攻撃"+"\n")
        messabox.insert(tk.END,"CIRCLEに10のダメージ！！"+"\n")
        messabox.insert(tk.END,"___________________________________"+"\n")
        messabox.insert(tk.END,"CIRCLEの攻撃"+"\n")
        messabox.insert(tk.END,"あなたに5のダメージ"+"\n")
        
        #ここで背景を作り直さないとダメージエフェクトが出ない！！
        canvas=tk.Canvas(root,width=390,height=210,bg="black")
        canvas.place(x=3,y=0)
        x=200
        y=100
        canvas.create_oval(x-50,y-50,x+50,y+50,fill="black",width=3)
        
        #通常攻撃判定システム準備
        import random
        a = random.randint(0,9)
        
        #敗北判定
        if a==1:
            canvas=tk.Canvas(root,width=390,height=210,bg="red")
            canvas.place(x=3,y=0)

            x=200
            y=100
            canvas.create_oval(x-50,y-50,x+50,y+50,outline="black",width=3)
            x=180
            y=85
            canvas.create_oval(x-10,y-10,x+10,y+10,outline="black",width=2)
            x=220
            y=85
            canvas.create_oval(x-10,y-10,x+10,y+10,outline="black",width=2)
            
            tmsg.showinfo("敗北", "GAMEOVER")    
            root.destroy()     

        #勝利判定
        if (a%2==0) and (a%3==0):
            tmsg.showinfo("勝利", "あなたはCIRCLEを倒した")
            root.destroy()
        
        #その他
        else:
            def damageb():
                x=200
                y=100
                canvas.create_oval(x-50,y-50,x+50,y+50,outline="white",width=3)
                x=180
                y=85
                canvas.create_oval(x-10,y-10,x+10,y+10,outline="white",width=15)
                x=220
                y=85
                canvas.create_oval(x-10,y-10,x+10,y+10,outline="white",width=15)

            #タイマー
            root.after(200,damageb)

    #ボタン設置
    button1 = tk.Button(root,text = "攻撃", font=("System", 5),command = ButtonClick1)
    button1.place(x = 297, y = 220)
```

ぶっちゃけ、バトルの勝敗は確立なので**メッセージボックスに表示されているダメージの数字には何の意味もない**。

- 個人的にダメージ演出には少しこだわっており、通常攻撃では相手が点滅、魔法攻撃だと相手は一瞬赤く染まる。

これらは、7章にあるタイマー機能を利用している。

# タイトル画面のお話+α

```python:タイトルから戦闘画面に飛ぶ

    #戦闘画面移行
def ButtonClick():

-----------------------------------------------------------------------------

#スタートボタン
button = tk.Button(root,text = "始める", font=("System", 5),command = ButtonClick)
button.place(x = 130, y = 220)

#終了ボタン
def ButtonClickfin():
    tmsg.showinfo("終わり", "ゲームを終了します")
    root.destroy()
button5 = tk.Button(root,text = "終わる", font=("System", 5),command = ButtonClickfin)
button5.place(x = 210, y = 220)
```
始めるボタンで戦闘画面に移行するために**def**を利用し、途中150行近くをすべて関数という扱いにした。

# 感想
私がPython初心者で未熟なこともあり、ターン制バトルと呼べるかも怪しいなんちゃって作品になってしまった。次にゲームを制作するときはBGMや効果音、派手なエフェクト、実際の攻撃力を反映したダメージや残りHPの確認、ちゃんとした画像が表示できるような作品が作りたい。

# 参考文献
- いちばんやさしいPython入門教室：大澤文孝［著］