PygameでRPG（戦闘画面）

a
[記事全体の目次へ移動](https://qiita.com/hijpa/items/056acaa13e935590fdc2)

# GIF

<details><summary>ここをクリックしてください</summary>

![無題の動画 ‐ Clipchampで作成 (2).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3874121/f8fa3429-6ace-c785-93df-db4e4040fed5.gif)


![無題の動画 ‐ Clipchampで作成 (1).gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3874121/17b5758c-7a7b-9d9e-6b99-90c31cf1e693.gif)
</details>


# キーハンドラー

何かキーが押されたとき、図形が表示されるコードです。

<details><summary>ここをクリックしてください</summary>

```python:keyhandler

import pygame
from pygame.locals import *
import sys

pygame.init()
screen = pygame.display.set_mode((160,160))
pygame.display.set_caption("key_handler")
rect_show = False

while(1):
    screen.fill((0,0,0))
    if rect_show:
        pygame.draw.rect(screen,(255,255,255),(60,60,40,40))
    pygame.display.update()
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == KEYDOWN:
            rect_show = not rect_show
```
elif event.type == KEYDOWN:
何かキーが押された時だけ処理が実行されます。
rect_show = not rect_show
処理が実行されるたびにFalseとTrueが入れ替わります。

</details>

# マウス操作

左クリックされたとき、図形が表示されます。
<details><summary>ここをクリックしてください</summary>

(ここをクリックしてください　をクリックしても図形は表示されません。たまたま表現が被ってるだけです。)

```python:mouse
import pygame
from pygame.locals import *
import sys

pygame.init()
screen = pygame.display.set_mode((160,160))
pygame.display.set_caption("mouse")
rect_show = False

while(1):
    screen.fill((0,0,0))
    if rect_show:
        pygame.draw.rect(screen,(255,255,255),(60,60,40,40))
    pygame.display.update()
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        mouse_pressed = pygame.mouse.get_pressed()
        if mouse_pressed[0]:
            rect_show = not rect_show
```
mouse_pressed = pygame.mouse.get_pressed()
マウスが押されたかどうかを判断します。
if mouse_pressed[0]:
左クリックされたかどうかを判断します。
[0]が左クリック

[1]がセンターボタン

[2]が右クリック

</details>

# Zキーが押されたら数字が減る　

<details><summary>ここをクリックしてください</summary>

ダメージを極限まで簡略化させたものです。

```python:

import pygame
import sys
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((160, 160))
pygame.display.set_caption('down')
#ここにフォントのパスを貼り付ける
font = pygame.font.Font(パス, 30)        

hp = 50
damage = 0

while (1):
    screen.fill((0, 0, 0))
    text = font.render(str(hp), True, (255, 255, 255)) 
    screen.blit(text, (60,60))    
    pygame.display.update()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type==KEYDOWN:
            if event.key==K_z:
                damage = 10
                hp -= damage

```

hp -= damage
he -= 10 でも良いわけですが、コードを読みやすくするためにこう書いています。

</details>

# 隅が丸い枠

<details><summary>ここをクリックしてください</summary>

![スクリーンショット (663).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3874121/c356fd3c-daa5-38e8-8471-99f4a1cbe7cf.png)


```python:隅が丸い枠
import pygame
import sys
from pygame.locals import *

pygame.init()
screen = pygame.display.set_mode((160, 160))
pygame.display.set_caption("flame")

while True:
    screen.fill((0, 0, 0))
    # 四角形を描画
    pygame.draw.rect(screen, (255, 255, 255), (40, 50, 80, 60), 3, 5)
    pygame.display.update()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

```
pygame.draw.rect(screen, (255, 255, 255), (40, 50, 80, 60), 3, 5)
(255, 255, 255)色の指定です。
(40, 50, 80, 60)座標と大きさです。(よこ、たて、幅、高さ)
３が枠の太さです。
５が角の丸みの半径です。
</details>

# 三角形の描画(カーソル風)

<details><summary>ここをクリックしてください</summary>

![スクリーンショット (662).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3874121/d8fd9d7c-b29f-c78e-d4d6-f8a79b65da91.png)


```python:
import pygame
import sys
from pygame.locals import *

pygame.init()
screen = pygame.display.set_mode((80, 80))
pygame.display.set_caption('Draw Triangle')

while True:
    # 画面を黒で塗りつぶす
    screen.fill((0, 0, 0)) 
    # 三角形を描画
    pygame.draw.polygon(screen, (255, 255, 255), [(5, 5), (15, 10), (5, 15)])
    pygame.display.update()
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()

```

pygame.draw.polygon(screen, (255, 255, 255), [(5, 5), (15, 10), (5, 15)])

[(5, 5), (15, 10), (5, 15)])
　図形の頂点の座標です。三角形なので3つあります。四角形なら4つですね。
　座標の順番には決まりがあるでしょうか。
　順番に決まりはありませんが、注意点があります。それは、図形が頂点を結んで描かれることです。三角形では頂点が交差しないので問題ありませんが、四角形からは気を付けなければなりません。

 [(5, 5), (5, 45), (45, 45), (45, 5)]

![正しい四角形.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3874121/2d8416a5-7402-bb61-6fc5-f00c8e69a701.png)


 [(5, 5), (5, 45), (45, 5), (45, 45)]

![予想外四角形.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3874121/65866843-0b1f-c627-819e-cf0e29527d6a.png)

座標は同じでも、順番によって描かれる図形が変わります。

</details>

