コード例 #1
0
ファイル: PhysicsBody.cs プロジェクト: weimingtom/erica
        /// <summary>
        /// コリジョン形状の変更
        /// </summary>
        /// <remarks>
        /// コリジョン形状を変更します。
        /// コリジョン形状に <c>null</c> に設定すると例外が発生します。
        /// </remarks>
        /// <param name="shape">コリジョン形状</param>
        public void SetShape(Collision shape)
        {
            if (shape == null) {
                throw new ArgumentNullException ("Shape is null");
            }
            var p2d = Physics2D.GetInstance ();

            this.shape = shape;
            this.body.CreateFixture (shape.CreateShapeBody (p2d.PPM), this);

            // コリジョン イベントは Body ではなく Fixture にセットされるので、
            // 形状を定義した後にセットする必要がある。
            this.body.OnCollision += new OnCollisionEventHandler (CollisionEnterEventHandler);
            this.body.OnSeparation += new OnSeparationEventHandler (CollisionExitEventHandler);
        }
コード例 #2
0
ファイル: Physics2D.cs プロジェクト: weimingtom/erica
        /*
         *
        /// <summary>
        /// 2物体の衝突の検出
        /// </summary>
        /// <remarks>
        /// 2物体の衝突を検出します。
        /// 現在のところ衝突地点とその法線について、それっぽい値を返していますが明確な取り決めはありません。
        /// </remarks>
        /// <param name="shapeA">コリジョン形状A</param>
        /// <param name="matA">変換行列A</param>
        /// <param name="shapeB">コリジョン形状B</param>
        /// <param name="matB">変換行列B</param>
        /// <param name="col">結果を受け取るコリジョン構造体</param>
        /// <returns>衝突があれば<c>true</c>, そうでなければ <c>false</c>.</returns>
        public static bool Collide (Collision shapeA, Matrix4x4? matA, Collision shapeB, Matrix4x4? matB, out Collision col) {
            if (shapeA == null || shapeB == null) {
                throw new ArgumentNullException ("Shapes are null");
            }

            var mani = new Manifold ();
            Vector3 T;
            Matrix3x3 R;
            Vector3 S;

            (matA ?? Matrix4x4.Identity).Decompress (out T, out R, out S);
            var shpA = shapeA.CreateShapeBody (1.0f);
            var posA = new XnaVector2 (T.X, T.Y);
            var rotA = new Mat22 (R[0], R[1], R[3], R[4]);
            var traA = new Transform (ref posA, ref rotA);

            (matB ?? Matrix4x4.Identity).Decompress (out T, out R, out S);
            var shpB = shapeB.CreateShapeBody (1.0f);
            var posB = new XnaVector2 (T.X, T.Y);
            var rotB = new Mat22 (R[0], R[1], R[3], R[4]);
            var traB = new Transform (ref posB, ref rotB);

            if (shapeA.IsPolygon && shapeB.IsPolygon) {
                FarseerPhysics.Collision.Collision.CollidePolygons (ref mani, (PolygonShape)shpA, ref traA, (PolygonShape)shpB, ref traB);
            }
            if (shapeA.IsPolygon && shapeB.IsCircle) {
                FarseerPhysics.Collision.Collision.CollidePolygonAndCircle (ref mani, (PolygonShape)shpA, ref traA, (CircleShape)shpB, ref traB);
            }
            if (shapeA.IsCircle && shapeB.IsPolygon) {
                MyMath.Swap (ref shpA, ref shpB);
                MyMath.Swap (ref traA, ref traB);
                FarseerPhysics.Collision.Collision.CollidePolygonAndCircle (ref mani, (PolygonShape)shpA, ref traA, (CircleShape)shpB, ref traB);
            }
            if (shapeA.IsCircle && shapeB.IsCircle) {
                FarseerPhysics.Collision.Collision.CollideCircles (ref mani, (CircleShape)shpA, ref traA, (CircleShape)shpB, ref traB);
            }

            XnaVector2 normal;
            FixedArray2<XnaVector2> points;

            switch (mani.PointCount) {
                case 0: {
                        col = new Collision (null, Vector3.Zero, Vector3.Zero);
                        return false;
                    }
                case 1: {
                        FarseerPhysics.Collision.Collision.GetWorldManifold (ref mani, ref traA, shpA.Radius, ref traB, shpB.Radius, out normal, out points);
                        var p = new Vector3 (points[0].X, points[0].Y, 0);
                        var n = new Vector3 (normal.X, normal.Y, 0);
                        col = new Collision (null, p, n);
                        return true;
                    }
                case 2: {
                        FarseerPhysics.Collision.Collision.GetWorldManifold (ref mani, ref traA, shpA.Radius, ref traB, shpB.Radius, out normal, out points);
                        var p = new Vector3 ((points[0].X + points[1].X) / 2.0f, (points[0].Y + points[1].Y) / 2.0f, 0);
                        var n = new Vector3 (normal.X, normal.Y, 0);
                        col = new Collision (null, p, n);
                        return true;
                    }
                default: throw new InvalidOperationException ("This never happen");
            }
        }

        /// <summary>
        /// 2物体の衝突の検出
        /// </summary>
        /// <remarks>
        /// 2物体の衝突を検出します。衝突地点の情報を受け取らない事を除き同名の関数と等価です。
        /// </remarks>
        /// <param name="shapeA">コリジョン形状A</param>
        /// <param name="matA">変換行列A</param>
        /// <param name="shapeB">コリジョン形状B</param>
        /// <param name="matB">変換行列B</param>
        /// <returns>衝突があれば<c>true</c>, そうでなければ <c>false</c>.</returns>
        public static bool Collide (Collision shapeA, Matrix4x4? matA, Collision shapeB, Matrix4x4? matB) {
            Collision col;
            return Collide (shapeA, matA, shapeB, matB, out col);
        }

        /// <summary>
        /// 2物体の衝突の検出
        /// </summary>
        /// <remarks>
        /// 2物体の衝突を検出します。変換行列は自動的に <see cref="Node.GlobalTransform"/> を取得して使用します。
        /// </remarks>
        /// <param name="shapeA">コリジョン形状A</param>
        /// <param name="shapeB">コリジョン形状B</param>
        /// <param name="col">結果を受け取るコリジョン構造体</param>
        /// <returns>衝突があれば<c>true</c>, そうでなければ <c>false</c>.</returns>
        public static bool Collide (Collision shapeA, Collision shapeB, out Collision col) {
            if(shapeA == null || shapeB == null){
                throw new ArgumentNullException("Shapes are null");
            }
            var matA = (shapeA.Node == null) ? Matrix4x4.Identity : shapeA.Node.GlobalTransform;
            var matB = (shapeB.Node == null) ? Matrix4x4.Identity : shapeB.Node.GlobalTransform;
            return Collide (shapeA, matA, shapeB, matB, out col);
        }

        /// <summary>
        /// 2物体の衝突の検出
        /// </summary>
        /// <remarks>
        /// 2物体の衝突を検出します。衝突地点の情報を受け取らない事を除き同名の関数と等価です。
        /// </remarks>
        /// <param name="shapeA">コリジョン形状A</param>
        /// <param name="shapeB">コリジョン形状B</param>
        /// <returns>衝突があれば<c>true</c>, そうでなければ <c>false</c>.</returns>
        public static bool Collide (Collision shapeA, Collision shapeB) {
            Collision col;
            return Collide (shapeA, shapeB, out col);
        }

        /// <summary>
        /// 2物体の最短距離の測定
        /// </summary>
        /// <remarks>
        /// 2つのコリジョン形状の最短距離を求めます。
        /// 2つの物体がオーバーラップしていた場合は一律 0 が帰り、負の値が変える事はありません。
        /// <note>
        /// 必要性が感じられないので削除予定。使用禁止。
        /// </note>
        /// </remarks>
        /// <param name="shapeA">コリジョン形状A</param>
        /// <param name="matA">変換行列A</param>
        /// <param name="shapeB">コリジョン形状B</param>
        /// <param name="matB">変換行列B</param>
        /// <returns></returns>
        public static float Distance (Collision shapeA, Matrix4x4? matA, Collision shapeB, Matrix4x4? matB) {
            if (shapeA == null) {
                Console.WriteLine ("Distance shapeA is null");
            }
            if (shapeB == null) {
                Console.WriteLine ("Distance shapeB is null");
            }
            ClosestPoints cp;
            return Distance (shapeA, matA, shapeB, matB, out cp);
        }

        /// <summary>
        /// 2物体の最短距離の測定
        /// </summary>
        /// <remarks>
        /// 2つのコリジョン形状の最短距離を求めます。
        /// 2つの物体がオーバーラップしていた場合は一律 0 が帰り、負の値が変える事はありません。
        /// <note>
        /// 必要性が感じられないので削除予定。使用禁止。
        /// </note>
        /// </remarks>
        /// <param name="shapeA">コリジョン形状A</param>
        /// <param name="matA">変換行列A</param>
        /// <param name="shapeB">コリジョン形状B</param>
        /// <param name="matB">変換行列B</param>
        /// <param name="cp">結果の再近接地点情報を受け取る</param>
        /// <returns>距離</returns>
        public static float Distance (Collision shapeA, Matrix4x4? matA, Collision shapeB, Matrix4x4? matB, out ClosestPoints cp) {

            DistanceOutput output;
            SimplexCache cache;
            DistanceInput input = new DistanceInput ();
            DistanceProxy proxyA = new DistanceProxy ();
            DistanceProxy proxyB = new DistanceProxy ();

            proxyA.Set (shapeA.CreateShapeBody (1), 0);
            proxyB.Set (shapeB.CreateShapeBody (1), 0);

            input.ProxyA = proxyA;
            input.ProxyB = proxyB;
            input.UseRadii = true;

            Vector3 T;
            Matrix3x3 M;
            Vector3 S;
            (matA ?? Matrix4x4.Identity).Decompress (out T, out M, out S);

            var posA = new XnaVector2 (T.X, T.Y);
            var rotA = new Mat22 (M[0], M[1], M[3], M[4]);
            input.TransformA = new Transform (ref posA, ref rotA);

            (matB ?? Matrix4x4.Identity).Decompress (out T, out M, out S);

            var posB = new XnaVector2 (T.X, T.Y);
            var rotB = new Mat22 (M[0], M[1], M[3], M[4]);
            input.TransformB = new Transform (ref posB, ref rotB);

            FarseerPhysics.Collision.Distance.ComputeDistance (out output, out cache, input);

            var pointA = new Vector3(output.PointA.X, output.PointA.Y, 0);
            var pointB = new Vector3 (output.PointB.X, output.PointB.Y, 0);
            cp = new ClosestPoints (pointA, pointB);

            return output.Distance;
        }

        /// <summary>
        /// コリジョン形状と1点の検出
        /// </summary>
        /// <remarks>
        /// 日本語変・・・
        /// </remarks>
        /// <param name="shapeA">コリジョン形状</param>
        /// <param name="matA">変換行列</param>
        /// <param name="point">判定したい1点</param>
        /// <returns>コリジョン形状の中にあれば<c>true</c>, そうでなければ <c>false</c>. </returns>
        public static bool Contain (Collision shapeA, Matrix4x4? matA, Vector2 point) {

            Vector3 T;
            Matrix3x3 R;
            Vector3 S;

            (matA ?? Matrix4x4.Identity).Decompress (out T, out R, out S);
            var shpA = shapeA.CreateShapeBody (1.0f);
            var posA = new XnaVector2 (T.X, T.Y);
            var rotA = new Mat22 (R[0], R[1], R[3], R[4]);
            var traA = new Transform (ref posA, ref rotA);

            var posB = new XnaVector2 (point.X, point.Y);

            return shpA.TestPoint (ref traA, ref posB);
        }

        /// <summary>
        /// レイキャストによる交差判定
        /// </summary>
        /// <remarks>
        /// レイと物体の交差判定を行い、衝突結果を受け取ります。
        /// </remarks>
        /// <param name="shapeA">形状A</param>
        /// <param name="matA">変換行列A</param>
        /// <param name="ray">レイ</param>
        /// <param name="rayOut">結果を受け取る <see cref="RayIntersection"/> オブジェクト</param>
        /// <returns>レイと物体が交差したら<c>true</c>, そうでなければ <c>false</c>.</returns>
        public static bool RayCast (Collision shapeA, Matrix4x4? matA, Ray ray, out RayIntersection rayOut) {
            FarseerPhysics.Collision.RayCastInput input;
            FarseerPhysics.Collision.RayCastOutput output;
            input.Point1 = Convert (ray.PointA);
            input.Point2 = Convert (ray.PointB);
            input.MaxFraction = ray.Fraction;

            var shpA = Convert (shapeA);
            var traA = Convert (matA ?? Matrix4x4.Identity);

            var hit = shpA.RayCast (out output, ref input, ref traA, 0);
            if (hit) {
                var normal = Convert (output.Normal);
                var frac = output.Fraction;
                rayOut = new RayIntersection (true, shapeA.Node, normal, frac, ray);
            }
            else {
                rayOut = new RayIntersection ();
            }

            return hit;
        }

        /// <summary>
        /// レイキャストによる交差判定
        /// </summary>
        /// <remarks>
        /// レイと物体の交差判定を行います。衝突情報を受け取ります。
        /// </remarks>
        /// <param name="shapeA">形状A</param>
        /// <param name="matA">変換行列A</param>
        /// <param name="ray">レイ</param>
        /// <returns></returns>
        public static bool RayCast (Collision shapeA, Matrix4x4? matA, Ray ray) {
            RayIntersection output;
            return RayCast (shapeA, matA, ray, out output);
        }

        /// <summary>
        /// レイキャストによる交差判定
        /// </summary>
        /// <remarks>
        /// レイと物体の交差判定を行います。衝突情報を受け取ります。
        /// 変換行列はアタッチされたノードの物を暗黙的に使用します。
        /// </remarks>
        /// <param name="shapeA">形状A</param>
        /// <param name="ray">レイ</param>
        /// <param name="output">結果を受け取る <see cref="RayIntersection"/> 構造体</param>
        /// <returns></returns>
        public static bool RayCast (Collision shapeA, Ray ray, out RayIntersection output) {
            if (shapeA.Node == null) {
                throw new ArgumentException ("ShapeA is not attached");
            }
            var matA = shapeA.Node.Transform;
            return RayCast (shapeA, matA, ray, out output);
        }

        /// <summary>
        /// レイキャストによる交差判定
        /// </summary>
        /// <remarks>
        /// レイと物体の交差判定を行います。衝突情報を受け取りません。
        /// 変換行列はアタッチされたノードの物を暗黙的に使用します。
        /// </remarks>
        /// <param name="shapeA">形状A</param>
        /// <param name="ray">レイ</param>
        /// <returns></returns>
        public static bool RayCast (Collision shapeA, Ray ray) {
            RayIntersection output;
            var matA = shapeA.Node.Transform;
            return RayCast (shapeA, matA, ray, out output);
        }
        */
        private static Shape Convert(Collision shape)
        {
            return shape.CreateShapeBody (1.0f);
        }