public void SetAsBox(float hx, float hy, b2Vec2 center, float angle)
        {
            m_vertexCount = 4;
            m_vertices[0].Set(-hx, -hy);
            m_vertices[1].Set(hx, -hy);
            m_vertices[2].Set(hx, hy);
            m_vertices[3].Set(-hx, hy);
            m_normals[0].Set(0.0f, -1.0f);
            m_normals[1].Set(1.0f, 0.0f);
            m_normals[2].Set(0.0f, 1.0f);
            m_normals[3].Set(-1.0f, 0.0f);
            m_centroid = center;

            b2Transform xf = b2Transform.Create();

            xf.p = center;
            xf.q.Set(angle);

            // Transform vertices and normals.
            for (int i = 0; i < m_vertexCount; ++i)
            {
                m_vertices[i] = b2Math.b2Mul(xf, m_vertices[i]);
                m_normals[i]  = b2Math.b2Mul(xf.q, m_normals[i]);
            }
        }
Example #2
0
        public void DrawFixture(b2Fixture fixture)
        {
            b2Color     color = new b2Color(0.95f, 0.95f, 0.6f);
            b2Transform xf    = fixture.Body.Transform;

            switch (fixture.ShapeType)
            {
            case b2ShapeType.e_circle:
            {
                b2CircleShape circle = (b2CircleShape)fixture.Shape;

                b2Vec2 center = b2Math.b2Mul(xf, circle.Position);
                float  radius = circle.Radius;

                m_debugDraw.DrawCircle(center, radius, color);
            }
            break;

            case b2ShapeType.e_polygon:
            {
                b2PolygonShape poly        = (b2PolygonShape)fixture.Shape;
                int            vertexCount = poly.VertexCount;
                Debug.Assert(vertexCount <= b2Settings.b2_maxPolygonVertices);
                b2Vec2[] vertices = new b2Vec2[b2Settings.b2_maxPolygonVertices];

                for (int i = 0; i < vertexCount; ++i)
                {
                    vertices[i] = b2Math.b2Mul(xf, poly.Vertices[i]);
                }

                m_debugDraw.DrawPolygon(vertices, vertexCount, color);
            }
            break;
            }
        }
 public ShapeCastInputNative()
 {
     transform     = Physics2DNative.GetNewTransform(Vector2.Zero, 0f);
     _EndTransform = Physics2DNative.GetNewTransform(Vector2.Zero, 0f);
     aabb          = new b2AABB();
     _End          = new b2AABB();
 }
Example #4
0
        /**
         * @inheritDoc
         */
        public override float ComputeSubmergedArea(
            b2Vec2 normal,
            float offset,
            b2Transform xf,
            b2Vec2 c)
        {
            b2Vec2 p = b2Math.MulX(xf, m_p);
            float  l = -(b2Math.Dot(normal, p) - offset);

            if (l < -m_radius + float.MinValue)
            {
                //Completely dry
                return(0.0f);
            }
            if (l > m_radius)
            {
                //Completely wet
                c.SetV(p);
                return(Mathf.PI * m_radius * m_radius);
            }

            //Magic
            float r2   = m_radius * m_radius;
            float l2   = l * l;
            float area = r2 * (Mathf.Asin(l / m_radius) + Mathf.PI / 2.0f) + l * Mathf.Sqrt(r2 - l2);
            float com  = -2.0f / 3.0f * Mathf.Pow(r2 - l2, 1.5f) / area;

            c.x = p.x + normal.x * com;
            c.y = p.y + normal.y * com;

            return(area);
        }
 /// Compute the collision manifold between an edge and a circle.
 public static void b2CollideEdgeAndPolygon(ref b2Manifold manifold,
                                 b2EdgeShape edgeA, ref b2Transform xfA,
                                 b2PolygonShape polygonB, ref b2Transform xfB)
 {
     b2EPCollider b = new b2EPCollider();
     b.Collide(ref manifold, edgeA, ref xfA, polygonB, ref xfB);
 }
