概要
プレイヤーの動きと衝突処理を実装
クラスPlayer
の説明
__init__
メソッド
プレイヤーオブジェクトの初期化を行います。
-
イメージの読み込み
self.surface = pg.image.load(IMAGE_PATH).convert()
IMAGE_PATH
で指定された画像を読み込んで、プレイヤーの外見として使用します。 -
位置情報
self.pos = pos
プレイヤーの初期位置を
pos
で指定します。 -
速度
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)
-
collision_direction
:衝突方向(水平か垂直か)を記録します。 -
hit_box_rect
:衝突判定用の矩形。inflate
を使用してサイズ調整も可能です。 -
direction
:プレイヤーの移動方向(Vector2
は2Dベクトル)。
-
input_with_rect
メソッド
プレイヤーの移動処理を行います。
-
キー入力の検出
keys = pg.key.get_pressed()
キーボードの現在の入力状態を取得します。
-
方向ごとの処理
- 左方向(
K_LEFT
):x座標を負の方向に移動します。self.rect.x -= 1 * dt * self.key_speed
- 右方向(
K_RIGHT
):x座標を正の方向に移動します。self.rect.x += 1 * dt * self.key_speed
- 下方向(
K_DOWN
):y座標を正の方向に移動します。self.rect.y += 1 * dt * self.key_speed
- 上方向(
K_UP
):y座標を負の方向に移動します。self.rect.y -= 1 * dt * self.key_speed
- 左方向(
-
衝突方向の記録
self.collision_direction = 'horizontal' または 'vertical'
水平方向(左右)または垂直方向(上下)のどちらに移動したかを記録します。
-
移動ベクトルの更新
self.direction.x または self.direction.y
移動方向を記録します(-1:負方向、1:正方向)。
collision
メソッド
プレイヤーとブロックの衝突処理を行います。
-
衝突判定
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
プレイヤーが右に移動中(
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
最終的な調整で以下のようにオブジェクト同士がぎりぎりのところで壁になっている
バグ修正
追記:
上記のプログラムには、斜め移動する時に、ワープしてしまうバグがありました。
修正版は以下になります。
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