private void AddPressureBody(ClosedShape shape)
        {
            DraggablePressureBody body = new DraggablePressureBody();
            body.Setup(JellyWorldManager.World, shape, 1.0f, 40.0f, 10.0f, 1.0f, 300.0f, 20.0f, transform.position, transform.rotation.eulerAngles.z, Vector2.one);
            body.Gravity = GravityModifier;

            body.addInternalSpring(0, 2, 400f, 12f);
            body.addInternalSpring(1, 3, 400f, 12f);
            _body = body;
        }
        private void CreateFloor()
        {
            // static ground object.
            GameObject ground = new GameObject ();
            ClosedShape groundShape = new ClosedShape ();
            groundShape.begin();
            groundShape.addVertex(new Vector2(-10f, -2f));
            groundShape.addVertex(new Vector2(-10f, 2f));
            groundShape.addVertex(new Vector2(10f, 2f));
            groundShape.addVertex(new Vector2(10f, -2f));
            groundShape.finish();

            // make the body.
            Body groundBody = new Body();
            groundBody.Setup(_world, groundShape, float.PositiveInfinity, new Vector2(0f, -5f), 0f, Vector2.one, false);
        }
        private void AddSpringBody(ClosedShape shape)
        {
            DraggableSpringBody body = new DraggableSpringBody();
            body.Setup(JellyWorldManager.World, shape, 1f, SpringK, Damping, SpringK, Damping, transform.position, transform.rotation.eulerAngles.z, Vector2.one);
            body.Gravity = GravityModifier;

            int i = springs.Count-1, l = -1;
            for(;i>l;i-=detail)
            {
                Vector2 v = springs[i];
                try{
                    //TODO: check if triangle is already added, if so, flip triangle.
                    body.addInternalSpring((int)v.x, (int)v.y,SpringK,Damping);
                }
                catch{
            //                  Debug.Log("couldnt add spring at " +i);
                }
            }
            _body = body;
        }
 /// <summary>
 /// Collision Stay. For override.
 /// </summary>
 /// <param name="otherBody">Other body.</param>
 public virtual void CollisionStay(Body otherBody)
 {
     if (OnCollisionStay != null)
     {
         OnCollisionStay(otherBody);
     }
 }
 /// <summary>
 /// Collision Exit. For override.
 /// </summary>
 /// <param name="otherBody">Other body.</param>
 public virtual void CollisionExit(Body otherBody)
 {
     if (OnCollisionExit != null)
     {
         OnCollisionExit(otherBody);
     }
 }
 /// <summary>
 /// Collision Entered. For override.
 /// </summary>
 /// <param name="otherBody">Other body.</param>
 public virtual void CollisionEnter(Body otherBody)
 {
     if (OnCollisionEnter != null)
     {
         OnCollisionEnter(otherBody);
     }
 }
Exemple #7
0
 public void Clear()
 {
     bodyA = bodyB = null; bodyApm = bodyBpmA = bodyBpmB = -1; hitPt = Vector2.Zero; edgeD = 0f; normal = Vector2.Zero; penetration = 0f;
 }
Exemple #8
0
        private void updateBodyBitmask(Body body)
        {
            AABB box = body.getAABB();

            int minX = (int)Math.Floor((box.Min.X - mWorldLimits.Min.X) / mWorldGridStep.X);
            int maxX = (int)Math.Floor((box.Max.X - mWorldLimits.Min.X) / mWorldGridStep.X);

            if (minX < 0) { minX = 0; } else if (minX > 32) { minX = 32; }
            if (maxX < 0) { maxX = 0; } else if (maxX > 32) { maxX = 32; }

            int minY = (int)Math.Floor((box.Min.Y - mWorldLimits.Min.Y) / mWorldGridStep.Y);
            int maxY = (int)Math.Floor((box.Max.Y - mWorldLimits.Min.Y) / mWorldGridStep.Y);

            if (minY < 0) { minY = 0; } else if (minY > 32) { minY = 32; }
            if (maxY < 0) { maxY = 0; } else if (maxY > 32) { maxY = 32; }

            body.mBitMaskX.clear();
            for (int i = minX; i <= maxX; i++)
                body.mBitMaskX.setOn(i);

            body.mBitMaskY.clear();
            for (int i = minY; i <= maxY; i++)
                body.mBitMaskY.setOn(i);

            //Console.WriteLine("Body bitmask: minX{0} maxX{1} minY{2} maxY{3}", minX, maxX, minY, minY, maxY);
        }