Example #6
0
        /**
         * @inheritDoc
         */
        public override void ComputeAABB(b2AABB aabb, b2Transform xf)
        {
            //var lower:b2Vec2 = b2Math.MulX(xf, m_vertices[0]);
            b2Mat22 tMat   = xf.R;
            b2Vec2  tVec   = m_vertices[0];
            float   lowerX = xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
            float   lowerY = xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
            float   upperX = lowerX;
            float   upperY = lowerY;

            for (int i = 1; i < m_vertexCount; ++i)
            {
                tVec = m_vertices[i];
                float vX = xf.position.x + (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y);
                float vY = xf.position.y + (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y);
                lowerX = lowerX < vX ? lowerX : vX;
                lowerY = lowerY < vY ? lowerY : vY;
                upperX = upperX > vX ? upperX : vX;
                upperY = upperY > vY ? upperY : vY;
            }

            aabb.lowerBound.x = lowerX - m_radius;
            aabb.lowerBound.y = lowerY - m_radius;
            aabb.upperBound.x = upperX + m_radius;
            aabb.upperBound.y = upperY + m_radius;
        }
Example #7
0
        public void SetAsBox(float hx, float hy, b2Vec2 center, float angle)
        {
            m_vertexCount = 4;
            Vertices[0].Set(-hx, -hy);
            Vertices[1].Set(hx, -hy);
            Vertices[2].Set(hx, hy);
            Vertices[3].Set(-hx, hy);
            Normals[0].Set(0.0f, -1.0f);
            Normals[1].Set(1.0f, 0.0f);
            Normals[2].Set(0.0f, 1.0f);
            Normals[3].Set(-1.0f, 0.0f);
            Centroid = center;

            b2Transform xf = b2Transform.Identity;

            xf.p = center;
            xf.q.Set(angle);

            // Transform vertices and normals.
            for (int i = 0; i < m_vertexCount; ++i)
            {
                Vertices[i] = b2Math.b2Mul(ref xf, ref Vertices[i]);
                Normals[i]  = b2Math.b2Mul(ref xf.q, ref Normals[i]);
            }
        }
Example #8
0
        /**
         * @inheritDoc
         */
        public override bool TestPoint(b2Transform xf, b2Vec2 p)
        {
            b2Vec2 tVec;

            //b2Vec2 pLocal = b2MulT(xf.R, p - xf.position);
            b2Mat22 tMat    = xf.R;
            float   tX      = p.x - xf.position.x;
            float   tY      = p.y - xf.position.y;
            float   pLocalX = (tX * tMat.col1.x + tY * tMat.col1.y);
            float   pLocalY = (tX * tMat.col2.x + tY * tMat.col2.y);

            for (int i = 0; i < m_vertexCount; ++i)
            {
                //float32 dot = b2Dot(m_normals[i], pLocal - m_vertices[i]);
                tVec = m_vertices[i];
                tX   = pLocalX - tVec.x;
                tY   = pLocalY - tVec.y;
                tVec = m_normals[i];
                float dot = (tVec.x * tX + tVec.y * tY);
                if (dot > 0.0f)
                {
                    return(false);
                }
            }

            return(true);
        }
Example #9
0
    /// Implement b2Shape.
    public override bool TestPoint(b2Transform transform, b2Vec2 p)
    {
        b2Vec2 center = transform.p + Utils.b2Mul(transform.q, m_p);
        b2Vec2 d      = p - center;

        return(Utils.b2Dot(d, d) <= m_radius * m_radius);
    }
        /// Compute the collision manifold between two circles.
        public static void b2CollideCircles(ref b2Manifold manifold,
                               b2CircleShape circleA, ref b2Transform xfA,
                               b2CircleShape circleB, ref b2Transform xfB)
        {
            manifold.pointCount = 0;

            b2Vec2 pA = b2Math.b2Mul(xfA, circleA.Position);
            b2Vec2 pB = b2Math.b2Mul(xfB, circleB.Position);

            b2Vec2 d = pB - pA;
            float distSqr = b2Math.b2Dot(d, d);
            float rA = circleA.Radius, rB = circleB.Radius;
            float radius = rA + rB;
            if (distSqr > radius * radius)
            {
                return;
            }

            manifold.type = b2ManifoldType.e_circles;
            manifold.localPoint = circleA.Position;
            manifold.localNormal.SetZero();
            manifold.pointCount = 1;

            manifold.points[0].localPoint = circleB.Position;
            manifold.points[0].id = b2ContactFeature.Zero;
        }
