HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2012
0128
バロ2Dアクションの当たり判定後の処理14未解決


バロ

リンク

2012/1/28(Sat) 18:42:45|NO.44580

今2Dアクションの当たり判定部分を作っています
自機とブロックが当たるとき、ブロックの右辺、左辺、上辺、下辺に分けて
判定をしています。そしてそれぞれの辺に自機が当たったとき位置をもとに
戻して処理をしています。
自機の右下部分がブロックの左上部分と重なっているとします
こういう状態になっているときブロックの左辺と上辺にあたり判定がでて
元の位置に戻そうとして、左にずれる+上にずれるで、当たると斜め左上にずれます。
しかし、自分がしたいことはたんに「右の壁に当たる」or「下の壁に当たる」
ということです。
矛盾してると思いますが、見た目上おかしくならないでうまくいくよう
ひとつの当たり判定だけにしたいのです
何か上手い方法はないでしょうか?分かりにくい文章ですがご教授願います。



この記事に返信する


晩御飯

リンク

2012/1/28(Sat) 20:45:01|NO.44582

まずある辺の「位置を戻す処理」をしてから次の辺の当たり判定をするとか



暇人

リンク

2012/1/29(Sun) 03:03:38|NO.44585

ゲームで使う斜め移動が45度しか無いならxとyのめり込みの差を比較すれば良い

そんなにきっちりした判定が必要ないなら動かした(戻した)先にブロックが
無ければそこで右下の判定を終らせるって手もある(先に動かした方向が優先されるが)

違う場合色々方法あると思うけど
・移動量(速度)と距離で左辺上辺どっちの境界線を先に越えたか
・移動前座標と移動後の座標の角度を取って移動前右下座標からからブロック左上座標を角度にして大小で上左分ける
・移動前右下と移動先右下の座標を線分としてブロック左上を点として線分と点の判定でどっちの領域に有るかを見る
など


距離と速度の例(割り算使うから0判定してるのがちょっとアレだが・・・)

bx=200//ブロック左 by=200//上 jo_x=bx-40//自機移動前座標左 jo_y=by-50//上 repeat color boxf color 200,200,200 boxf bx,by,bx+31,by+31//ブロック j_x=mousex//自機左 j_y=mousey//上 jr_x=j_x+31//自機右 jd_y=j_y+31//下 color 0,125,255 line jr_x,j_y,j_x,j_y:line jr_x,jd_y:line j_x,jd_y:line j_x,j_y//自機 jor_x=jo_x+31//自機移動前座標右 jod_y=jo_y+31//下 color 0,255,0 line bx,by,jor_x,jod_y//自機移動前右下からブロック右上のまでのライン js_x=jo_x-j_x//自機の速度 js_y=jo_y-j_y d_x=jor_x-bx//自機右下からブロック左上までの距離 d_y=jod_y-by if js_x!0{xx=absf(double(d_x)/js_x)}//距離を速度で割る if js_y!0{yy=absf(double(d_y)/js_y)} color 255,255,255 pos 150,250 mes "xx="+xx mes "yy="+yy //小さい方が先に辺の境界線を超えるから違う方の辺にしか当たれない if (xx>yy) {mes "左"}else{mes "上"} color 255 line jor_x,jod_y,jr_x,jd_y//自機移動前右下から自機右下までのライン redraw 1 wait 1 stick lc if lc=256{//左クリックで移動前左上座標セット jo_x=mousex jo_y=mousey } redraw 0 loop
これが使えるのは自機が移動前に当たったブロックのどの辺の正面には無く
当たった自機の角とは対角線にあるブロックの角のみ(自機の左下ならブロック右上)



おちゃっこ

リンク

2012/1/29(Sun) 05:52:24|NO.44586

やりたいことと違うかもしれませんが
当たっていないときの位置を保存しておいて
当たったらその保存してある場所に戻すというのではダメですか??



M

リンク

2012/1/29(Sun) 23:12:23|NO.44603

1フレーム内で「どの障害物」と「どの方向で当たったか」という情報を記憶しておき、自機と障害物との角度(あるいは自機のベクトル)を元に、どの辺に当たったのかを選ぶようにする。
図説できる掲示板がほしい



暇人

リンク

2012/1/30(Mon) 00:36:59|NO.44604

NO.44585の

>if js_x!0{xx=absf(double(d_x)/js_x)}//距離を速度で割る
>if js_y!0{yy=absf(double(d_y)/js_y)}
の部分を

xx=sqrt(js_x*js_x)*d_y yy=sqrt(js_y*js_y)*d_x

	
sq=sqrt(js_x*js_x+js_y*js_y) xx=sq*js_y*d_x yy=sq*js_x*d_y

変えると割り算を使わないので0判定しなくて良いからすっきりしてるかもしれない



バロ

リンク

2012/1/30(Mon) 18:22:50|NO.44609


