2D横スクロールアクションゲームの壁判定についての質問

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
marumine
記事: 3
登録日時: 1年前

2D横スクロールアクションゲームの壁判定についての質問

#1

投稿記事 by marumine » 1年前

現在アクションゲームを作っています.
移動について、座標の更新と壁判定の処理をそれぞれ関数化してコードを整理したいのですが
上手くいかないので助言を頂けると助かります.

問題点について詳しく説明します.
自分は参考書に書かれてるように移動と壁判定は下記のように分けてすっきりさせたいのですが
void Update(){
move();
collide();
}

自分の描いた実際に書いたソースコードはこのようになってます.

コード:

void Player::move() {
	vy = (y - prev_y) + F;
	if (vy > BaseSize - 1) {
		vy = BaseSize - 1;
	}
	if (vy < -BaseSize + 1) {
		vy = -BaseSize + 1;
	}

	prev_y = y;
	y = y + vy;
	F = 1;

	x = x + vx;
	//天井にぶつかったかどうかの判定
	if (stage->Collision(x, y) || stage->Collision(x + width - 1, y)) {
		y = y / BaseSize * BaseSize + BaseSize;
	}

	//床に着いてるかどうかの判定
	if (stage->Collision(x, y + height - 1) || stage->Collision(x + width - 1, y + height - 1)) {
		vy = 0;
		jumping = false;
		y = y / BaseSize * BaseSize;
	}




	//x = x + vx;
	//左側の壁にぶつかってるかの判定
	if (stage->Collision(x, y) || stage->Collision(x, y + height - 1)) {
		x = x / BaseSize * BaseSize + BaseSize;
	}

	//右側の壁にぶつかってるかの判定
	if (stage->Collision(x + width - 1, y) || stage->Collision(x + width - 1, y + height - 1)) {
		x = x / BaseSize * BaseSize;
	}

	if (CheckHitKey(KEY_INPUT_Z) && !jumping) {
		F = -20;
		jumping = true;
	}
}
補足
BaseSizeはゲームオブジェクト全体の基本的なサイズで整数の32になっています
FはVerlet積分でのジャンプの処理に使っている変数です
Collision(x,y)はstageクラスが持つ2次元配列の地形データTerrain[y][x]が1か0を返す関数です


y座標の更新の直後に天井と床の判定が来てその次に
x座標の更新、左右の壁の判定が来るという感じで
座標の更新と壁判定が交互になっている状態です

x座標の更新をy座標の更新の直後に書いてコンパイルすると左右の壁にぶつかるとプレイヤーが床を突き抜けて画面に飛び出してしまいます。

どうすればよいでしょうか?

アバター
もるも
記事: 46
登録日時: 3年前
連絡を取る:

Re: 2D横スクロールアクションゲームの壁判定についての質問

#2

投稿記事 by もるも » 1年前

天井にぶつかったときの条件と左側の壁にぶつかったときの条件が同じなので、
壁に当たるとx座標とy座標が同時に座標修正されているようですね。
移動速度(vx、vy)があるようなので、
vxが正の数なら右を歩いている、負の数なら左を歩いているといった感じに判断できるので、

if(vx>0 && Collision(x,y)){  //右に移動して壁に当たったら
 //壁にめり込んだ分押し戻す
}
という感じで上下左右それぞれの当たり判定を細かくしてみてはいかかでしょうか。

アバター
usao
記事: 1529
登録日時: 6年前

Re: 2D横スクロールアクションゲームの壁判定についての質問

#3

投稿記事 by usao » 1年前

オフトピック
座標の補正式に widthやheight が使われていないのが,ぱっと見で不思議な感じ.
(width==height==BaseSize なのかな?)

marumine
記事: 3
登録日時: 1年前

Re: 2D横スクロールアクションゲームの壁判定についての質問

#4

投稿記事 by marumine » 1年前

回答ありがとうございます。
条件に関して指摘されている以外にも内容が被っている部分がありましたので
現在修正中です

座標の補正式にweightとheightを使っていないのは
ゲーム上のブロックのサイズが32×32で縦480横640の画面に敷き詰めるように並べています
これをStage[15][20]という2次元配列を使って中身が0ならブロックが無い、あれば1という風にしています
そして座標の補正では、該当する座標がめり込んでいる際、たとえばプレイヤーのx座標が左側の壁に
めり込んだ時は、x/32,y/32でプレイヤーの座標から配列の要素番号を求めます.この値のまま補正
するとブロックと重なってしまうので左のめり込みに対して右に押し出すのでちょうど32右に足すと
ブロックの隣に補正されるようにしています。
つまり、座標の補正はブロックのサイズに依存してプレイヤーのサイズは補正には影響しないので
BaseSizeだけで補正しています。

このやり方に問題があればまた修正します。

アバター
usao
記事: 1529
登録日時: 6年前

Re: 2D横スクロールアクションゲームの壁判定についての質問

#5

投稿記事 by usao » 1年前

図を描いてみました.
白と水色の正方形は32*32サイズを表しています.
ここで,赤枠のサイズがwidth*heightだとして
(x,y)座標をwidthやheight無しで求められるのかな? と.
Fig.png
右に行こうとしたら壁があって補正された雰囲気
Fig.png (1.32 KiB) 閲覧数: 2704 回

marumine
記事: 3
登録日時: 1年前

Re: 2D横スクロールアクションゲームの壁判定についての質問

#6

投稿記事 by marumine » 1年前

出来ないですね
いつも32×32でやってたので気づきませんでした
直ちに修正します

ISLe
記事: 2640
登録日時: 8年前
連絡を取る:

Re: 2D横スクロールアクションゲームの壁判定についての質問

#7

投稿記事 by ISLe » 1年前

現状のコードに対するアドバイスではないのですが、下のコードはこの掲示板に以前投稿したものです。

結果としてrcResultの各メンバに上下左右それぞれめり込んだ量が入ります。
左右あるいは上下ともに値が入っているとき、合計がキャラの幅以下なら壁に挟まれていて、キャラの幅を超えていれば壁の中にいる状態です。

良かったら参考にしてみてください。

コード:

RECT rcMover = { /* 当たり判定するキャラの座標で初期化 */ };
RECT rc, rcResult;
CopyRect(&rcResult, &rcMover);

{ // 当たり判定の対象の数だけ繰り返し
	// 四角いブロックの場合
	RECT rcBlock = { /* ブロックの座標で初期化 */ };
	if (IntersectRect(&rc, &rcMover, &rcBlock)) {
		// めり込んでいる分だけ領域を削る
		if (rc.left == rcMover.left) { // 左寄り
			if (rc.right > rcResult.left) rcResult.left = rc.right;
		}
		if (rc.top == rcMover.top) { // 上寄り
			if (rc.bottom > rcResult.top) rcResult.top = rc.bottom;
		}
		if (rc.right == rcMover.right) { // 右寄り
			if (rc.left < rcResult.right) rcResult.right = rc.left;
		}
		if (rc.bottom == rcMover.bottom) { // 下寄り
			if (rc.top < rcResult.bottom) rcResult.bottom = rc.top;
		}
	}
}

// めり込んでいる量に変換
rcResult.left -= rcMover.left;
rcResult.top -= rcMover.top;
rcResult.right = rcMover.right - rcResult.right;
rcResult.bottom = rcMover.bottom - rcResult.bottom;

返信

“C言語何でも質問掲示板” へ戻る