Example #11
0
    private void testQueryShape_poly()
    {
        Vector3 mousePos        = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        b2WorldQueryCallback cb = delegate(b2Fixture fixture) {
            b2Body body = fixture.GetBody();
            body.SetAwake(true);
            return(true);
        };

        b2Vec2[] vertices = new b2Vec2[4];
        vertices [0] = new b2Vec2(-100.0f / ptm_ratio, 0.0f / ptm_ratio);
        vertices [1] = new b2Vec2(0.0f / ptm_ratio, 100.0f / ptm_ratio);
        vertices [2] = new b2Vec2(100.0f / ptm_ratio, 0.0f / ptm_ratio);
        vertices [3] = new b2Vec2(0.0f / ptm_ratio, -200.0f / ptm_ratio);
        b2PolygonShape shape = b2PolygonShape.AsArray(vertices, vertices.Length);

        b2Transform transform = new b2Transform(new b2Vec2(mousePos.x, mousePos.y), b2Mat22.FromAngle(0));

        _world.QueryShape(cb, shape, transform);

        for (int i = 0; i < vertices.Length; i++)
        {
            vertices[i].x += mousePos.x;
            vertices[i].y += mousePos.y;
        }
        b2Color color = new b2Color(1.0f, 0.0f, 0.0f);

        _debugDraw.DrawPolygon(vertices, vertices.Length, color);
    }
Example #12
0
        /**
         * @inheritDoc
         */
        public override void ComputeAABB(b2AABB aabb, b2Transform transform)
        {
            b2Mat22 tMat = transform.R;
            //b2Vec2 v1 = b2Mul(transform, m_v1);
            float v1X = transform.position.x + (tMat.col1.x * m_v1.x + tMat.col2.x * m_v1.y);
            float v1Y = transform.position.y + (tMat.col1.y * m_v1.x + tMat.col2.y * m_v1.y);
            //b2Vec2 v2 = b2Mul(transform, m_v2);
            float v2X = transform.position.x + (tMat.col1.x * m_v2.x + tMat.col2.x * m_v2.y);
            float v2Y = transform.position.y + (tMat.col1.y * m_v2.x + tMat.col2.y * m_v2.y);

            if (v1X < v2X)
            {
                aabb.lowerBound.x = v1X;
                aabb.upperBound.x = v2X;
            }
            else
            {
                aabb.lowerBound.x = v2X;
                aabb.upperBound.x = v1X;
            }
            if (v1Y < v2Y)
            {
                aabb.lowerBound.y = v1Y;
                aabb.upperBound.y = v2Y;
            }
            else
            {
                aabb.lowerBound.y = v2Y;
                aabb.upperBound.y = v1Y;
            }
        }
Example #13
0
        public virtual void Synchronize(b2BroadPhase broadPhase, ref b2Transform transform1, ref b2Transform transform2)
        {
            if (m_proxyCount == 0)
            {
                return;
            }

            for (int i = 0, count = m_proxyCount; i < count; ++i)
            {
                b2FixtureProxy proxy = m_proxies[i];

                // Compute an AABB that covers the swept shape (may miss some rotation effect).
                b2AABB aabb1, aabb2;
                Shape.ComputeAABB(out aabb1, ref transform1, proxy.childIndex);
                Shape.ComputeAABB(out aabb2, ref transform2, proxy.childIndex);

                proxy.aabb.Combine(ref aabb1, ref aabb2);

                b2Vec2 displacement;
                displacement.x = transform2.p.x - transform1.p.x;
                displacement.y = transform2.p.y - transform1.p.y;

                broadPhase.MoveProxy(proxy.proxyId, ref proxy.aabb, ref displacement);
            }
        }
        public virtual bool TestPoint(b2Transform transform, b2Vec2 p)
        {
            b2Vec2 center = transform.p + b2Math.b2Mul(transform.q, m_p);
            b2Vec2 d      = p - center;

            return(b2Math.b2Dot(d, d) <= m_radius * m_radius);
        }