#define SCREEN_WIDTH 640 //画面のxサイズ #define SCREEN_HEIGHT 480 //画面のyサイズ #define ME_S_X 16 //自分のxサイズ #define ME_S_Y 32 //自分のyサイズ #define CHIP_SIZE 32 //マップチップのx,yサイズ #define MAP_WIDTH SCREEN_WIDTH / CHIP_SIZE //xのチップ数 #define MAP_HEIGHT SCREEN_HEIGHT / CHIP_SIZE //yのチップ数 *hitcheck_b //右壁の場合 if me_x+ME_S_X>CHIP_SIZE*wid{ if me_x+ME_S_X<CHIP_SIZE*wid+CHIP_SIZE{ if me_y+ME_S_Y>CHIP_SIZE*hei{ if me_y<CHIP_SIZE*hei+CHIP_SIZE{ me_vx=-(me_x+ME_S_X-CHIP_SIZE*wid) } } } } //左壁の場合 if me_x<CHIP_SIZE*wid+CHIP_SIZE{ if me_x>CHIP_SIZE*wid{ if me_y+ME_S_Y>CHIP_SIZE*hei{ if me_y<CHIP_SIZE*hei+CHIP_SIZE{ me_vx=CHIP_SIZE*wid+CHIP_SIZE-me_x } } } } //下壁の場合 if me_y+ME_S_Y>CHIP_SIZE*hei{ if me_y+ME_S_Y<CHIP_SIZE*hei+CHIP_SIZE{ if me_x+ME_S_X>CHIP_SIZE*wid{ if me_x<CHIP_SIZE*wid+CHIP_SIZE{ me_vy=-(me_y+ME_S_Y-CHIP_SIZE*hei) j_frg=0 } } } } return
これが当たり判定部分のコードです、me_xとme_yは自機のx座標,y座標です
壁にめりこんだ分の数値を計算してme_x、me_yにその数値を足してます。



バロ

リンク

2012/1/30(Mon) 18:41:22|NO.44610

初心者なので分からないこともありますがお許しを。

>>晩御飯さん
申し訳ありませんがよく分からないです

>>暇人さん 
ありがとうございます。
 とてもありがたいのですが、条件が限られていると厳しいですね…

>>おちゃっこさん 
それを考えたことがあるのですが、例えば毎フレームで自機が15ドットずつ進むと
 します。(速度が15ドット)そして壁にぶつかります。4ドットめり込むとします。
 ぶつかる前の自機の位置を保存したとしても、毎フレーム15ドット進んでいるので
 4-15=-11ドットで、自機は壁から-11ドット離れたとこにいることになり、壁に当
 たってるようには見えないと思うのです。自分の推測なのでちゃんとした方法が
 あるかもしれませんが。

>>Mさん 
詳しく教えてもらいたいです><



晩御飯

リンク

2012/1/30(Mon) 23:04:01|NO.44617

縦方向と横方向の当たり判定と戻す処理を同時にやろうとすれば斜めに移動するのも当然なので
縦方向の当たり判定と戻す処理をしてから横方向の当たり判定と戻す処理をしたら問題ないのでは
という意味です
もちろん縦横逆でも構いませんが



M

リンク

2012/1/30(Mon) 23:38:55|NO.44620

そだ。前にやった手なのですが、参考に。
障害物ではなくて、自機に当たり判定を作るんですよ。
具体的には、自機の周囲四方向に猫のヒゲのような触覚(?)を付けるんです。
で、そのヒゲに何かぶつかったら、その方向には進まないようにする。



ひじき

リンク

2012/1/31(Tue) 10:48:12|NO.44621

私は、それほど処理速度が必要でない場合、
かなり効率としては悪い方法ですが、

例えば、自機のx速度が+3で、y速度が+5だった時、
毎フレーム、x方向の移動を3回 y方向の移動を5回 という風に行なっていました。
具体的には、


x = 自機X座標 y = 自機Y座標 vx = 自機X移動量 vy = 自機Y移動量 ;X方向の移動処理 repeat vx if vx >= 1 { if ここでx+1の位置が通行可能かを調べる { ;通行可能だった場合 x + 1 vx - 1 } else { vx = 0 } } if vx <= -1 { if ここでx-1の位置が通行可能かを調べる { x - 1 vx + 1 } else { vx = 0 } } if vx = 0 { break } loop ;以下同じ
※上記スクリプトは実際に実行できることを前提に組んでおりません。

という風にして、壁にめり込まず且つ壁とピッタリの位置まで移動するように組んだことがあります。
ただその時私が作ったゲームは自機の移動速度が最高でも-4〜+4程度だったおかげで
このような雑な組み方でなんとかなりましたが、
自機の移動速度が早くなったり、そもそも実数で座標を管理しているゲームだと、
その他の部分で更に面倒なことがたくさん起こるのであまりオススメできません。
もしお作りになろうとしているゲームが、
整数で座標を管理していて、且つ自機の移動最高速度が遅いものであれば、
割とすんなり組めてしまい処理速度もそんなに気にならないものだと思います。
とは言うもののかなり強引で雑な組み方ではありますが・・・;
私には他のものは思いつかなかったです。お力になれれば幸いです。



