CocosCreator 物理引擎中的碰撞平面的法線
阿新 • • 發佈:2020-07-20
CocosCreator使用的是box2d.js物理引擎,碰撞平面法線方向必須取反
private onBeginContact(contact:cc.PhysicsContact,selfCollider:cc.PhysicsCollider,otherCollider:cc.PhysicsCollider):void{ let normal=contact.getWorldManifold().normal; normal.mulSelf(-1);//CocosCreator中,normal的方向是由selfCollider指向otherCollider,所以正確的碰撞平臺法線是相反的方向 cc.log(normal); }
注意:在AS3版的Box2d中,只有當前剛體和contact的剛體A不同時,法線的方向才需要取反。
此問題應該是AS3版Box2d的Bug,檢視AS3版的Box2D\Collision\b2WorldManifold.as的Initialize方法的以下程式碼:
case b2Manifold.e_faceB:{ //normal = b2Math.b2MulMV(xfB.R, manifold.m_localPlaneNormal); tMat = xfB.R; tVec = manifold.m_localPlaneNormal; normalX = tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; normalY = tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; //planePoint = b2Math.b2MulX(xfB, manifold.m_localPoint); tMat = xfB.R; tVec = manifold.m_localPoint; planePointX = xfB.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; planePointY = xfB.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; //此程式碼應放置到for迴圈之後 // Ensure normal points from A to B m_normal.x = -normalX; m_normal.y = -normalY; // for (i = 0; i < manifold.m_pointCount; i++) { //clipPoint = b2Math.b2MulX(xfA, manifold.m_points[i].m_localPoint); tMat = xfA.R; tVec = manifold.m_points[i].m_localPoint; clipPointX = xfA.position.x + tMat.col1.x * tVec.x + tMat.col2.x * tVec.y; clipPointY = xfA.position.y + tMat.col1.y * tVec.x + tMat.col2.y * tVec.y; //b2Vec2 cA = clipPoint - radiusA * normal; //b2Vec2 cB = clipPoint + (radiusB - b2Dot(clipPoint - planePoint, normal)) * normal; //m_points[i] = 0.5f * (cA + cB); m_points[i].x = clipPointX + 0.5 * (radiusB - (clipPointX - planePointX) * normalX - (clipPointY - planePointY) * normalY - radiusA ) * normalX; m_points[i].y = clipPointY + 0.5 * (radiusB - (clipPointX - planePointX) * normalX - (clipPointY - planePointY) * normalY - radiusA ) * normalY; } }
JS版的Box2d,b2WorldManifold的Initialize方法:
case exports.b2ManifoldType.e_faceB: { b2Rot.MulRV(xfB.q, manifold.localNormal, this.normal); var planePoint = b2Transform.MulXV(xfB, manifold.localPoint, b2WorldManifold.Initialize_s_planePoint); for (var i = 0; i < manifold.pointCount; ++i) { var clipPoint = b2Transform.MulXV(xfA, manifold.points[i].localPoint, b2WorldManifold.Initialize_s_clipPoint); var s = radiusB - b2Vec2.DotVV(b2Vec2.SubVV(clipPoint, planePoint, b2Vec2.s_t0), this.normal); var cB = b2Vec2.AddVMulSV(clipPoint, s, this.normal, b2WorldManifold.Initialize_s_cB); var cA = b2Vec2.SubVMulSV(clipPoint, radiusA, this.normal, b2WorldManifold.Initialize_s_cA); b2Vec2.MidVV(cA, cB, this.points[i]); this.separations[i] = b2Vec2.DotVV(b2Vec2.SubVV(cA, cB, b2Vec2.s_t0), this.normal); // b2Dot(cA - cB, normal); } // Ensure normal points from A to B. this.normal.SelfNeg(); break; }
AS3版:
// Ensure normal points from A to B
m_normal.x = -normalX;
m_normal.y = -normalY;
JS版:
// Ensure normal points from A to B.
this.normal.SelfNeg();
兩個版本的反轉法線的程式碼位置不一致,導致以上問題