Example #15
0
    public static Vector2 b2Mul(b2Transform T, Vector2 v)
    {
        float x = (T.q.c * v.x - T.q.s * v.y) + T.p.x;
        float y = (T.q.s * v.x + T.q.c * v.y) + T.p.y;

        return(new Vector2(x, y));
    }
Example #16
0
        public override void ComputeAABB(out b2AABB output, ref b2Transform xf, int childIndex)
        {
            b2Vec2 v1;

            v1.x = (xf.q.c * Vertex1.x - xf.q.s * Vertex1.y) + xf.p.x;
            v1.y = (xf.q.s * Vertex1.x + xf.q.c * Vertex1.y) + xf.p.y;

            b2Vec2 v2;

            v2.x = (xf.q.c * Vertex2.x - xf.q.s * Vertex2.y) + xf.p.x;
            v2.y = (xf.q.s * Vertex2.x + xf.q.c * Vertex2.y) + xf.p.y;

            b2Vec2 lower;

            lower.x = v1.x < v2.x ? v1.x : v2.x;
            lower.y = v1.y < v2.y ? v1.y : v2.y;

            //b2Math.b2Min(v1, v2);
            b2Vec2 upper;

            upper.x = v1.x > v2.x ? v1.x : v2.x;
            upper.y = v1.y > v2.y ? v1.y : v2.y;
            // = b2Math.b2Max(v1, v2);

            output.LowerBound = lower;
            output.UpperBound = upper;
            output.Fatten(Radius);
        }
Example #17
0
    /// Implement b2Shape.

    // Collision Detection in Interactive 3D Environments by Gino van den Bergen
    // From Section 3.1.2
    // x = s + a * r
    // norm(x) = radius
    public override bool RayCast(b2RayCastOutput output, b2RayCastInput input, b2Transform transform, int childIndex)
    {
        b2Vec2 position = transform.p + Utils.b2Mul(transform.q, m_p);
        b2Vec2 s        = input.p1 - position;
        float  b        = Utils.b2Dot(s, s) - m_radius * m_radius;

        // Solve quadratic equation.
        b2Vec2 r     = input.p2 - input.p1;
        float  c     = Utils.b2Dot(s, r);
        float  rr    = Utils.b2Dot(r, r);
        float  sigma = c * c - rr * b;

        // Check for negative discriminant and short segment.
        if (sigma < 0.0f || rr < float.Epsilon)
        {
            return(false);
        }

        // Find the point of intersection of the line with the circle.
        float a = -(c + (float)Math.Sqrt(sigma));

        // Is the intersection point on the segment?
        if (0.0f <= a && a <= input.maxFraction * rr)
        {
            a /= rr;
            output.fraction = a;
            output.normal   = s + a * r;
            output.normal.Normalize();
            return(true);
        }

        return(false);
    }
        public static float b2EdgeSeparation(b2PolygonShape poly1, b2Transform xf1, int edge1,
                                      b2PolygonShape poly2, b2Transform xf2)
        {
            b2Vec2[] vertices1 = poly1.Vertices;
            b2Vec2[] normals1 = poly1.Normals;

            int count2 = poly2.VertexCount;
            b2Vec2[] vertices2 = poly2.Vertices;

            // Convert normal from poly1's frame into poly2's frame.
            b2Vec2 normal1World = b2Math.b2Mul(xf1.q, normals1[edge1]);
            b2Vec2 normal1 = b2Math.b2MulT(xf2.q, normal1World);

            // Find support vertex on poly2 for -normal.
            int index = 0;
            float minDot = b2Settings.b2_maxFloat;

            for (int i = 0; i < count2; ++i)
            {
                float dot = b2Math.b2Dot(ref vertices2[i], ref normal1);
                if (dot < minDot)
                {
                    minDot = dot;
                    index = i;
                }
            }

            b2Vec2 v1 = b2Math.b2Mul(xf1, vertices1[edge1]);
            b2Vec2 v2 = b2Math.b2Mul(xf2, vertices2[index]);
            float separation = b2Math.b2Dot(v2 - v1, normal1World);
            return separation;
        }