通りすがり

リンク

2012/1/31(Tue) 16:20:04|NO.44622

線分交差を使って処理するという方法もありますよ。

自分が移動した分の線分(前フレームの位置から現在の位置までの線分)と、
ブロック4辺の線分をそれぞれ線分交差でチェックすれば交差するのは大抵1辺だけです。
稀に2辺交差することがありますが、それは交点の位置をチェックすれば解決します。



暇人

リンク

2012/1/31(Tue) 21:56:35|NO.44631

"}"の数が違ってたから削除して再掲載

> とてもありがたいのですが、条件が限られていると厳しいですね…
他の判定と組み合わせて使えば良いだけ

○B○
A■C
○D○

Aからブロックの上下右辺には当たれないんだから
白丸以外の方向以外からブロックに当たった場合は
移動前の座標からどの辺に当たるかは簡単な比較だけで判断できる

NO.44609のが
・マップチップ総当りで判定してる
・全て判定が終ってからme_x、me_yに値を足してる
これを前提に下のを作ってみた

移動前me_x、移動前me_yは
キー操作入力前のme_x、me_yを代入したとして作ってる

*hitcheck_b //右壁の場合 if me_x+ME_S_X>CHIP_SIZE*wid{ if me_x+ME_S_X<CHIP_SIZE*wid+CHIP_SIZE{ if me_y+ME_S_Y>CHIP_SIZE*hei{ if me_y<CHIP_SIZE*hei+CHIP_SIZE{ if 移動前me_x < me_x {//右に移動中 if (移動前me_x+ME_S_X) <= (CHIP_SIZE*wid) {//移動前は当たったブロックの縦ラインに重なってはいなかった 横+1 me_vx=-(me_x+ME_S_X-CHIP_SIZE*wid) } } } } } } //左壁の場合 if me_x<CHIP_SIZE*wid+CHIP_SIZE{ if me_x>CHIP_SIZE*wid{ if me_y+ME_S_Y>CHIP_SIZE*hei{ if me_y<CHIP_SIZE*hei+CHIP_SIZE{ if 移動前me_x > me_x {//左に移動中 if 移動前me_x >= (CHIP_SIZE*wid+CHIP_SIZE) { 横+1 me_vx=CHIP_SIZE*wid+CHIP_SIZE-me_x } } } } } } //下壁の場合 if me_y+ME_S_Y>CHIP_SIZE*hei{ if me_y+ME_S_Y<CHIP_SIZE*hei+CHIP_SIZE{ if me_x+ME_S_X>CHIP_SIZE*wid{ if me_x<CHIP_SIZE*wid+CHIP_SIZE{ if 移動前me_y < me_y {//下に移動中 if 移動前me_y+ME_S_Y <= CHIP_SIZE*hei {//移動前は当たったブロックの横ラインに重なってはいなかった 床+1 me_vy=-(me_y+ME_S_Y-CHIP_SIZE*hei)//j_frg=0は実際にme_vyをme_yに足す時にする } } } } } } return
判定のループが全て終った後に

//横、床 //片方又は両方が2の場合 並んだブロックに二つまたがって当たってる 2になってるのを優先し2以外は破棄 //片方が1で違う方が0の場合 1になってる方に移動 //両方1の場合 斜め方向から一番近い角に当たった ブロックの上に乗る方を優先(簡易処理) if 横=床{ if 床=2{ me_x+me_vx me_y+me_vy:j_frg=0 }else{ if 床=1{//ブロックの斜め方向から一番近い角に当たった(ここにNO.44585、NO.44604の処理を組み込むことも可能) me_y+me_vy:j_frg=0//斜め方向から当たったらブロックの上に乗る方を優先 } } }else{ if 横>床 { if 横>0 {me_x+me_vx} }else{ if 床>0 {me_y+me_vy:j_frg=0} } } 横=0 床=0
このスクリプトは頭の中でしか動かして無いから正しいかは不明



49

リンク

2012/2/2(Thu) 17:25:29|NO.44665

いい質問ですね。自分もこの手のことで悩みました。
スーパーマリオのようなものでも落下のときに下方向の判定をとるか横方向の判定をとるか
はちょっと難しい。
ぶつかる直前フレームの位置を参照してどっちをとるかでしょうね。



レッド

リンク

2012/2/3(Fri) 18:47:32|NO.44697

当たった時点で、その当たったブロックの座標ギリギリに
主人公の位置をイコールしてしまうのはどうでしょう。
それを縦と横に作って、でも1つの処理でまとめると言う感じになってないですけど。



ONION software Copyright 1997-2023(c) All rights reserved.