Exemple #9
0
 private bool defaultCollisionFilter(Body A, int Apm, Body B, int Bpm1, int Bpm2, Vector2 hitPt, float normSpeed)
 {
     return true;
 }
Exemple #10
0
        private void bodyCollide(Body bA, Body bB, List<BodyCollisionInfo> infoList)
        {
            int bApmCount = bA.PointMassCount;
            int bBpmCount = bB.PointMassCount;

            AABB boxB = bB.getAABB();

            // check all PointMasses on bodyA for collision against bodyB.  if there is a collision, return detailed info.
            BodyCollisionInfo infoAway = new BodyCollisionInfo();
            BodyCollisionInfo infoSame = new BodyCollisionInfo();
            for (int i = 0; i < bApmCount; i++)
            {
                Vector2 pt = bA.getPointMass(i).Position;

                // early out - if this point is outside the bounding box for bodyB, skip it!
                if (!boxB.contains(ref pt))
                    continue;

                // early out - if this point is not inside bodyB, skip it!
                if (!bB.contains(ref pt))
                    continue;

                int prevPt = (i>0) ? i-1 : bApmCount-1;
                int nextPt = (i < bApmCount - 1) ? i + 1 : 0;

                Vector2 prev = bA.getPointMass(prevPt).Position;
                Vector2 next = bA.getPointMass(nextPt).Position;

                // now get the normal for this point. (NOT A UNIT VECTOR)
                Vector2 fromPrev = new Vector2();
                fromPrev.X = pt.X - prev.X;
                fromPrev.Y = pt.Y - prev.Y;

                Vector2 toNext = new Vector2();
                toNext.X = next.X - pt.X;
                toNext.Y = next.Y - pt.Y;

                Vector2 ptNorm = new Vector2();
                ptNorm.X = fromPrev.X + toNext.X;
                ptNorm.Y = fromPrev.Y + toNext.Y;
                VectorTools.makePerpendicular(ref ptNorm);

                // this point is inside the other body.  now check if the edges on either side intersect with and edges on bodyB.
                float closestAway = 100000.0f;
                float closestSame = 100000.0f;

                infoAway.Clear();
                infoAway.bodyA = bA;
                infoAway.bodyApm = i;
                infoAway.bodyB = bB;

                infoSame.Clear();
                infoSame.bodyA = bA;
                infoSame.bodyApm = i;
                infoSame.bodyB = bB;

                bool found = false;

                int b1 = 0;
                int b2 = 1;
                for (int j = 0; j < bBpmCount; j++)
                {
                    Vector2 hitPt;
                    Vector2 norm;
                    float edgeD;

                    b1 = j;

                    if (j < bBpmCount - 1)
                        b2 = j + 1;
                    else
                        b2 = 0;

                    Vector2 pt1 = bB.getPointMass(b1).Position;
                    Vector2 pt2 = bB.getPointMass(b2).Position;

                    // quick test of distance to each point on the edge, if both are greater than current mins, we can skip!
                    float distToA = ((pt1.X - pt.X) * (pt1.X - pt.X)) + ((pt1.Y - pt.Y) * (pt1.Y - pt.Y));
                    float distToB = ((pt2.X - pt.X) * (pt2.X - pt.X)) + ((pt2.Y - pt.Y) * (pt2.Y - pt.Y));

                    if ((distToA > closestAway) && (distToA > closestSame) && (distToB > closestAway) && (distToB > closestSame))
                        continue;

                    // test against this edge.
                    float dist = bB.getClosestPointOnEdgeSquared(pt, j, out hitPt, out norm, out edgeD);

                    // only perform the check if the normal for this edge is facing AWAY from the point normal.
                    float dot;
                    //Vector2.Dot(ref ptNorm, ref edgeNorm, out dot);
                    Vector2.Dot(ref ptNorm, ref norm, out dot);
                    if (dot <= 0f)
                    {
                        if (dist < closestAway)
                        {
                            closestAway = dist;
                            infoAway.bodyBpmA = b1;
                            infoAway.bodyBpmB = b2;
                            infoAway.edgeD = edgeD;
                            infoAway.hitPt = hitPt;
                            infoAway.normal = norm;
                            infoAway.penetration = dist;
                            found = true;
                        }
                    }
                    else
                    {
                        if (dist < closestSame)
                        {
                            closestSame = dist;
                            infoSame.bodyBpmA = b1;
                            infoSame.bodyBpmB = b2;
                            infoSame.edgeD = edgeD;
                            infoSame.hitPt = hitPt;
                            infoSame.normal = norm;
                            infoSame.penetration = dist;
                        }
                    }
                }

                // we've checked all edges on BodyB.  add the collision info to the stack.
                if ((found) && (closestAway > mPenetrationThreshold) && (closestSame < closestAway))
                {
                    infoSame.penetration = (float)Math.Sqrt(infoSame.penetration);
                    infoList.Add(infoSame);
                }
                else
                {
                    infoAway.penetration = (float)Math.Sqrt(infoAway.penetration);
                    infoList.Add(infoAway);
                }
            }
        }