Example #19
0
        public void SetAsOrientedBox(float hx, float hy, b2Vec2 center = null, float angle = 0.0f)
        {
            m_vertexCount = 4;
            Reserve(4);
            m_vertices[0].Set(-hx, -hy);
            m_vertices[1].Set(hx, -hy);
            m_vertices[2].Set(hx, hy);
            m_vertices[3].Set(-hx, hy);
            m_normals[0].Set(0.0f, -1.0f);
            m_normals[1].Set(1.0f, 0.0f);
            m_normals[2].Set(0.0f, 1.0f);
            m_normals[3].Set(-1.0f, 0.0f);
            m_centroid = center;

            b2Transform xf = new b2Transform();

            xf.position = center;
            xf.R.Set(angle);

            // Transform vertices and normals.
            for (int i = 0; i < m_vertexCount; ++i)
            {
                m_vertices[i] = b2Math.MulX(xf, m_vertices[i]);
                m_normals[i]  = b2Math.MulMV(xf.R, m_normals[i]);
            }
        }
Example #20
0
    /// @see b2Shape::ComputeAABB
    public override void ComputeAABB(ref b2AABB aabb, b2Transform transform, int childIndex)
    {
        b2Vec2 p = transform.p + Utils.b2Mul(transform.q, m_p);

        aabb.lowerBound.Set(p.x - m_radius, p.y - m_radius);
        aabb.upperBound.Set(p.x + m_radius, p.y + m_radius);
    }
Example #21
0
        public override bool TestPoint(b2Transform transform, b2Vec2 p)
        {
            b2Vec2 center = transform.p + b2Math.b2Mul(transform.q, m_p);
            b2Vec2 d      = p - center;

            return(d.LengthSquared <= m_radius * m_radius);
        }
Example #22
0
        /// Compute the collision manifold between two circles.
        public static void b2CollideCircles(ref b2Manifold manifold,
                                            b2CircleShape circleA, ref b2Transform xfA,
                                            b2CircleShape circleB, ref b2Transform xfB)
        {
            manifold.pointCount = 0;

            b2Vec2 pA = b2Math.b2Mul(xfA, circleA.Position);
            b2Vec2 pB = b2Math.b2Mul(xfB, circleB.Position);

            b2Vec2 d;// = pB - pA;

            d.x = pB.x - pA.x;
            d.y = pB.y - pA.y;
            float distSqr = d.LengthSquared;
            float rA = circleA.Radius, rB = circleB.Radius;
            float radius = rA + rB;

            if (distSqr > radius * radius)
            {
                return;
            }

            manifold.type       = b2ManifoldType.e_circles;
            manifold.localPoint = circleA.Position;
            manifold.localNormal.SetZero();
            manifold.pointCount = 1;

            manifold.points[0].localPoint = circleB.Position;
            manifold.points[0].id.key     = 0;
        }
Example #23
0
    /// Build vertices to represent an oriented box.
    /// @param hx the half-width.
    /// @param hy the half-height.
    /// @param center the center of the box in local coordinates.
    /// @param angle the rotation of the box in local coordinates.
    public b2PolygonShape SetAsBox(float hx, float hy, b2Vec2 center, float angle)
    {
        m_count = 4;
        m_vertices[0].Set(-hx, -hy);
        m_vertices[1].Set(hx, -hy);
        m_vertices[2].Set(hx, hy);
        m_vertices[3].Set(-hx, hy);
        m_normals[0].Set(0.0f, -1.0f);
        m_normals[1].Set(1.0f, 0.0f);
        m_normals[2].Set(0.0f, 1.0f);
        m_normals[3].Set(-1.0f, 0.0f);
        m_centroid = center;

        b2Transform xf = new b2Transform();

        xf.p = center;
        xf.q.Set(angle);

        // Transform vertices and normals.
        for (int i = 0; i < m_count; ++i)
        {
            m_vertices[i] = Utils.b2Mul(xf, m_vertices[i]);
            m_normals[i]  = Utils.b2Mul(xf.q, m_normals[i]);
        }

        return(this);
    }