# 戦闘画面

<details><summary>ここをクリックしてください</summary>

![スクリーンショット (665).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3874121/482a3c48-cc1f-8d7f-1291-0ebd99e5bed3.png)


```python:
import pygame
import sys
from pygame.locals import *

pygame.init()
screen = pygame.display.set_mode((320, 320))
pygame.display.set_caption('battle')
#ここにフォントのパスを貼り付ける
font = pygame.font.Font(パス,15)

hp = 39
while (1):
    screen.fill((0, 0, 0))
    #HP枠
    pygame.draw.rect(screen,(255,255,255),(20,10,100,100),3,5)
    #コマンド枠
    pygame.draw.rect(screen,(255,255,255),(20,210,100,100),3,5)
    #モンスター名枠
    pygame.draw.rect(screen,(255,255,255),(130,210,180,40),3,5)
    #線
    pygame.draw.line(screen,(255,255,255),(20,35),(116,35),1)
    #ステータス表示
    text = font.render("ゆうしゃ",True,(255,255,255))
    screen.blit(text,(40,13))
    text = font.render("H　　" + str(hp),True,(255,255,255))
    screen.blit(text,(35,38))
    text = font.render("M　　０",True,(255,255,255))
    screen.blit(text,(35,58))
    text = font.render("ゆ：　１",True,(255,255,255))
    screen.blit(text,(35,78))
    #コマンド表示
    text = font.render("ゆうしゃ",True,(255,255,255))
    screen.blit(text,(40,213))
    text = font.render("たたかう",True,(255,255,255))
    screen.blit(text,(40,243))
    text = font.render("モンスター　　一匹",True,(255,255,255))
    screen.blit(text,(150,218))
    pygame.draw.line(screen,(255,255,255),(20,235),(116,235),1)
    #カーソル
    pygame.draw.polygon(screen, (255, 255, 255), [(25,250), (35, 255), (25, 260)])

    pygame.display.update()
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()

```
</details>


# 枠の点滅

<details><summary>ここをクリックしてください</summary>

Zキーを押したら枠が点滅します。

```python:
import pygame
import sys
from pygame.locals import *
import time

pygame.init()
screen = pygame.display.set_mode((160, 160))
pygame.display.set_caption('flame_flash')
damage_flash = True
flash = 0
while (1):
    screen.fill((0, 0, 0))
    if damage_flash:
        pygame.draw.rect(screen, (255,255,255), Rect(60,60,40,40), 3)
    pygame.display.update()
    #枠点滅
    if flash > 0:
        damage_flash = not damage_flash
        flash -= 1
        time.sleep(0.15)
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        if event.type == KEYDOWN:
            if event.key == K_z:
                damage_flash = False
                flash = 3
                time.sleep(0.5)

```

'if damage_flash:
     pygame.draw.rect(screen, (255,255,255), Rect(60,60,40,40), 3)'
        
if分をつけることで条件を満たさないときに、枠が消えるようにしています。

if event.type == KEYDOWN:
    if event.key == K_z:
        damage_flash = not damage_flash
        flash = 3
        time.sleep(0.5)

if event.type == KEYDOWN:
    if event.key == K_z:

　Zキーが押されたとき,処理を実行します。

'damage_flash = not damage_flash'

　damage_flashをFalseにします。
damage_flash = Falseと書いても同じことです。

flash = 3 点滅の回数のためにあります。

pygame.display.update()
    #枠点滅
    if flash > 0:
    damage_flash = not damage_flash
    flash -= 1
    time.sleep(0.15)

　このコードで一番大事なところです。
 
if flash > 0:

　0でなければ、処理を実行します。flashが3でしたから、3回実行します。キーハンドラーで1回実行してますから、合計4回です。消えて、現れて、消えて、現れて。
　キーハンドラーのところのflashが偶数だと消えたままになるので注意が必要です。

flash -= 1

flashを減らします。

time.sleep(0.15) 

 点滅の速さのためにあります。数字が大きければ遅く、小さければ早くなります。
 
　このコードのどこが大事なのでしょうか。
　ぼくは枠を点滅させるためにいろいろ考えましたが、完成させられずに早々にあきらめました。
　Copilotに聞いたところ、このコードを返したのですが、ぼくが最初に考えたのとほとんどおんなじです。何が違うのか詳しく見ると、pygame.display.update()の下にありました。何かを描画する際は必ずpygame.display.update()の上に書くものという先入観があったので盲点でした。ちなみに、pygame.display.update()の上だとうまくいきません。
 
</details>

# モンスター画像の点滅

<details><summary>ここをクリックしてください</summary>

Zキーを押したらモンスター画像が点滅します。

```python:

import pygame
import sys
from pygame.locals import *
import time

pygame.init()
screen = pygame.display.set_mode((160, 160))
pygame.display.set_caption('monster_flash')
#ここにモンスター画像のパスを貼り付ける
img = pygame.image.load(パス)
damage_flash = True
flash = 0
while (1):
    screen.fill((0, 0, 0))
    #モンスター画像の表示
    if damage_flash: 
        screen.blit(img, (25,25))  
    pygame.display.update()
    if flash > 0:
        damage_flash = not damage_flash
        flash -= 1
        time.sleep(0.15)
    for event in pygame.event.get():
        if event.type == QUIT:
            pygame.quit()
            sys.exit()
        if event.type == KEYDOWN:
            if event.key == K_z:
                damage_flash = False
                flash = 3
                time.sleep(0.5)

```
</details>