アクションゲームにおける壁の当たり判定など2 with OpenSiv3D

f:id:movementi:20180515153823j:plain
上下左右どこから触れても大丈夫

前回の記事の最後にも書きましたが下からブロックに当たったときの処理を書いていないので今回の記事で書いていきます。解説は短めです。

前回までの記事

movement.hatenablog.jp movement.hatenablog.jp movement.hatenablog.jp 完全に続きものだから先にこっち読んでくださいね。

Siv3Dのバージョン

OpenSiv3D 0.2.5を使います。

コード全文

コピペするだけで動きます。

前回の記事から少しだけ弄りました。 movement.hatenablog.jp

解説

Blockクラスの変更

テクスチャからカラーへ

m_region.movedBy(-m_playerPosition + Window::Center()).draw(color);

OpenSiv3D ver0.2.5になってもExample/Brick.jpgが用意されていないので、テクスチャを使用しない形に変更しました。

BlockクラスにColor型の変数colorを追加しdraw()の引数にcolorを入れます。Texture周りは消しておきましょう。

当たり判定の取得

 const RectF getRegion() const
    {
        return m_region;
    }

前までは関数内でdoubleにして返していましたがRectF型を返すように変更しました。

今見直すと旧版はえらい回りくどいですね。

//ブロックの上部のY座標を取得
//新
double blockY = blocks[i].getRegion().topCenter().y;
//旧
double topY() const
    {
        return (m_region.top().begin.y + m_region.top().end.y) / 2.0;
    }

//ブロック右辺のLineを取得
//新
getRegion().right()
//旧
std::pair<double, double> pair_sideX() const
    {
        return{ (m_region.left().begin.x + m_region.left().end.x) / 2.0, (m_region.right().begin.x + m_region.right().end.x) / 2.0};
 }

ブロック下部からの接触

今回のキモ部分ですね。手順はまずプレイヤーが上昇中か確認。ブロックとプレイヤーの当たり判定上部とで接触判定を行います。その後の処理は下の感じです。

double blockY = blocks[i].getRegion().bottomCenter().y;
ブロック下部中点のY座標を取得。
if (m_position.y - m_size.y < blockY)
//m_position.y ==プレイヤーの座標(足元中央)
//m_size.y == キャラの高さ
    {
        m_position.y = blockY + m_size.y + FLT_EPSILON;
        //足元中央のY座標 = ブロック下部中点のY座標+キャラの高さ+ FLT_EPSILON
    }
        m_speed.y = 0.0; //お好みで
//FLT_EPSILONとはfloatにおいて1.0f+FLT_EPSILON != 1.0fになる一番小さな数で10^-5以下です。

ほとんど床との接触と同じですね。 ブロックとの接触時にプレイヤーの上昇速度を0にするのは個人の好みやゲームの仕様で決めてください。

Main関数の方でブロックを1つ追加しています。ジャンプして下から当たってみてください。

f:id:movementi:20180517174126p:plain
追加したブロック

まとめ

これで上下左右どこから触れても大丈夫な形に進化しました。ジャンプの基本的な部分はほぼ完成といっていいでしょう。

実はブロックが細すぎたり、移動速度が大きすぎるとブロックを貫通してしまう仕様ですが…

普通に見える大きさのブロック、普通に目で追える移動速度ならあまり問題にはなりません。気になるかたは是非改良してみてください。