Exemple #11
0
 /// <summary>
 /// Remove a body from the world.  call this outside of an update to remove the body.
 /// </summary>
 /// <param name="b">the body to remove</param>
 public void removeBody(Body b)
 {
     if (mBodies.Contains(b))
     {
         mBodies.Remove(b);
     }
 }
Exemple #12
0
 /// <summary>
 /// Add a Body to the world.  Bodies do this automatically, you should NOT need to call this.
 /// </summary>
 /// <param name="b">the body to add to the world</param>
 public void addBody(Body b)
 {
     if (!mBodies.Contains(b))
     {
         mBodies.Add(b);
     }
 }
        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        void Update()
        {
            // UPDATE the physics!
            for (int i = 0; i < 3; i++)
                mWorld.update(1 / 120f);

            // cursor movement.
            cursorPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);

            // if the user presses the A button, create a new body at the cursor position.
            if (Input.GetKeyDown(KeyCode.A))
            {
                GameObject s = new GameObject ();
                JelloPhysics.ClosedShape shape = new JelloPhysics.ClosedShape ();

                shape.begin();
                shape.addVertex(new Vector2(-1.0f, 0f));
                shape.addVertex(new Vector2(0f, 1.0f));
                shape.addVertex(new Vector2(1.0f, 0f));
                shape.addVertex(new Vector2(0f, -1.0f));
                shape.finish();

                DraggableSpringBody body = new DraggableSpringBody();
                body.Setup(mWorld, shape, 1f, 150, 5,300,15, new Vector2(cursorPos.x, cursorPos.y),((float)UnityEngine.Random.Range(0,360)), Vector2.one);

                body.addInternalSpring(0, 2, 400f, 12f);
                body.addInternalSpring(1, 3, 400f, 12f);
            }

            if (Input.GetKeyDown(KeyCode.B))
            {
                GameObject s = new GameObject ();
                JelloPhysics.ClosedShape shape = new JelloPhysics.ClosedShape ();

                shape.begin();
                for (int i = 0; i < 360; i += 20)
                {
                    shape.addVertex(new Vector2((float)Mathf.Cos(((float)-i) * Mathf.Deg2Rad), (float)Mathf.Sin(((float)-i) * Mathf.Deg2Rad)));
                }
                shape.finish();

                DraggablePressureBody pb = new DraggablePressureBody();
                pb.Setup(mWorld, shape, 1.0f, 40.0f, 10.0f, 1.0f, 300.0f, 20.0f, cursorPos, 0, Vector2.one);
                pb.addTriangle(0, 10, 9);
                pb.addTriangle(0, 9, 1);
                pb.addTriangle(1, 9, 8);
                pb.addTriangle(1, 8, 2);
                pb.addTriangle(2, 8, 7);
                pb.addTriangle(2, 7, 3);
                pb.addTriangle(3, 7, 6);
                pb.addTriangle(3, 6, 4);
                pb.addTriangle(4, 6, 5);
                pb.addTriangle(17, 10, 0);
                pb.addTriangle(17, 11, 10);
                pb.addTriangle(16, 11, 17);
                pb.addTriangle(16, 12, 11);
                pb.addTriangle(15, 12, 16);
                pb.addTriangle(15, 13, 12);
                pb.addTriangle(14, 12, 15);
                pb.addTriangle(14, 13, 12);
                pb.finalizeTriangles(Color.white);

                pb.addInternalSpring(0, 2, 400f, 12f);
                pb.addInternalSpring(1, 3, 400f, 12f);
            }

            // dragging!
            if (Input.GetMouseButton(0))
            {
                if (dragBody != null)
                {
                    PointMass pm = dragBody.getPointMass(dragPoint);
                    if (dragBody.GetType().Name == "DraggableSpringBody")
                        ((DraggableSpringBody)dragBody).setDragForce(JelloPhysics.VectorTools.calculateSpringForce(pm.Position, pm.Velocity, cursorPos, Vector2.zero, 0.0f, 100.0f, 10.0f), dragPoint);
                    else if (dragBody.GetType().Name == "DraggablePressureBody")
                        ((DraggablePressureBody)dragBody).setDragForce(JelloPhysics.VectorTools.calculateSpringForce(pm.Position, pm.Velocity, cursorPos, Vector2.zero, 0.0f, 100.0f, 10.0f), dragPoint);

                }
            }
            else
            {
                dragBody = null;
                dragPoint = -1;
            }

            if (Input.GetMouseButtonDown(0))
            {
                if (dragBody == null)
                {
                    int body;
                    mWorld.getClosestPointMass(cursorPos, out body, out dragPoint);
                    dragBody = mWorld.getBody(body);
                }
            }
        }
        void Update()
        {
            // UPDATE the physics!

            _cursorPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);

            // dragging!
            if (Input.GetMouseButton(0))
            {
                if (_dragBody != null)
                {
                    PointMass pm = _dragBody.getPointMass(_dragPoint);
                    if (_dragBody.GetType().Name == "DraggableSpringBody")
                        ((DraggableSpringBody)_dragBody).setDragForce(JelloPhysics.VectorTools.calculateSpringForce(pm.Position, pm.Velocity, _cursorPos, Vector2.zero, 0.0f, 100.0f, 10.0f), _dragPoint);
                    else if (_dragBody.GetType().Name == "DraggablePressureBody")
                        ((DraggablePressureBody)_dragBody).setDragForce(JelloPhysics.VectorTools.calculateSpringForce(pm.Position, pm.Velocity, _cursorPos, Vector2.zero, 0.0f, 100.0f, 10.0f), _dragPoint);

                }
            }
            else
            {
                _dragBody = null;
                _dragPoint = -1;
            }

            if (Input.GetMouseButtonDown(0))
            {
                if (_dragBody == (null))
                {
                    int body;
                    _world.getClosestPointMass(_cursorPos, out body, out _dragPoint);
                    _dragBody = _world.getBody(body);
                }
            }
        }
