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); } } }
/// <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); } } }
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); } } }
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); dot = Vector2.Dot(ptNorm, norm); 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); } } }