0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Pygameを使って RPGを作る(6. 衝突判定後のPlayerの移動を制限する)

Last updated at Posted at 2025-01-01

概要

プレイヤーの動きと衝突処理を実装


クラスPlayerの説明

__init__メソッド

プレイヤーオブジェクトの初期化を行います。

  1. イメージの読み込み

    self.surface = pg.image.load(IMAGE_PATH).convert()
    

    IMAGE_PATHで指定された画像を読み込んで、プレイヤーの外見として使用します。

  2. 位置情報

    self.pos = pos
    

    プレイヤーの初期位置をposで指定します。

  3. 速度

    self.key_speed = 10
    

    プレイヤーが移動する速さを設定します。

  4. 矩形(rect)の設定

    self.rect = self.surface.get_frect(topleft=pos)
    

    読み込んだ画像の矩形情報を取得し、プレイヤーの位置情報に基づいて初期位置を設定します。

  5. 衝突関連の初期値

    self.collision_direction = ''
    self.hit_box_rect = self.rect.inflate(0, 0)
    self.direction = pg.Vector2(0, 0)
    
    • collision_direction:衝突方向(水平か垂直か)を記録します。
    • hit_box_rect:衝突判定用の矩形。inflateを使用してサイズ調整も可能です。
    • direction:プレイヤーの移動方向(Vector2は2Dベクトル)。

input_with_rectメソッド

プレイヤーの移動処理を行います。

  1. キー入力の検出

    keys = pg.key.get_pressed()
    

    キーボードの現在の入力状態を取得します。

  2. 方向ごとの処理

    • 左方向(K_LEFT):
      self.rect.x -= 1 * dt * self.key_speed
      
      x座標を負の方向に移動します。
    • 右方向(K_RIGHT):
      self.rect.x += 1 * dt * self.key_speed
      
      x座標を正の方向に移動します。
    • 下方向(K_DOWN):
      self.rect.y += 1 * dt * self.key_speed
      
      y座標を正の方向に移動します。
    • 上方向(K_UP):
      self.rect.y -= 1 * dt * self.key_speed
      
      y座標を負の方向に移動します。
  3. 衝突方向の記録

    self.collision_direction = 'horizontal' または 'vertical'
    

    水平方向(左右)または垂直方向(上下)のどちらに移動したかを記録します。

  4. 移動ベクトルの更新

    self.direction.x または self.direction.y
    

    移動方向を記録します(-1:負方向、1:正方向)。


collisionメソッド

プレイヤーとブロックの衝突処理を行います。

  1. 衝突判定

    if block.rect.colliderect(self.rect):
    

    プレイヤーとブロックの矩形が重なった場合に衝突処理を実行します。

  2. 衝突処理

    • 水平方向の衝突:

      if self.collision_direction == 'horizontal':
          if self.direction.x > 0: self.rect.right = block.rect.left
          if self.direction.x < 0: self.rect.left = block.rect.right
      

      プレイヤーが右に移動中(self.direction.x > 0)なら、ブロックの左端にプレイヤーの右端を合わせます。逆に左移動中なら、ブロックの右端にプレイヤーの左端を合わせます。

    • 垂直方向の衝突:

      elif self.collision_direction == 'vertical':
          if self.direction.y > 0: self.rect.bottom = block.rect.top
          if self.direction.y < 0: self.rect.top = block.rect.bottom
      

      プレイヤーが下に移動中(self.direction.y > 0)なら、ブロックの上端にプレイヤーの下端を合わせます。逆に上移動中なら、ブロックの下端にプレイヤーの上端を合わせます。


要約

  • Playerクラスは、プレイヤーの位置と移動、さらにブロックとの衝突判定を管理します。
  • 移動はキーボード入力に基づき、矩形(rect)を操作します。
  • 衝突時には、移動方向に応じてプレイヤーの位置を調整し、ブロックを通り抜けないようにします。
from settings import * 
import pygame as pg

class Player:
    def __init__(self, pos):
        # イメージの読み込み
        self.surface = pg.image.load(IMAGE_PATH).convert()
        # 位置
        self.pos = pos
        # speed
        self.key_speed = 10
        # rect
        self.rect = self.surface.get_frect(topleft=pos)
        self.collision_direction = ''

        self.hit_box_rect = self.rect.inflate(0,0)
        self.direction = pg.Vector2(0,0)

    def input_with_rect(self, dt):
        # キーボード押されているかをキャッチしてくれる(キーボードイベントリスナー)
        keys = pg.key.get_pressed()
        if keys[pg.K_LEFT]:
            self.rect.x -= 1 * dt * self.key_speed
            self.collision_direction ='horizontal'
            self.direction.x = -1
        elif keys[pg.K_RIGHT]:
            self.rect.x += 1 * dt * self.key_speed
            self.collision_direction ='horizontal'
            self.direction.x = 1
        elif keys[pg.K_DOWN]:
            self.rect.y += 1 * dt * self.key_speed
            self.collision_direction ='vertical'
            self.direction.y = 1
        elif keys[pg.K_UP]:
            self.rect.y -= 1 * dt * self.key_speed
            self.collision_direction ='vertical'
            self.direction.y = -1

    def collision(self, block_list):
        for block in block_list:
            if block.rect.colliderect(self.rect):
                if self.collision_direction == 'horizontal':
                    if self.direction.x > 0: self.rect.right = block.rect.left
                    if self.direction.x < 0: self.rect.left = block.rect.right
                elif self.collision_direction == 'vertical':
                    if self.direction.y > 0: self.rect.bottom = block.rect.top
                    if self.direction.y < 0: self.rect.top = block.rect.bottom

image.png

最終的な調整で以下のようにオブジェクト同士がぎりぎりのところで壁になっている
image.png

バグ修正

追記:
上記のプログラムには、斜め移動する時に、ワープしてしまうバグがありました。
修正版は以下になります。

   def handle_input(self):
        """キーボード入力で移動処理を行う"""
        keys = pg.key.get_pressed()
        self.direction = pg.Vector2(0, 0)  # 初期化

        if keys[pg.K_LEFT]:
            self.direction.x = -1
        if keys[pg.K_RIGHT]:
            self.direction.x = 1

        if keys[pg.K_UP]:
            self.direction.y = -1
        if keys[pg.K_DOWN]:
            self.direction.y = 1
        
        self.direction = self.direction.normalize() if self.direction else self.direction

    def collision(self, block_list, dt):
        """ブロックとの衝突判定と位置調整を行う"""
        self.hit_box_rect.x += self.direction.x * self.key_speed *dt
        for block in block_list:
            if block.rect.colliderect(self.hit_box_rect):
                print(f"Collision detected: {self.hit_box_rect}, {block.rect}")
                # if self.collision_direction == 'horizontal':
                if self.direction.x > 0 :
                    self.hit_box_rect.right = block.rect.left
                if 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 block_list:
            if block.rect.colliderect(self.hit_box_rect):
                print(f"Collision detected: {self.hit_box_rect}, {block.rect}")    
                # if self.collision_direction == 'vertical':
                if self.direction.y > 0: self.hit_box_rect.bottom = block.rect.top
                if self.direction.y < 0: self.hit_box_rect.top = block.rect.bottom
                self.direction.y = 0
        
        # メイン矩形をヒットボックスに同期
        self.rect.center = self.hit_box_rect.center
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?