Exemple #15
0
        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {
            //////////////////////////////////////////////////////////////////////
            GamePadState gs = GamePad.GetState(PlayerIndex.One);

            // perform several updates per frame, with a smal timestep.
            for (int i = 0; i < 5; i++)
            //if (gs.Buttons.Y == ButtonState.Pressed)
            {
                mWorld.update(1f / 200f);

                // dragging!
                if (gs.Buttons.A == ButtonState.Pressed)
                {
                    if (dragBody != null)
                    {
                        PointMass pm = dragBody.getPointMass(dragPoint);
                        if (dragBody.GetType().Name == "DraggableSpringBody")
                            ((DraggableSpringBody)dragBody).setDragForce(JelloPhysics.VectorTools.calculateSpringForce(pm.Position, pm.Velocity, mCursorPos, Vector2.Zero, 0.0f, 100.0f, 10.0f), dragPoint);
                        else if (dragBody.GetType().Name == "DraggablePressureBody")
                            ((DraggablePressureBody)dragBody).setDragForce(JelloPhysics.VectorTools.calculateSpringForce(pm.Position, pm.Velocity, mCursorPos, Vector2.Zero, 0.0f, 100.0f, 10.0f), dragPoint);

                    }
                }
                else
                {
                    dragBody = null;
                    dragPoint = -1;
                }

            }

            // QUITTING
            if (gs.Buttons.Back == ButtonState.Pressed)
                this.Exit();

            // CURSOR MOVEMENT - 360 PAD
            mCursorPos.X += (gs.ThumbSticks.Left.X * gs.ThumbSticks.Left.X) * 0.5f * ((gs.ThumbSticks.Left.X > 0) ? 1 : -1);
            mCursorPos.Y += (gs.ThumbSticks.Left.Y * gs.ThumbSticks.Left.Y) * 0.5f * ((gs.ThumbSticks.Left.Y > 0) ? 1 : -1);

            // CAMERA UPDATE
            Vector2 stray = (mCursorPos - new Vector2(cameraPos.X, cameraPos.Y));
            float maxStrayX = cameraPos.Z * 0.35f;
            float maxStrayY = (screenHeight * maxStrayX) / screenWidth;

            if (Math.Abs(stray.X) > maxStrayX)
                cameraPos.X += (stray.X > 0) ? -(maxStrayX - stray.X) : (maxStrayX + stray.X);

            if (Math.Abs(stray.Y) > maxStrayY)
                cameraPos.Y += (stray.Y > 0) ? -(maxStrayY - stray.Y) : (maxStrayY + stray.Y);

            cameraPos.Z += (gs.Triggers.Left - gs.Triggers.Right);
            if (cameraPos.Z < 5.0f) { cameraPos.Z = 5.0f; }

            // DRAGGING!
            if ((gs.Buttons.A == ButtonState.Pressed) && (oldPadState.Buttons.A == ButtonState.Released))
            {
                if (dragBody == null)
                {
                    int body;
                    mWorld.getClosestPointMass(mCursorPos, out body, out dragPoint);
                    dragBody = mWorld.getBody(body);
                }
            }

            // PRESSURE CHANGE!
            mPressureBodies[0].GasPressure += (gs.ThumbSticks.Right.Y) * 3.0f;

            // DEBUG VISUALIZATION
            if ((gs.Buttons.LeftShoulder == ButtonState.Pressed) && (oldPadState.Buttons.LeftShoulder == ButtonState.Released))
                showDebug = !showDebug;

            if ((gs.Buttons.RightShoulder == ButtonState.Pressed) && (oldPadState.Buttons.RightShoulder == ButtonState.Released))
                showVelocities = !showVelocities;

            oldPadState = gs;

            base.Update(gameTime);
        }
