現在サイドビューの2Dアクションを作ろうとしています。
色々なサイトを参考にして、プレイヤーとブロックの当たり判定、押し返し処理はできたのですが、
プレイヤーと動くブロックの当たり判定で、行き詰ってしまいました。
状況としては
「左に動いているプレイヤー」と「右に動いているブロック」
「右に動いているプレイヤー」と「左に動いているブロック」
の判定を行うと、プレイヤーが上に押し出されてしまうというものです。
(移動している向きが同じ場合は押し出されませんでした。)
プレイヤーとブロックの当たり判定では
「1フレーム前からX座標だけ動かしたプレイヤー」と「ブロック」
「1フレーム前からY座標だけ動かしたプレイヤー」と「ブロック」
の2つの判定を行い、もし斜めからプレイヤーがブロックに侵入している場合は、
「Y軸」の押し返しを優先する
というものです。
動く足場の処理を色々調べてみましたが、詳しい記事は見つからず、こちらの質問掲示板でもキーワードが無効であるとしてヒットしませんでした。
アルゴリズムの考え方、もしくは2Dアクションの作り方に関する詳しい記事がありましたらご教授いただければ幸いです。
よろしくお願いします。
void Game::player_vs_block() {
//プレイヤーの着地判定を外す
player.set_ground(false);
//プレイヤーの1フレーム前の座標と現在の座標、X,Y軸における移動量を取得
RectF old_rect = player.get_old_rect();
RectF rect = player.get_rect();
double move_x = rect.x - old_rect.x;
double move_y = rect.y - old_rect.y;
//x座標だけ動かしたもの・y座標だけ動かしたもの
RectF rect_x = old_rect.movedBy(move_x, 0);
RectF rect_y = old_rect.movedBy(0, move_y);
//動くブロック用
bool on_move_block = false;
double on_move_block_x = 0;
double on_move_block_y = 0;
//動くブロックの判定
for (auto& b : block) {
if (b.get_name() == U"move_block") {
//プレイヤーとブロックが触れた場合
if (player.get_rect().intersects(b.get_old_rect())) {
bool bottom = 0;
//下(乗っている)
if (move_y > 0) {
//プレイヤーの下の辺をブロックの上に合わせる
if (rect_y.intersects(b.get_rect())) {
on_move_block = true;
on_move_block_x = b.get_moved_x();
on_move_block_y = b.get_moved_y();
}
}
}
}
}
//動くブロックに乗っているプレイヤーを動かす
if (on_move_block == true) {
player.move_x(on_move_block_x);
player.move_y(on_move_block_y);
}
//プレイヤーとブロックの判定
for (auto& b : block) {
if (player.get_rect().intersects(b.get_rect())) {
bool right = false;
bool left = false;
bool top = false;
bool bottom = false;
//右
if (move_x > 0) {
//プレイヤーとブロックが触れた場合
if (rect_x.intersects(b.get_rect())) {
right = true;
}
}
//左
else if (move_x < 0) {
//プレイヤーとブロックが触れた場合
if (rect_x.intersects(b.get_rect())) {
left = true;
}
}
//下
if (move_y > 0) {
//プレイヤーとブロックが触れた場合
if (rect_y.intersects(b.get_rect())) {
bottom = true;
}
}//上
else if (move_y < 0) {
//プレイヤーとブロックが触れた場合
if (rect_y.intersects(b.get_rect())) {
top = 1;
}
}
//斜め判定
if (left == true or right == true) {
if (top == true or bottom == true) {
left = false;
right = false;
}
}
if (right == true) {
player.set_pos_x(b.get_rect().x - player.get_size());
//慣性を0にする
player.zero_inertia();
}
else if (left == true) {
player.set_pos_x(b.get_rect().x + b.get_rect().w);
//慣性を0にする
player.zero_inertia();
}
if (bottom == true) {
player.set_pos_y(b.get_rect().y - player.get_size());
//地上にいる判定にする
player.set_ground(true);
//重力加速度を0にする
player.zero_speed_y();
//コヨーテタイム
player.set_coyote_time(0.2);
}
else if (top == true) {
player.set_pos_y(b.get_rect().y + b.get_rect().h);
//重力加速度を0にする
player.zero_speed_y();
}
}
}
}