物体同士の衝突反射
動いているもの同士が衝突した際に、衝突後の速度を求めるつうやつ。運動量保存のやつって云ったら伝わるだろうか。面倒、面倒と敬遠してたのですが、てきとーにやったらそれなりに動いたので、恥を晒してみます。
参考→(http://www.h6.dion.ne.jp/~game296o/COL_MV_No1_HowToCalcVelocity.html)
読んでて頭痛くなってきたので、結果の式を眺めながら考えてみる。
v1' = (m/(m+m))*(1+e)Dot(v1-v2, c)c + v1 // すげー適当
m/(m+m)ってのは、2物体の質量で、今回は全部質量を同じにしてしまいましょう。m/(m+m)==0.5;
(1+e)ってのは、反発係数で、完全弾性衝突にしてしまいましょう。e==1 なので、(1+e)==2;
v1-v2ってのはベクトルの引き算なので、えーと。ああ、物体1の相対速度ってことすね。つまり、止まってる物体2に物体1が速度(v1-v2)でぶつかったと見立ててるわけか。
で、ベクトルc(物体2から見た物体1の位置ベクトル)と内積(Dot)をとってやると、物体1の速度の衝突に有効な成分を抜き出してると。*1
で、内積とベクトルcを掛けると物体1が反発する速度成分が求まる、と。
最後に元の速度v1を足してやると、衝突後の速度が求まるよ、と。
なるほどねー。よく考えてみれば、難しい式ではないや。つうことで、書いたソース。
void CEnermyCommon::Reflect(CCharBase* pObj, CCharBase* pTarget) { // pObj : 自分 // pTarget : 衝突相手 POINT* pMPos = &(pObj->mPos); // 自分現在地 POINT* pMPrevPos = &(pObj->mPrevPos); // 相手一手前 POINT* pTPos = &(pTarget->mPos); // 相手現在地 POINT* pTPrevPos = &(pTarget->mPrevPos); // 相手一手前 // 超適当なめり込み回避 int TargetAngle = GetTA( pTPos, pMPos ) & 4095; // 相手からみた自分の角度を求める pMPos->x += (pObj->mSpeed>>8)*(COS4096(TargetAngle)>>8); pMPos->y += (pObj->mSpeed>>8)*(SIN4096(TargetAngle)>>8); const int MyVx = pMPos->x - pMPrevPos->x; // 自分速度 const int MyVy = pMPos->y - pMPrevPos->y; // 自分速度 const int TargetVx = pTPos->x - pTPrevPos->x; // 相手速度 const int TargetVy = pTPos->y - pTPrevPos->y; // 相手速度 const int SotaiVx = MyVx - TargetVx; // 相対速度 const int SotaiVy = MyVy - TargetVy; // 相対速度 // 内積 const int Naiseki = (SotaiVx>>8) * (COS4096(TargetAngle)>>8) + (SotaiVy>>8) * (COS4096(TargetAngle)>>8); // 新速度 const int NewVx = pObj->mVer.x = MyVx + (Naiseki>>8)*(COS4096(TargetAngle)>>8); const int NewVy = pObj->mVer.y = MyVy + (Naiseki>>8)*(SIN4096(TargetAngle)>>8); // 新角度 pObj->mAngle = CMathUtil::Vector2Angle(NewVx, NewVy); // ベクトルを角度に変換する }
ところどころに自前関数があったり、CCharBaseとか云う自前構造体をしれっと出してる辺り不親切ですね。まあ、雰囲気だけでも参考になるかなぁって。この関数は、衝突が起こった場合は、自分と相手それぞれに対して呼ばれるのがミソ。あと、毎フレーム一手前の座標を保持しておいて、現在座標との差を持って速度としているのも怪しいですが、今はオブジェクト1個に対して複数の動作が加味される可能性のある作りにしているので、オブジェクトに保存してある速度があてにならんのです。そんな感じで。