Exemple #16
0
        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            #if XBOX360
            graphics.PreferredBackBufferWidth = this.Window.ClientBounds.Width;
            graphics.PreferredBackBufferHeight = this.Window.ClientBounds.Height;
            graphics.PreferMultiSampling = true;
            #else
            graphics.PreferredBackBufferWidth = 800;
            graphics.PreferredBackBufferHeight = 600;
            #endif
            graphics.ApplyChanges();

            screenWidth = graphics.GraphicsDevice.Viewport.Width;
            screenHeight = graphics.GraphicsDevice.Viewport.Height;

            // setup camera
            cameraPos = new Vector3(-2f, -15f, 25f);
            cameraLookVector = Vector3.Forward;

            // basic effect used for drawing all objects, based on vertexcolor.
            lineEffect = new BasicEffect(graphics.GraphicsDevice, null);
            lineEffect.LightingEnabled = false;
            lineEffect.VertexColorEnabled = true;
            lineEffect.Alpha = 1.0f;

            // initialize physics world
            mWorld = new World();

            // lists to keep track of bodies.
            mSpringBodies = new List<DraggableSpringBody>();
            mPressureBodies = new List<DraggablePressureBody>();
            mStaticBodies = new List<Body>();

            // STATIC COLLISION SHAPE
            // all Closed Shape objects are assumed to be a list of lines going from point to point, with the last point
            // connecting back to the first point to close the shape.  This is a simple rectangle to represent the ground for this demo.
            // ClosedShape objects are automatically "centered" when you call finish(), and that center becomes the center when
            // setting the position of the object.
            ClosedShape stat = new ClosedShape();
            stat.begin();
            stat.addVertex(new Vector2(-20f,-1f));
            stat.addVertex(new Vector2(-20f, 1f));
            stat.addVertex(new Vector2(20f, 1f));
            stat.addVertex(new Vector2(20f, -1f));
            stat.finish();

            // creating the body.  Since this is a static body, we can use the base class Body.
            // setting the mass per point to PositiveInfinity makes it immobile / static.
            Body b = new Body(mWorld, stat, float.PositiveInfinity, new Vector2(0f, -19f), 0, Vector2.One, false);
            mStaticBodies.Add(b);

            // this is a more complex body, in the shape of a capital "I", and connected with many internal springs.
            ClosedShape shape = new ClosedShape();
            shape.begin();
            shape.addVertex(new Vector2(-1.5f, 2.0f));
            shape.addVertex(new Vector2(-0.5f, 2.0f));
            shape.addVertex(new Vector2(0.5f, 2.0f));
            shape.addVertex(new Vector2(1.5f, 2.0f));
            shape.addVertex(new Vector2(1.5f, 1.0f));
            shape.addVertex(new Vector2(0.5f, 1.0f));
            shape.addVertex(new Vector2(0.5f, -1.0f));
            shape.addVertex(new Vector2(1.5f, -1.0f));
            shape.addVertex(new Vector2(1.5f, -2.0f));
            shape.addVertex(new Vector2(0.5f, -2.0f));
            shape.addVertex(new Vector2(-0.5f, -2.0f));
            shape.addVertex(new Vector2(-1.5f, -2.0f));
            shape.addVertex(new Vector2(-1.5f, -1.0f));
            shape.addVertex(new Vector2(-0.5f, -1.0f));
            shape.addVertex(new Vector2(-0.5f, 1.0f));
            shape.addVertex(new Vector2(-1.5f, 1.0f));
            shape.finish();

            // draggablespringbody is an inherited version of SpringBody that includes polygons for visualization, and the
            // ability to drag the body around the screen with the cursor.
            for (int x = -8; x <= 8; x += 4)
            {
                DraggableSpringBody body = new DraggableSpringBody(mWorld, shape, 1f, 150.0f, 5.0f, 300.0f, 15.0f, new Vector2(x, 0), 0.0f, Vector2.One);
                body.addInternalSpring(0, 14, 300.0f, 10.0f);
                body.addInternalSpring(1, 14, 300.0f, 10.0f);
                body.addInternalSpring(1, 15, 300.0f, 10.0f);
                body.addInternalSpring(1, 5, 300.0f, 10.0f);
                body.addInternalSpring(2, 14, 300.0f, 10.0f);
                body.addInternalSpring(2, 5, 300.0f, 10.0f);
                body.addInternalSpring(1, 5, 300.0f, 10.0f);
                body.addInternalSpring(14, 5, 300.0f, 10.0f);
                body.addInternalSpring(2, 4, 300.0f, 10.0f);
                body.addInternalSpring(3, 5, 300.0f, 10.0f);
                body.addInternalSpring(14, 6, 300.0f, 10.0f);
                body.addInternalSpring(5, 13, 300.0f, 10.0f);
                body.addInternalSpring(13, 6, 300.0f, 10.0f);
                body.addInternalSpring(12, 10, 300.0f, 10.0f);
                body.addInternalSpring(13, 11, 300.0f, 10.0f);
                body.addInternalSpring(13, 10, 300.0f, 10.0f);
                body.addInternalSpring(13, 9, 300.0f, 10.0f);
                body.addInternalSpring(6, 10, 300.0f, 10.0f);
                body.addInternalSpring(6, 9, 300.0f, 10.0f);
                body.addInternalSpring(6, 8, 300.0f, 10.0f);
                body.addInternalSpring(7, 9, 300.0f, 10.0f);

                // polygons!
                body.addTriangle(0, 15, 1);
                body.addTriangle(1, 15, 14);
                body.addTriangle(1, 14, 5);
                body.addTriangle(1, 5, 2);
                body.addTriangle(2, 5, 4);
                body.addTriangle(2, 4, 3);
                body.addTriangle(14, 13, 6);
                body.addTriangle(14, 6, 5);
                body.addTriangle(12, 11, 10);
                body.addTriangle(12, 10, 13);
                body.addTriangle(13, 10, 9);
                body.addTriangle(13, 9, 6);
                body.addTriangle(6, 9, 8);
                body.addTriangle(6, 8, 7);
                body.finalizeTriangles(Color.SpringGreen, Color.Navy);

                mSpringBodies.Add(body);
            }

            // pressure body. similar to a SpringBody, but with internal pressurized gas to help maintain shape.
            JelloPhysics.ClosedShape ball = new ClosedShape();
            ball.begin();
            for (int i = 0; i < 360; i += 20)
            {
                ball.addVertex(new Vector2((float)Math.Cos(MathHelper.ToRadians((float)-i)), (float)Math.Sin(MathHelper.ToRadians((float)-i))));
            }
            ball.finish();

            // make many of these.
            for (int x = -10; x <= 10; x+=5)
            {
                DraggablePressureBody pb = new DraggablePressureBody(mWorld, ball, 1.0f, 40.0f, 10.0f, 1.0f, 300.0f, 20.0f, new Vector2(x, -12), 0, Vector2.One);
                pb.addTriangle(0, 10, 9);
                pb.addTriangle(0, 9, 1);
                pb.addTriangle(1, 9, 8);
                pb.addTriangle(1, 8, 2);
                pb.addTriangle(2, 8, 7);
                pb.addTriangle(2, 7, 3);
                pb.addTriangle(3, 7, 6);
                pb.addTriangle(3, 6, 4);
                pb.addTriangle(4, 6, 5);
                pb.addTriangle(17, 10, 0);
                pb.addTriangle(17, 11, 10);
                pb.addTriangle(16, 11, 17);
                pb.addTriangle(16, 12, 11);
                pb.addTriangle(15, 12, 16);
                pb.addTriangle(15, 13, 12);
                pb.addTriangle(14, 12, 15);
                pb.addTriangle(14, 13, 12);
                pb.finalizeTriangles((x==-10) ? Color.Teal : Color.Maroon);
                mPressureBodies.Add(pb);
            }

            // default cursor position, etc.
            mCursorPos = new Vector2(cameraPos.X, cameraPos.Y);

            base.Initialize();
        }