Pygameを使って RPGを作る（3. キャラクター配置と移動）

# 概要
本記事はキャラクターを配置と移動を実現する

配置については、前回のSurfaceにイメージ画像を読み込ませたオブジェクトを代入するだけで実現できる。
今回はキーボードリスナーを追加し、キャラクターをキーボードで動かすようにする

# 使い方の例

https://www.pygame.org/docs/ref/image.html#pygame.image.load
公式だとloadしたイメージがSurfaceになっている。
load(filename) -> Surface

```py
# surface
IMAGE_PATH = '../img/F1.png'
self.test_surface = pg.image.load(IMAGE_PATH)
# fillはコメントアウトしておく。
# self.test_surface.fill(RED)
```

# キャラクター操作
配置したキャラクターをキーボード操作で動かせるようにする

1. キャラクターをゆくゆく育てるため、Playerクラスを作成する
### player.py
```py
from settings import * 
import pygame as pg

class Player:
    def __init__(self):
        self.surface = pg.image.load(IMAGE_PATH)
```
### main.py
```py 
import pygame as pg
from settings import *

from player import Player

class game:
    def __init__(self):
        pg.init()

        # screen
        self.display_surface = pg.display.set_mode((WIDTH, HEIGHT))
        # title
        pg.display.set_caption(TITLE)
        # clock
        self.clock = pg.time.Clock()
        self.running = True

        # Playerクラスのインスタンス宣言
        self.player = Player()

    def run(self):
        """ゲームループ"""
        dt = self.clock.tick(FPS) / 1000

        dx = 0
        direction = 1
        while self.running:
            # イベント処理
            for event in pg.event.get():
                if event.type == pg.QUIT:
                    self.running = False

            # draw
            self.display_surface.fill(BLUE)

            # playerの表示    
            self.display_surface.blit(self.player.surface,(100, 100))

            pg.display.update()

        pg.quit()

if __name__ == "__main__":
    new_game = game()
    new_game.run()
```
メインクラスでインスタンスと表示は以下のようにメインクラスを変更する
```py
# Playerクラスのインスタンス宣言
self.player = Player()
# 中略
# playerの表示    
self.display_surface.blit(self.player.surface,(100, 100))
```
2.キーボードイベントリスナーを作成する
Playerクラスにinputメソッドを実装
```py
def input(self):
    # キーボード押されているかをキャッチしてくれる（キーボードイベントリスナー）
    keys = pg.key.get_pressed()
    if keys[pg.K_LEFT]:
        print('左矢印が押されました')
    elif keys[pg.K_RIGHT]:
        print('右矢印が押されました')
```
メインクラスで、メソッドをコールする
```py
# Playerクラスのインスタンス宣言
self.player = Player()
# 中略
# playerの表示    
self.display_surface.blit(self.player.surface,(100, 100))
# キーボードイベントリスナー
self.player.input()
```
これでキーボードイベントが押されたら、メッセージ表示される

<B>※キーボードイベント判定はPlayerクラスでやるのが肝心な所。</B>

上記の実装だとキーボード一回押したら、FPS処理速度が速いため、何回も同じメッセージが表示されるので、あまりよくない。

次のようにしておくと解消されます。
```py 
class Player:
    def __init__(self):
        self.surface = pg.image.load(IMAGE_PATH)
        # フラグを追加
        self.push_flag = False

    def input(self):
        # キーボード押されているかをキャッチしてくれる（キーボードイベントリスナー）
        keys = pg.key.get_pressed()
        if keys[pg.K_LEFT] and not self.push_flag:
            print('左矢印が押されました')
            self.push_flag = True
        elif keys[pg.K_RIGHT] and not self.push_flag:
            print('右矢印が押されました')
            self.push_flag = True
        # キーが押されていない場合にフラグをリセット
        elif not (keys[pg.K_LEFT] or keys[pg.K_RIGHT]):
            self.push_flag = False
```
3.キャラクターを動かすためには、メインクラスとPlayerクラスの間に、Playerの位置のやり取りするインターフェースが必要になるため、Playerクラスに位置を追加する
```py
class Player:
    def __init__(self, pos):
        self.surface = pg.image.load(IMAGE_PATH)
        # フラグを追加
        self.push_flag = False
        # 位置
        self.pos = pos
```
メインクラス：
```py
# Playerクラスのインスタンス宣言
self.player = Player([100,100])

# 中略
# playerの表示    
self.display_surface.blit(self.player.surface,self.player.pos)
```
4.あとはキーボードリスナーに位置を変更するだけ
```py
from settings import * 
import pygame as pg

class Player:
    def __init__(self, pos):
        self.surface = pg.image.load(IMAGE_PATH)
        # フラグを追加
        self.push_flag = False
        # 位置
        self.pos = pos
        
    def input(self):
        # print(f'pos:{self.pos}')
        # キーボード押されているかをキャッチしてくれる（キーボードイベントリスナー）
        keys = pg.key.get_pressed()
        if keys[pg.K_LEFT] and not self.push_flag:
            print('左矢印が押されました')
            self.pos[0] -= 10
            self.push_flag = True
        elif keys[pg.K_RIGHT] and not self.push_flag:
            print('右矢印が押されました')
            self.push_flag = True
            self.pos[0] += 10
        # キーが押されていない場合にフラグをリセット
        elif not (keys[pg.K_LEFT] or keys[pg.K_RIGHT]):
            self.push_flag = False
```
ゲーム画面
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/80955c2a-c150-c95a-0d19-d112379af0b1.png)

```terminal
$ python base_main.py 
pygame-ce 2.5.2 (SDL 2.30.8, Python 3.12.2)
右矢印が押されました
左矢印が押されました
右矢印が押されました
右矢印が押されました
右矢印が押されました
```