TkinterでHPバーをつくる

## HPバーとは
こういうのです。
![bar_image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625723/a9490817-2ff9-51b6-8b60-542774aa64e0.png)

HPゲージ、体力ゲージ、ライフゲージ等とも言いますね。

## Tkinterのウィジェットを用いたHPバー


### シンプルなHPバー

tkinterのttkモジュールにはプログレスバーが用意されているので、簡単にHPバーを作成できます。

![bar2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625723/40140014-a978-0e9f-368d-b3917c22877d.png)


```python:hp-bar_1.python

import tkinter as tk
import tkinter.ttk as ttk
import tkinter.messagebox as tkmsg

HP_MAX = 100        #体力の最大値
ATTACK_DAMAGE = 30  #攻撃力

class ProgressBar(ttk.Frame):

    def __init__(self, window, hp):
        super().__init__(window)
        self.pack()
        
        self.maxhp=hp #HPの最大値
        self.hp=hp    #現在のHP
        
        #ラベルを設置
        label = ttk.Label(self,text="HP:")
        label.pack(side="left")
        
        #変数を用意
        self.var = tk.IntVar()
        self.var.set(100) #HPを100%に設定
        
        #プログレスバーを設置
        self.HPbar = ttk.Progressbar(self, orient="horizontal", length=200, mode="determinate",variable=self.var)
        self.HPbar.pack(side="left")
        
        #攻撃ボタン設置
        attackbutton = ttk.Button(self,text="攻撃",command = self.attack)
        attackbutton.pack(side="left")
        
    #攻撃してHPを減らすメゾット
    def attack(self):
        self.hp -= ATTACK_DAMAGE
        #self.varは百分率で与える
        self.var.set((self.hp/self.maxhp)*100)
        
        #HPが0以下になったら終了
        if(self.hp<=0):
            tkmsg.showinfo("Info","敵を倒した！")
            exit()


if __name__ == '__main__':
    #ウィンドウの作成
    window  = tk.Tk()
    
    #ウィンドウの大きさとタイトルを設定
    window.geometry("600x300")
    window.title("HPbar-type1")
    
    #フレームを作成
    frame = ProgressBar(window,HP_MAX)
    
    #ウィンドウの表示
    window.mainloop()

```



### ダメージによって色が変わるHPバー

style.configure()を利用すれば、体力に応じて色が変わるHPバーを作成できます。

![bar3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625723/58bd8a73-b0f6-0d71-41b3-c47b018d3b50.png)

<details><summary>コード　(クリックして展開)</summary>

```python:hp-bar_2.python
import tkinter as tk
import tkinter.ttk as ttk
import tkinter.messagebox as tkmsg

HP_MAX = 100        #体力の最大値
ATTACK_DAMAGE = 10  #攻撃力
COLOR_LIST =["orangered","orange","yellow","greenyellow","chartreuse"] #バーの色
COLOR_THRESHOLD =[15,25,40,60,100] #バーの色を決めるしきい値

class ProgressBar(ttk.Frame):

    def __init__(self, window, hp):
        super().__init__(window)
        self.pack()
        
        self.maxhp=hp #HPの最大値
        self.hp=hp    #現在のHP
        
        #ラベルを設置
        label = ttk.Label(self,text="HP:")
        label.pack(side="left")
        
        #変数を用意
        self.var = tk.IntVar()
        self.var.set(100) #HPを100%に設定
        
        #スタイルを設定
        self.style=ttk.Style()
        self.style.theme_use("winnative")
        self.style.configure("Horizontal.TProgressbar", background="chartreuse")
        
        #プログレスバーを設置
        self.HPbar = ttk.Progressbar(self, orient="horizontal", length=200, mode="determinate",variable=self.var)
        self.HPbar.pack(side="left")
        
        #攻撃ボタン設置
        attackbutton = ttk.Button(self,text="攻撃",command = self.attack)
        attackbutton.pack(side="left")
        
    #攻撃してHPを減らすメゾット
    def attack(self):
        self.hp -= ATTACK_DAMAGE
        #self.varは百分率で与える
        self.var.set((self.hp/self.maxhp)*100)
        
        #HPが0以下になったら終了
        if(self.hp<=0):
            tkmsg.showinfo("Info","敵を倒した！")
            exit()

        #残りのHPに応じて色を変更
        for i in range(len(COLOR_LIST)):
            if((self.hp/self.maxhp)*100<=COLOR_THRESHOLD[i]):
                self.style.configure("Horizontal.TProgressbar", background=COLOR_LIST[i])
                break


if __name__ == '__main__':
    #ウィンドウの作成
    window  = tk.Tk()
    
    #ウィンドウの大きさとタイトルを設定
    window.geometry("600x300")
    window.title("HPbar-type2")
    
    #フレームを作成
    frame = ProgressBar(window,HP_MAX)
    
    #ウィンドウの表示
    window.mainloop()
```
</details>