Example #24
0
        /**
         * Get the first vertex and apply the supplied transform.
         */
        public b2Vec2 GetFirstVertex(b2Transform xf)
        {
            //return b2Mul(xf, m_coreV1);
            b2Mat22 tMat = xf.R;

            return(new b2Vec2(xf.position.x + (tMat.col1.x * m_coreV1.x + tMat.col2.x * m_coreV1.y),
                              xf.position.y + (tMat.col1.y * m_coreV1.x + tMat.col2.y * m_coreV1.y)));
        }
Example #25
0
 public override void ComputeAABB(b2AABB aabb, b2Transform transform, int childIndex)
 {
     Box2DPINVOKE.b2CircleShape_ComputeAABB(swigCPtr, b2AABB.getCPtr(aabb), b2Transform.getCPtr(transform), childIndex);
     if (Box2DPINVOKE.SWIGPendingException.Pending)
     {
         throw Box2DPINVOKE.SWIGPendingException.Retrieve();
     }
 }
Example #26
0
 public virtual void ComputeAABB(b2AABB aabb, b2Transform xf, int childIndex)
 {
     Box2DPINVOKE.b2Shape_ComputeAABB(swigCPtr, b2AABB.getCPtr(aabb), b2Transform.getCPtr(xf), childIndex);
     if (Box2DPINVOKE.SWIGPendingException.Pending)
     {
         throw Box2DPINVOKE.SWIGPendingException.Retrieve();
     }
 }
    public override void Evaluate(b2Manifold manifold, b2Transform xfA, b2Transform xfB)
    {
        b2ChainShape chain = (b2ChainShape)m_fixtureA.GetShape();
        b2EdgeShape  edge  = new b2EdgeShape();

        chain.GetChildEdge(edge, m_indexA);
        Utils.b2CollideEdgeAndPolygon(manifold, edge, xfA, (b2PolygonShape)m_fixtureB.GetShape(), xfB);
    }
Example #28
0
 public virtual void DrawTransform(b2Transform xf)
 {
     Box2DPINVOKE.b2Draw_DrawTransform(swigCPtr, b2Transform.getCPtr(xf));
     if (Box2DPINVOKE.SWIGPendingException.Pending)
     {
         throw Box2DPINVOKE.SWIGPendingException.Retrieve();
     }
 }
Example #29
0
        /**
         * This supports body activation/deactivation.
         */
        public void CreateProxy(IBroadPhase broadPhase, b2Transform xf)
        {
            //b2Assert(m_proxyId == b2BroadPhase::e_nullProxy);

            // Create proxy in the broad-phase.
            m_shape.ComputeAABB(m_aabb, xf);
            m_proxy = broadPhase.CreateProxy(m_aabb, this);
        }
Example #30
0
 public void Initialize(b2Manifold manifold, b2Transform xfA, float radiusA, b2Transform xfB, float radiusB)
 {
     Box2DPINVOKE.b2WorldManifold_Initialize(swigCPtr, b2Manifold.getCPtr(manifold), b2Transform.getCPtr(xfA), radiusA, b2Transform.getCPtr(xfB), radiusB);
     if (Box2DPINVOKE.SWIGPendingException.Pending)
     {
         throw Box2DPINVOKE.SWIGPendingException.Retrieve();
     }
 }
Example #31
0
 public static Vector2 b2Mul(b2Transform T, Vector2 v)
 {
     float x = (T.q.c * v.x - T.q.s * v.y) + T.p.x;
     float y = (T.q.s * v.x + T.q.c * v.y) + T.p.y;
     return new Vector2(x, y);
 }
