2D見下ろし型ゲームで円形の当たり判定を持った物体と正方形の当たり判定を持った壁の当たり判定をしたいです。
ただ判定をするだけなら龍神録のレーザーと同じ要領でやればよいのですが、今回は座標の補正と反射ベクトルの計算もしたいので行き詰ってしまった次第です。
現在パラメータとして持ってるのは
物体:中心座標 2次元ベクトル、速度 2次元ベクトル、半径 実数型、反発係数 実数型
壁:中心座標 2次元ベクトル、一辺の長さ 実数型、反発係数、実数型
以上です
ベクトルはもちろん実数型2つでx要素・y要素を保持していて正規化・内外積を含む基本的な操作はできます。
反発係数は物体のものと壁のものを掛け合わせて反発係数とする予定です。
以上のパラメータを用いて想定通りの当たり判定と座標・速度補正は可能でしょうか。
可能でしたらどのような方法で実装すれば良いでしょうか。
ネット上で探しても、円と正方形(長方形)の判定の仕方に関する情報があまりなく、反射や座標補正のことも含めると情報量は絶望的でした。
正方形と円の当たり判定(補正付き)
Re: 正方形と円の当たり判定(補正付き)
自分で実装するなら、正方形を、適当な大きさの円で近似するのが吉。
そうでなければ、適当な物理演算エンジン
https://ja.wikipedia.org/wiki/%E7%89%A9 ... 8%E3%83%B3
を使用の事。
そうでなければ、適当な物理演算エンジン
https://ja.wikipedia.org/wiki/%E7%89%A9 ... 8%E3%83%B3
を使用の事。
VTuber:
東上☆海美☆(とうじょう・うみみ)
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。
中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。
東上☆海美☆(とうじょう・うみみ)
http://atassyu.php.xdomain.jp/vtuber/index.html
レスがついていないものを優先して、レスするみみ。時々、見当外れなレスしみみ。
中の人:
手提鞄あたッしュ、[MrAtassyu] 手提鞄屋魚有店
http://ameblo.jp/mratassyu/
Pixiv: 666303
Windows, Mac, Linux, Haiku, Raspbery Pi, Jetson Nano, 電子ブロック 持ち。
Re: 正方形と円の当たり判定(補正付き)
単純には
(1)円が正方形の辺に触れるパターン
(2)正方形の角が円に触れるパターン
に分けて考えればよいのでは.
で,どちらだろうが,物体の速度を「ある方向Nに対して反転する」のがシンプルな処理であろう.
(1)の場合のNとは,触れた辺の法線方向(辺に直交して,正方形の外側に向く方向)であろう.これは単純明快.
(2)の場合は,至極単純には,接触点から円の中心に向かう方向をNとして用いることが考えられるが,
そのような挙動で良いのかどうかはアプリケーション次第なので何とも言えない.
なお,「物体の速度のN方向成分とNとの内積が正である場合には速度反転処理をしない」といったifを仕込んでおくと良いかもしれない.
(1)円が正方形の辺に触れるパターン
(2)正方形の角が円に触れるパターン
に分けて考えればよいのでは.
で,どちらだろうが,物体の速度を「ある方向Nに対して反転する」のがシンプルな処理であろう.
(1)の場合のNとは,触れた辺の法線方向(辺に直交して,正方形の外側に向く方向)であろう.これは単純明快.
(2)の場合は,至極単純には,接触点から円の中心に向かう方向をNとして用いることが考えられるが,
そのような挙動で良いのかどうかはアプリケーション次第なので何とも言えない.
なお,「物体の速度のN方向成分とNとの内積が正である場合には速度反転処理をしない」といったifを仕込んでおくと良いかもしれない.
Re: 正方形と円の当たり判定(補正付き)
上記は反発係数を用いて速度の法線方向(N)成分のみを単純に反射する話.
座標側の補正に関しては,あまりにも(見た目に不自然なほどに)大きくめり込むのでもないならそのまま放っておいても良いのではないかな?とか.
どうしても座標もいじくりたいならば,座標更新処理を「接した時刻」で2分すればよかろう.
なお,
接方向(Nと垂直な方向)成分も扱いたい(:摩擦を表現したいとかいう)場合には,適当に速度の接方向成分もいじくればよいのではないかと.
単純には s (0.0< s <1.0) 倍してやるとか.
s の値を壁側のパラメータにでもすれば,摩擦が強い/弱い 壁みたいなのを表現できるかもね.
座標側の補正に関しては,あまりにも(見た目に不自然なほどに)大きくめり込むのでもないならそのまま放っておいても良いのではないかな?とか.
どうしても座標もいじくりたいならば,座標更新処理を「接した時刻」で2分すればよかろう.
なお,
接方向(Nと垂直な方向)成分も扱いたい(:摩擦を表現したいとかいう)場合には,適当に速度の接方向成分もいじくればよいのではないかと.
単純には s (0.0< s <1.0) 倍してやるとか.
s の値を壁側のパラメータにでもすれば,摩擦が強い/弱い 壁みたいなのを表現できるかもね.
Re: 正方形と円の当たり判定(補正付き)
現在、あたっしゅさんの助言を踏まえて円を内接する正方形として扱い判定を取る方針でプログラムを組んでいます(辺を考えた方が反射の方向は簡単に出そうなので)。
usaoさんの助言を踏まえて反射の方向は考えてみようと思っています。
想定通りの挙動になったら具体的な方針を書いて解決にしたいと思います。
usaoさんの助言を踏まえて反射の方向は考えてみようと思っています。
想定通りの挙動になったら具体的な方針を書いて解決にしたいと思います。
毎回ゲーム作ろうとするたびに壁にぶち当たる
Re: 正方形と円の当たり判定(補正付き)
先ほど想定通りの挙動が得られたので少し詳細に書いて解決にしたいと思います。
大枠としてこのサイトを参考にしました(http://monooki.ldblog.jp/archives/35959913.html)。
ですが、本ゲームには速度に加えて加速度もあったため、次のフレームの位置を予測するのに現在座標+速度+加速度を採用しました。これで自機のような壁にぶつかってからも力をかけ続けるような物体を壁で制止することが出来ました。
そして、前は「円を内接する正方形に近似する」と言いましたが、ゲーム性の観点から「円を外接する正方形に近似する」方針にしました。
次に反射ですが、速度ベクトルがもともと縦方向と横方向で保存されていたため、正方形の上または下の辺に当たったかと右または左の辺に当たったかとでそれぞれ対応する要素のみを反転させました。
最後に、ソースコードの該当する部分のみを貼っておきます。
注:ReflectionCFは物体自身の反発係数、WallReflectionCFは壁の反発係数です。壁は重心をPositionとしています。物体のSizeは半径です。perFrameは1/60で加速度をフレームで割って分かりやすくしています(自分にとって)。
最後に、初歩的な質問で申し訳ないのですが、以前まであった「解決ボタン」は廃止されたのですか?
見つからなかったので、私の見落としでしたら教えてください。
大枠としてこのサイトを参考にしました(http://monooki.ldblog.jp/archives/35959913.html)。
ですが、本ゲームには速度に加えて加速度もあったため、次のフレームの位置を予測するのに現在座標+速度+加速度を採用しました。これで自機のような壁にぶつかってからも力をかけ続けるような物体を壁で制止することが出来ました。
そして、前は「円を内接する正方形に近似する」と言いましたが、ゲーム性の観点から「円を外接する正方形に近似する」方針にしました。
次に反射ですが、速度ベクトルがもともと縦方向と横方向で保存されていたため、正方形の上または下の辺に当たったかと右または左の辺に当たったかとでそれぞれ対応する要素のみを反転させました。
最後に、ソースコードの該当する部分のみを貼っておきます。
void CMover::onWall(CVector WallPosition, CVector WallSize, double WallReflectionCF)
{
CVector nextPosition = Position + Velocity + Acceleration*Constant::perFrame;
double max = (Position.x + Size) - (WallPosition.x - WallSize.x / 2), may = (Position.y + Size) - (WallPosition.y - WallSize.y / 2);
double nax = (WallPosition.x + WallSize.x / 2) - (Position.x - Size), nay = (WallPosition.y + WallSize.y / 2) - (Position.y - Size);
double _max = (nextPosition.x + Size) - (WallPosition.x - WallSize.x / 2), _may = (nextPosition.y + Size) - (WallPosition.y - WallSize.y / 2);
double _nax = (WallPosition.x + WallSize.x / 2) - (nextPosition.x - Size), _nay = (WallPosition.y + WallSize.y / 2) - (nextPosition.y - Size);
bool U = false, D = false, R = false, L = false;
//カド同士の判定
if (0 >= max && 0 >= may && _max > 0 && _may > 0) {
if (_max >= _may) {
//下にある
D = true;
}
else {
//右にある
R = true;
}
}
if (0 >= nax && 0 >= may && _nax > 0 && _may > 0) {
if (_nax >= _may) {
//下にある
D = true;
}
else {
//左にある
L = true;
}
}
if (0 >= max && 0 >= nay && _max > 0 && _nay > 0) {
if (_max >= _nay) {
//上にある
U = true;
}
else {
//右にある
R = true;
}
}
if (0 >= nax && 0 >= nay && _nax > 0 && _nay > 0) {
if (_nax >= _nay) {
//上にある
U = true;
}
else {
//左にある
L = true;
}
}
//上下左右の判定
if (may > 0 && nay > 0) {
if (_nax > 0 && (Position.x - Size) > (WallPosition.x - WallSize.x / 2)) {
//左にある
L = true;
}
if (_max > 0 && (WallPosition.x + WallSize.x / 2) > (Position.x + Size)) {
//右にある
R = true;
}
}
if (max > 0 && nax > 0) {
if (_nay > 0 && (Position.y - Size) > (WallPosition.y - WallSize.y / 2)) {
//上にある
U = true;
}
if (_may > 0 && (WallPosition.y + WallSize.y / 2) > (Position.y + Size)) {
//下にある
D = true;
}
}
if (U) {
Position.y = WallPosition.y + WallSize.y / 2 + Size;
Velocity.y *= -ReflectCF * WallReflectionCF;
if(Acceleration.y < 0)Acceleration.y = 0;
}
if (D) {
Position.y = WallPosition.y - WallSize.y / 2 - Size;
Velocity.y *= -ReflectCF * WallReflectionCF;
if (Acceleration.y > 0)Acceleration.y = 0;
}
if (R) {
Position.x = WallPosition.x - WallSize.x / 2 - Size;
Velocity.x *= -ReflectCF * WallReflectionCF;
if (Acceleration.x > 0)Acceleration.x = 0;
}
if (L) {
Position.x = WallPosition.x + WallSize.x / 2 + Size;
Velocity.x *= -ReflectCF * WallReflectionCF;
if (Acceleration.x < 0)Acceleration.x = 0;
}
}
最後に、初歩的な質問で申し訳ないのですが、以前まであった「解決ボタン」は廃止されたのですか?
見つからなかったので、私の見落としでしたら教えてください。
毎回ゲーム作ろうとするたびに壁にぶち当たる