ただし、色の変更はすべてのバーに適応されるため、複数呼び出すとうまく動作しませんでした。

![bar4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625723/55e55070-3a08-6763-6d14-6231c7426a14.png)

プレイヤーのHPバーなど、1つだけで十分な場合には使えると思います。


## 図形を用いたHPバー

Canvas上でcreate_rectangleを用いて、灰色の長方形の上に色つきの長方形を描画し、HPバーを作成します。

![bar5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625723/482d30f1-abba-6bcc-74cd-bacc8b06e02b.png)

<details><summary>コード　(クリックして展開)</summary>

```python:hp-bar_3.python

import tkinter as tk
import tkinter.ttk as ttk
import tkinter.messagebox as tkmsg

HP_MAX = 100        #体力の最大値
ATTACK_DAMAGE = 10  #攻撃力
COLOR_LIST =["orangered","orange","yellow","greenyellow","chartreuse"] #バーの色
COLOR_THRESHOLD =[15,25,40,60,100] #バーの色を決めるしきい値
BAR_LENGTH = 200 #バーの長さ
BAR_HEIGHT = 10  #バーの幅

class HPBar():
    def __init__(self, canvas, hp, x, y,name):
        self.maxhp=hp #HPの最大値
        self.hp=hp    #現在のHP
        self.coord=(x,y) #バーの始点座標
        self.name=name #バーの名前
        
        #バーの土台を設置
        canvas.create_rectangle(self.coord[0], self.coord[1], self.coord[0]+BAR_LENGTH, self.coord[1]+BAR_HEIGHT, fill="gray", width=0,tag=f"{self.name}_bar_base")
        #バーを設置
        canvas.create_rectangle(self.coord[0], self.coord[1], self.coord[0]+(self.hp/self.maxhp)*BAR_LENGTH, self.coord[1]+BAR_HEIGHT, fill=COLOR_LIST[len(COLOR_LIST)-1], width=0, tag=f"{self.name}_bar_slider")
        
    #攻撃してHPを減らすメゾット
    def attack(self):
        self.hp -= ATTACK_DAMAGE
        
        for i in range(len(COLOR_LIST)):
            if((self.hp/self.maxhp)*100<=COLOR_THRESHOLD[i]): #ダメージが一定以下なら
                #tagをもとにHPバーを削除して再描写
                canvas.delete(f"{self.name}_bar_slider")
                canvas.create_rectangle(self.coord[0], self.coord[1], self.coord[0]+(self.hp/self.maxhp)*BAR_LENGTH, self.coord[1]+BAR_HEIGHT, fill=COLOR_LIST[i], width=0, tag=f"{self.name}_bar_slider")
                break
        
        #HPが0以下になったら終了
        if(self.hp<=0):
            tkmsg.showinfo("Info","敵を倒した！")
            exit()


if __name__ == '__main__':
    #ウィンドウの作成
    window  = tk.Tk()
    
    #ウィンドウの大きさとタイトルを設定
    window.geometry("600x400")
    window.title("HPbar-type3")
    
    #キャンバスの設置
    canvas = tk.Canvas(window, width=600, height=300, background="white")
    canvas.pack()
    
    #バーの設置
    bar1 = HPBar(canvas, HP_MAX, 100, 30, "enemy1")
    
    #攻撃ボタンの設置
    attackbutton = ttk.Button(window, text="攻撃", command = bar1.attack)
    attackbutton.pack(side="right")
    
    #ウィンドウの表示
    window.mainloop()

```
</details>
この方法であれば、複数呼び出しても機能します。

![bar6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3625723/055c2336-1cde-a303-f3d4-f098b0077eec.png)

図のような、それぞれのキャラクターの頭の上に表示されるHPバーなどに適していると思います。