第18回 重力、ジャンプ、着地
3 / 4 接地中にジャンプする
このステップの目的
前の接地状態で入力を判定し、移動後の足元で接地状態を更新します。
入力を先に判定する
GameTuning.h の namespace player へ、ジャンプ開始時の上向き速度を追加します。
GameTuning.hcpp
inline constexpr float MaxFallSpeed = 720.0f;
inline constexpr float JumpPower = -660.0f;Player::Update() は入力、物理更新の順で接続します。ステップ1で用意した UpdateInput() の左右入力を残し、X速度を制限する行の下へ次を追加します。events は同関数の引数として宣言済みです。
Player.cpp(UpdateInputの末尾)cpp
velocity_.x = std::clamp(velocity_.x,
-tuning::player::MaxSpeed, tuning::player::MaxSpeed);
if (onGround_ && input.IsPressed(Key::Jump))
{
velocity_.y = tuning::player::JumpPower;
remainderY_ = 0.0f;
onGround_ = false;
events.jumped = true;
}JumpPowerは上向きの速度なので負の値です。IsPressedはキーを押した瞬間だけtrueを返します。入力判定より前にonGround_をfalseにすると、床に立っていてもジャンプできなくなります。
移動後に足元を調べる
先に Stage.h の public へ bool IsSolidAtRect(const dxgame::Rect& rect) const; を宣言し、Stage.cpp に次の関数を定義します。前のステップの PixelToTile() と IsSolidTile() を使います。
Stage.cppcpp
bool Stage::IsSolidAtRect(const dxgame::Rect& rect) const
{
if (rect.width <= 0.0f || rect.height <= 0.0f)
return false;
const int leftTile = PixelToTile(rect.x);
const int rightTile = PixelToTile(rect.x + rect.width - 0.001f);
const int topTile = PixelToTile(rect.y);
const int bottomTile = PixelToTile(rect.y + rect.height - 0.001f);
for (int y = topTile; y <= bottomTile; y++)
{
for (int x = leftTile; x <= rightTile; x++)
{
if (IsSolidTile(x, y))
return true;
}
}
return false;
}UpdatePhysicsは重力を加え、横移動、縦移動を行います。その後、命中矩形を1ピクセル下へずらしたgroundProbeで床を調べます。
Player.cpp(UpdatePhysics内の足元確認)cpp
MoveHorizontal(deltaTime);
MoveVertical(stage, deltaTime);
dxgame::Rect groundProbe = GetHitbox();
groundProbe.y += 1.0f;
onGround_ = stage.IsSolidAtRect(groundProbe);
if (onGround_ && velocity_.y >= 0.0f)
{
velocity_.y = 0.0f;
remainderY_ = 0.0f;
}足元は移動量が0ピクセルでも調べます。次のステップで UpdatePhysics() 全体とイベントへの接続をそろえてから実行し、以下の動作を確認します。
チェックリスト
- 床に立っているときだけ、Z キーでジャンプできる
- キーを長押ししても、着地後に自動で再ジャンプしない
- 床で静止しても接地状態が維持され、足場を離れると空中になる