Pygameを使って RPGを作る（9. 敵の配置と衝突判定）

# 概要
Mapに敵配置とPlayerとの衝突判定を追加

# Enemyクラス
```py
class Enemy(pg.sprite.Sprite):
    def __init__(self, pos, img_path, enemy_sprites):
        super().__init__(enemy_sprites)

        # イメージの読み込み
        self.img_path = img_path
        self.surface = pg.image.load(self.img_path).convert_alpha()
        self.surface = pg.transform.scale(self.surface, (64, 64))
        # 位置
        self.pos = pos
        # rect
        self.rect = self.surface.get_frect(topleft=pos)
```

# Mapクラス
敵は3種類のみ用意
```py
class Map(pg.sprite.Sprite):
    def __init__(self, collision_sprites, enemy_sprites):

        self.block_images = {
            "B" : "../maps/tree.png",
            "E" : ["../img/enemy/e001.png",'../img/enemy/e002.png','../img/enemy/e003.png']
        }
        self.name = 'map_01'
        self.current_map = TILE[self.name]

        self.collision_sprites = collision_sprites
        self.enemy_sprites = enemy_sprites

        self.map_list = []
        self.enemy_list = []
        self.player = None

    def create(self):
        enemy_count = 0
        for i, row in enumerate(self.current_map):
            for j, column in enumerate(row):
                x = j * TILE_SIZE
                y = i * TILE_SIZE

                if column == 'B':
                    self.block = Block((x,y), self.block_images['B'], self.collision_sprites)
                    self.map_list.append(self.block)
                if column == 'P':
                    self.player = Player((x,y), self.collision_sprites, self.enemy_sprites)
                if column == 'E':
                    self.enemy = Enemy((x,y), self.block_images['E'][enemy_count], self.enemy_sprites)
                    enemy_count += 1
                    self.enemy_list.append(self.enemy)

        return self.player, self.map_list, self.enemy_list
```
# Playerクラス
```py
class Player(pg.sprite.Sprite):
    
    def __init__(self, pos, collision_sprites, enemy_sprites):
        super().__init__()

        self.collision_sprites = collision_sprites
        self.enemy_sprites = enemy_sprites
        # イメージの読み込み
        self.surface = pg.image.load(IMAGE_PATH).convert_alpha()

        # 矩形（rect）と位置情報
        self.rect = self.surface.get_frect(topleft=pos)
        self.hit_box_rect = self.rect.inflate(-10,-10)

        # 移動関連
        self.key_speed = 10
        self.direction = pg.Vector2(0, 0)

    def handle_input(self, dt):
        """キーボード入力で移動処理を行う"""
        keys = pg.key.get_pressed()

        # キーが押されたときだけ移動
        self.direction.x = int(keys[pg.K_RIGHT]) - int(keys[pg.K_LEFT])
        self.direction.y = int(keys[pg.K_DOWN]) - int(keys[pg.K_UP])
        
        self.direction = self.direction.normalize() if self.direction else self.direction

    def collision_enemy(self, dt):
       
        # 水平方向、垂直方向の衝突判定を処理
        self.hit_box_rect.x += self.direction.x * self.key_speed * dt
        for enemy in self.enemy_sprites:
            if enemy.rect.colliderect(self.hit_box_rect):
                print('Enemyと衝突しました！')
        self.hit_box_rect.y += self.direction.y * self.key_speed * dt
        for enemy in self.enemy_sprites:
            if enemy.rect.colliderect(self.hit_box_rect):
                print('Enemyと衝突しました！')
        
        # メイン矩形をヒットボックスに同期
        self.rect.center = self.hit_box_rect.center

    def collision_block(self,dt):
        """ブロックとの衝突判定と位置調整を行う"""
        # 水平方向の衝突処理
        self.hit_box_rect.x += self.direction.x * self.key_speed *dt
        for block in self.collision_sprites:
            if block.rect.colliderect(self.hit_box_rect):
                if self.direction.x > 0:  # 右に移動中
                    self.hit_box_rect.right = block.rect.left
                elif self.direction.x < 0:  # 左に移動中
                    self.hit_box_rect.left = block.rect.right
                # 衝突後、移動量をリセット
                self.direction.x = 0

        # 垂直方向の衝突処理
        self.hit_box_rect.y += self.direction.y * self.key_speed *dt
        for block in self.collision_sprites:
            if block.rect.colliderect(self.hit_box_rect):
                if self.direction.y > 0:  # 下に移動中
                    self.hit_box_rect.bottom = block.rect.top
                elif self.direction.y < 0:  # 上に移動中
                    self.hit_box_rect.top = block.rect.bottom
                # 衝突後、移動量をリセット
                self.direction.y = 0

        # メイン矩形をヒットボックスに同期
        self.rect.center = self.hit_box_rect.center
        

    def update(self, dt):
        self.handle_input(dt)
        self.collision_block(dt)
        self.collision_enemy(dt)
```
# メインクラス

```py
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

        # 通過不可Sprite
        self.collision_sprites = pg.sprite.Group()
        # Enemy Sprite
        self.enemy_sprites = pg.sprite.Group()

        # Map
        self.player, self.map_list, self.enemy_list = Map(
            self.collision_sprites,
            self.enemy_sprites,
            ).create()

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

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

            # draw
            self.display_surface.fill(BLUE)

            # 衝突用ブロック
            for map in self.map_list:
                self.display_surface.blit(map.surface, map.rect)

            # Enemyの表示
            for enemy in self.enemy_list:
                self.display_surface.blit(enemy.surface, enemy.rect)

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

            # player Update
            self.player.update(dt)

            pg.display.update()

        pg.quit()

if __name__ == "__main__":
    new_game = game()
    new_game.run()
```

# ゲーム画面

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/576081/64f5f46f-c541-bdf0-4d2b-a1f92b4c8d74.png)