Example #32
0
            public override void DrawTransform(b2Transform xf)
            {
                b2Vec2 p1 = xf.position, p2;
                const float k_axisScale = 0.4f;
                Gl.glBegin(Gl.GL_LINES);

                Gl.glColor3f(1.0f, 0.0f, 0.0f);
                Gl.glVertex2f(p1.x, p1.y);
                p2 = p1 + k_axisScale * xf.R.col1;
                Gl.glVertex2f(p2.x, p2.y);

                Gl.glColor3f(0.0f, 1.0f, 0.0f);
                Gl.glVertex2f(p1.x, p1.y);
                p2 = p1 + k_axisScale * xf.R.col2;
                Gl.glVertex2f(p2.x, p2.y);

                Gl.glEnd();
            }
Example #33
0
    // Use this for initialization
    protected override void Init()
    {
        API.SetGravity(world,Vector2.zero);
        var ground = API.CreateBody(world, new Vector2(0,20), 0, BodyType.STATIC_BODY );
        ShapeDef sp = new ShapeDef(0);
        sp.restitution = 0.4f;

        API.AddEdgeShape(ground, new Vector2(-20,-20), new Vector2(-20,20), sp);
        API.AddEdgeShape(ground, new Vector2(20,-20), new Vector2(20,20), sp);
        API.AddEdgeShape(ground, new Vector2(-20,20), new Vector2(20,20), sp);
        API.AddEdgeShape(ground, new Vector2(-20,-20), new Vector2(20,-20), sp);

        BodyDef bd = new BodyDef(BodyType.DYNAMIC_BODY);
        bd.allowSleep = false;
        bd.angle = 3.14159265359f;
        bd.angularDamping = 5.0f;
        bd.linearDamping = 0.1f;
        bd.position = new Vector2(0,2);
        m_body = API.CreateBody(world,bd);

        sp.restitution = 0.0f;
        sp.density = 4.0f;

        b2Transform xf1 = new b2Transform();
        xf1.q = new b2Rot(0.3524f * Mathf.PI);
        xf1.p = xf1.q.GetXAxis();

        Vector2[] vertices = new Vector2[3];
        vertices[0] = b2Math.b2Mul(xf1, new Vector2(-1.0f, 0.0f));
        vertices[1] = b2Math.b2Mul(xf1, new Vector2(1.0f, 0.0f));
        vertices[2] = b2Math.b2Mul(xf1, new Vector2(0.0f, 0.5f));

        API.AddPolygonShape(m_body, vertices, vertices.Length, sp);

        sp.density = 2.0f;
        xf1.q = new b2Rot(-0.3524f * Mathf.PI);
        xf1.p = -xf1.q.GetXAxis();

        vertices[0] = b2Math.b2Mul(xf1, new Vector2(-1.0f, 0.0f));
        vertices[1] = b2Math.b2Mul(xf1, new Vector2(1.0f, 0.0f));
        vertices[2] = b2Math.b2Mul(xf1, new Vector2(0.0f, 0.5f));

        API.AddPolygonShape(m_body, vertices, vertices.Length, sp);

        sp.density = 1.0f;
        sp.friction = 0.3f;
        float gravity = 10;

        FrictionJointDef jd = new FrictionJointDef();
        for(int i=0; i<10; ++i)
        {
            var b = API.CreateBody(world, new Vector2(0,5.0f+1.54f*i), 0, BodyType.DYNAMIC_BODY );
            API.AddBoxShape(b, 0.5f, 0.5f, Vector2.zero, 0, sp);
            float I = API.GetInertia(b);
            float mass = API.GetMass(b);
            float radius = Mathf.Sqrt(2.0f*I/mass);

            jd.bodyA = ground;
            jd.bodyB = b;
            jd.collideConnected = true;
            jd.maxForce = mass*gravity;
            jd.maxTorque = mass*radius*gravity;

            API.CreateFrictionJoint(world,jd);
        }
    }