private void Reset(FSFixture fA, int indexA, FSFixture fB, int indexB) { Flags = ContactFlags.Enabled; FixtureA = fA; FixtureB = fB; ChildIndexA = indexA; ChildIndexB = indexB; Manifold.PointCount = 0; NodeA.Contact = null; NodeA.Prev = null; NodeA.Next = null; NodeA.Other = null; NodeB.Contact = null; NodeB.Prev = null; NodeB.Next = null; NodeB.Other = null; TOICount = 0; //FPE: We only set the friction and restitution if we are not destroying the contact if (FixtureA != null && FixtureB != null) { Friction = FSSettings.MixFriction(FixtureA.Friction, FixtureB.Friction); Restitution = FSSettings.MixRestitution(FixtureA.Restitution, FixtureB.Restitution); } TangentSpeed = 0; }
private void PreSolve(Contact contact, ref Manifold oldManifold) { if ((Flags & DebugViewFlags.ContactPoints) == DebugViewFlags.ContactPoints) { Manifold manifold = contact.Manifold; if (manifold.PointCount == 0) { return; } FSFixture fixtureA = contact.FixtureA; FixedArray2 <PointState> state1, state2; Collision.Collision.GetPointStates(out state1, out state2, ref oldManifold, ref manifold); FixedArray2 <FVector2> points; FVector2 normal; contact.GetWorldManifold(out normal, out points); for (int i = 0; i < manifold.PointCount && _pointCount < MaxContactPoints; ++i) { if (fixtureA == null) { _points[i] = new ContactPoint(); } ContactPoint cp = _points[_pointCount]; cp.Position = points[i]; cp.Normal = normal; cp.State = state2[i]; _points[_pointCount] = cp; ++_pointCount; } } }
private bool OnCollisionEvent(FSFixture fixtureA, FSFixture fixtureB, Contact contact) { if (!lastContacts.Contains(contact)) { lastContacts.Add(contact); } return(true); }
public void DrawShape(FSFixture fixture, Transform xf, Color color) { switch (fixture.ShapeType) { case ShapeType.Circle: { CircleShape circle = (CircleShape)fixture.Shape; FVector2 center = MathUtils.Mul(ref xf, circle.Position); float radius = circle.Radius; FVector2 axis = MathUtils.Mul(xf.q, new FVector2(1.0f, 0.0f)); DrawSolidCircle(center, radius, axis, color); } break; case ShapeType.Polygon: { PolygonShape poly = (PolygonShape)fixture.Shape; int vertexCount = poly.Vertices.Count; Debug.Assert(vertexCount <= FSSettings.MaxPolygonVertices); for (int i = 0; i < vertexCount; ++i) { _tempVertices[i] = MathUtils.Mul(ref xf, poly.Vertices[i]); } DrawSolidPolygon(_tempVertices, vertexCount, color); } break; case ShapeType.Edge: { EdgeShape edge = (EdgeShape)fixture.Shape; FVector2 v1 = MathUtils.Mul(ref xf, edge.Vertex1); FVector2 v2 = MathUtils.Mul(ref xf, edge.Vertex2); DrawSegment(v1, v2, color); } break; case ShapeType.Chain: { ChainShape chain = (ChainShape)fixture.Shape; int count = chain.Vertices.Count; FVector2 v1 = MathUtils.Mul(ref xf, chain.Vertices[count - 1]); DrawCircle(v1, 0.05f, color); for (int i = 0; i < count; ++i) { FVector2 v2 = MathUtils.Mul(ref xf, chain.Vertices[i]); DrawSegment(v1, v2, color); v1 = v2; } } break; } }
private bool OnCollisionEvent(FSFixture fixtureA, FSFixture fixtureB, Contact contact) { FSBody bodyB = fixtureB.Body; //if (bodyB.UserTag == "Respawn") { FVector2 normal; FarseerPhysics.Common.FixedArray2 <FVector2> contactPoints; contact.GetWorldManifold(out normal, out contactPoints); bodyB.ApplyLinearImpulse(normal * (-1 * Force)); //} return(true); }
private bool OnCollisionEvent(FSFixture fixtureA, FSFixture fixtureB, Contact contact) { FSBody bodyB = fixtureB.Body; //if (bodyB.UserTag == "Respawn") { FVector2 normal; FarseerPhysics.Common.FixedArray2 <FVector2> contactPoints; contact.GetWorldManifold(out normal, out contactPoints); bodyB.SetTransform(FSHelper.Vector3ToFVector2(RespawnPosition.position), 0f); bodyB.ResetDynamics(); //} return(true); }
internal static Contact Create(FSFixture fixtureA, int indexA, FSFixture fixtureB, int indexB) { ShapeType type1 = fixtureA.ShapeType; ShapeType type2 = fixtureB.ShapeType; Debug.Assert(ShapeType.Unknown < type1 && type1 < ShapeType.TypeCount); Debug.Assert(ShapeType.Unknown < type2 && type2 < ShapeType.TypeCount); Contact c; Queue <Contact> pool = fixtureA.Body.World.ContactPool; if (pool.Count > 0) { c = pool.Dequeue(); if ((type1 >= type2 || (type1 == ShapeType.Edge && type2 == ShapeType.Polygon)) && !(type2 == ShapeType.Edge && type1 == ShapeType.Polygon)) { c.Reset(fixtureA, indexA, fixtureB, indexB); } else { c.Reset(fixtureB, indexB, fixtureA, indexA); } } else { // Edge+Polygon is non-symetrical due to the way Erin handles collision type registration. if ((type1 >= type2 || (type1 == ShapeType.Edge && type2 == ShapeType.Polygon)) && !(type2 == ShapeType.Edge && type1 == ShapeType.Polygon)) { c = new Contact(fixtureA, indexA, fixtureB, indexB); } else { c = new Contact(fixtureB, indexB, fixtureA, indexA); } } c._type = _registers[(int)type1, (int)type2]; return(c); }
public override void Start() { base.Start(); FSBody body; // Create 'basket' { body = BodyFactory.CreateBody(FSWorldComponent.PhysicsWorld, new FVector2(150f / physScale, -100f / physScale)); body.BodyType = BodyType.Dynamic; body.IsBullet = true; // bottom fixture FSFixture f = FixtureFactory.AttachRectangle(90f / physScale, 9f / physScale, 4f, FVector2.Zero, body); f.Restitution = 1.4f; // left fixture f = FixtureFactory.AttachRectangle(9f / physScale, 90f / physScale, 4f, new FVector2(-43.5f / physScale, 50.5f / physScale), body); f.Restitution = 1.4f; // right fixture f = FixtureFactory.AttachRectangle(9f / physScale, 90f / physScale, 4f, new FVector2(43.5f / physScale, 50.5f / physScale), body); f.Restitution = 1.4f; } // add some small circles for effect for (int i = 0; i < 5; i++) { body = BodyFactory.CreateBody(FSWorldComponent.PhysicsWorld, new FVector2((Random.value * 300f + 250f) / physScale, (Random.value * -320f - 20f) / physScale)); FSFixture f = FixtureFactory.AttachCircle((Random.value * 10f + 5f) / physScale, 1f, body); f.Friction = 0.3f; f.Restitution = 1.1f; body.BodyType = BodyType.Dynamic; body.IsBullet = true; } }
public virtual void Start() { if (initialized) { return; } initialized = true; //Body = BodyFactory.CreateRectangle(FSWorldComponent.PhysicsWorld, 1f, 1f, Density); body = new FSBody(FSWorldComponent.PhysicsWorld); FSShapeComponent[] shapecs = GetComponentsInChildren <FSShapeComponent>(); //print("shapes " + name + ": " + shapecs.Length); foreach (FSShapeComponent shp in shapecs) { FSFixture fixture = body.CreateFixture(shp.GetShape()); fixture.Friction = shp.Friction; fixture.Restitution = shp.Restitution; if (shp.tag.Length > 0) { fixture.UserTag = shp.tag; } if (shp.CollisionFilter == CollisionGroupDef.Manually) { fixture.CollisionCategories = shp.BelongsTo; fixture.CollidesWith = shp.CollidesWith; } else if (shp.CollisionFilter == CollisionGroupDef.PresetFile) { if (shp.CollisionGroup != null) { fixture.CollisionCategories = shp.CollisionGroup.BelongsTo; fixture.CollidesWith = shp.CollisionGroup.CollidesWith; } } } // try to get a single shape at the same level // if theres no children if (shapecs.Length < 1) { var shape = GetComponent <FSShapeComponent>(); if (shape != null) { var fixture = body.CreateFixture(shape.GetShape()); fixture.Friction = shape.Friction; fixture.Restitution = shape.Restitution; if (shape.tag.Length > 0) { fixture.UserTag = shape.tag; } if (shape.CollisionFilter == CollisionGroupDef.Manually) { fixture.CollisionCategories = shape.BelongsTo; fixture.CollidesWith = shape.CollidesWith; } else if (shape.CollisionFilter == CollisionGroupDef.PresetFile) { if (shape.CollisionGroup != null) { fixture.CollisionCategories = shape.CollisionGroup.BelongsTo; fixture.CollidesWith = shape.CollisionGroup.CollidesWith; } } } } body.BodyType = Type; body.Position = new FVector2(transform.position.x, transform.position.y); body.Rotation = transform.rotation.eulerAngles.z * Mathf.Deg2Rad; if (this.tag.Length > 0) { body.UserTag = this.tag; } body.UserFSBodyComponent = this; }
public override void Update(float dt) { _uniqueBodies.Clear(); World.QueryAABB(fixture => { if (fixture.Body.IsStatic || !fixture.Body.Awake) { return(true); } if (!_uniqueBodies.ContainsKey(fixture.Body.BodyId)) { _uniqueBodies.Add(fixture.Body.BodyId, fixture.Body); } return(true); }, ref _container); foreach (KeyValuePair <int, FSBody> kv in _uniqueBodies) { FSBody body = kv.Value; FVector2 areac = FVector2.Zero; FVector2 massc = FVector2.Zero; float area = 0; float mass = 0; for (int j = 0; j < body.FixtureList.Count; j++) { FSFixture fixture = body.FixtureList[j]; if (fixture.Shape.ShapeType != ShapeType.Polygon && fixture.Shape.ShapeType != ShapeType.Circle) { continue; } Shape shape = fixture.Shape; FVector2 sc; float sarea = shape.ComputeSubmergedArea(_normal, _offset, body.Xf, out sc); area += sarea; areac.X += sarea * sc.X; areac.Y += sarea * sc.Y; mass += sarea * shape.Density; massc.X += sarea * sc.X * shape.Density; massc.Y += sarea * sc.Y * shape.Density; } areac.X /= area; areac.Y /= area; massc.X /= mass; massc.Y /= mass; if (area < FSSettings.Epsilon) { continue; } //Buoyancy FVector2 buoyancyForce = -Density * area * _gravity; body.ApplyForce(buoyancyForce, massc); //Linear drag FVector2 dragForce = body.GetLinearVelocityFromWorldPoint(areac) - Velocity; dragForce *= -LinearDragCoefficient * area; body.ApplyForce(dragForce, areac); //Angular drag body.ApplyTorque(-body.Inertia / body.Mass * area * body.AngularVelocity * AngularDragCoefficient); } }
public override void Start() { base.Start(); CircleShape circ; PolygonShape box; FSFixture fixture; FSRevoluteJoint joint; // Add 2 ragdolls along the top for (int i = 0; i < 2; i++) { float startX = 70f + Random.value * 20f + 480f * (float)i; float startY = (20f + Random.value * 50f) * -1f; // Head FSBody head = new FSBody(FSWorldComponent.PhysicsWorld); circ = new CircleShape(12.5f / physScale, 1f); fixture = new FSFixture(head, circ); fixture.Friction = 0.4f; fixture.Restitution = 0.3f; head.Position = new FVector2(startX / physScale, startY / physScale); head.ApplyLinearImpulse(new FVector2(Random.value * 100f - 50f, Random.value * 100f - 50f), head.Position); head.BodyType = BodyType.Dynamic; // Torso 1 FSBody torso1 = new FSBody(FSWorldComponent.PhysicsWorld); box = new PolygonShape(1f); box.SetAsBox(15f / physScale, 10f / physScale); fixture = new FSFixture(torso1, box); fixture.Friction = 0.4f; fixture.Restitution = 0.1f; torso1.Position = new FVector2(startX / physScale, (startY - 28f) / physScale); torso1.BodyType = BodyType.Dynamic; // Torso 2 FSBody torso2 = new FSBody(FSWorldComponent.PhysicsWorld); box = new PolygonShape(1f); box.SetAsBox(15f / physScale, 10f / physScale); fixture = new FSFixture(torso2, box); fixture.Friction = 0.4f; fixture.Restitution = 0.1f; torso2.Position = new FVector2(startX / physScale, (startY - 43f) / physScale); torso2.BodyType = BodyType.Dynamic; // Torso 3 FSBody torso3 = new FSBody(FSWorldComponent.PhysicsWorld); box = new PolygonShape(1f); box.SetAsBox(15f / physScale, 10f / physScale); fixture = new FSFixture(torso3, box); fixture.Friction = 0.4f; fixture.Restitution = 0.1f; torso3.Position = new FVector2(startX / physScale, (startY - 58f) / physScale); torso3.BodyType = BodyType.Dynamic; // UpperArm // L FSBody upperArmL = new FSBody(FSWorldComponent.PhysicsWorld); box = new PolygonShape(1f); box.SetAsBox(18f / physScale, 6.5f / physScale); fixture = new FSFixture(upperArmL, box); fixture.Friction = 0.4f; fixture.Restitution = 0.1f; upperArmL.Position = new FVector2((startX - 30f) / physScale, (startY - 20f) / physScale); upperArmL.BodyType = BodyType.Dynamic; // R FSBody upperArmR = new FSBody(FSWorldComponent.PhysicsWorld); box = new PolygonShape(1f); box.SetAsBox(18f / physScale, 6.5f / physScale); fixture = new FSFixture(upperArmR, box); fixture.Friction = 0.4f; fixture.Restitution = 0.1f; upperArmR.Position = new FVector2((startX + 30f) / physScale, (startY - 20f) / physScale); upperArmR.BodyType = BodyType.Dynamic; // LowerArm // L FSBody lowerArmL = new FSBody(FSWorldComponent.PhysicsWorld); box = new PolygonShape(1f); box.SetAsBox(17f / physScale, 6f / physScale); fixture = new FSFixture(lowerArmL, box); fixture.Friction = 0.4f; fixture.Restitution = 0.1f; lowerArmL.Position = new FVector2((startX - 57f) / physScale, (startY - 20f) / physScale); lowerArmL.BodyType = BodyType.Dynamic; // R FSBody lowerArmR = new FSBody(FSWorldComponent.PhysicsWorld); box = new PolygonShape(1f); box.SetAsBox(17f / physScale, 6f / physScale); fixture = new FSFixture(lowerArmR, box); fixture.Friction = 0.4f; fixture.Restitution = 0.1f; lowerArmR.Position = new FVector2((startX + 57f) / physScale, (startY - 20f) / physScale); lowerArmR.BodyType = BodyType.Dynamic; // UpperLeg // L FSBody upperLegL = new FSBody(FSWorldComponent.PhysicsWorld); box = new PolygonShape(1f); box.SetAsBox(7.5f / physScale, 22f / physScale); fixture = new FSFixture(upperLegL, box); fixture.Friction = 0.4f; fixture.Restitution = 0.1f; upperLegL.Position = new FVector2((startX - 8f) / physScale, (startY - 85f) / physScale); upperLegL.BodyType = BodyType.Dynamic; // R FSBody upperLegR = new FSBody(FSWorldComponent.PhysicsWorld); box = new PolygonShape(1f); box.SetAsBox(7.5f / physScale, 22f / physScale); fixture = new FSFixture(upperLegR, box); fixture.Friction = 0.4f; fixture.Restitution = 0.1f; upperLegR.Position = new FVector2((startX + 8f) / physScale, (startY - 85f) / physScale); upperLegR.BodyType = BodyType.Dynamic; // LowerLeg // L FSBody lowerLegL = new FSBody(FSWorldComponent.PhysicsWorld); box = new PolygonShape(1f); box.SetAsBox(7.5f / physScale, 22f / physScale); fixture = new FSFixture(lowerLegL, box); fixture.Friction = 0.4f; fixture.Restitution = 0.1f; lowerLegL.Position = new FVector2((startX - 8f) / physScale, (startY - 120f) / physScale); lowerLegL.BodyType = BodyType.Dynamic; // R FSBody lowerLegR = new FSBody(FSWorldComponent.PhysicsWorld); box = new PolygonShape(1f); box.SetAsBox(7.5f / physScale, 22f / physScale); fixture = new FSFixture(lowerLegR, box); fixture.Friction = 0.4f; fixture.Restitution = 0.1f; lowerLegR.Position = new FVector2((startX + 8f) / physScale, (startY - 120f) / physScale); lowerLegR.BodyType = BodyType.Dynamic; // JOINTS // Head to shoulders joint = JointFactory.CreateRevoluteJoint(FSWorldComponent.PhysicsWorld, torso1, head, head.GetLocalPoint(new FVector2(startX / physScale, (startY - 15f) / physScale))); joint.LowerLimit = -40f * Mathf.Deg2Rad; joint.UpperLimit = 40f * Mathf.Deg2Rad; joint.LimitEnabled = true; joint.CollideConnected = false; // Upper arm to shoulders // L joint = JointFactory.CreateRevoluteJoint(FSWorldComponent.PhysicsWorld, torso1, upperArmL, upperArmL.GetLocalPoint(new FVector2((startX - 18f) / physScale, (startY - 20f) / physScale))); joint.LowerLimit = -85f * Mathf.Deg2Rad; joint.UpperLimit = 130f * Mathf.Deg2Rad; joint.LimitEnabled = true; joint.CollideConnected = false; // R joint = JointFactory.CreateRevoluteJoint(FSWorldComponent.PhysicsWorld, torso1, upperArmR, upperArmR.GetLocalPoint(new FVector2((startX + 18f) / physScale, (startY - 20f) / physScale))); joint.LowerLimit = -130f * Mathf.Deg2Rad; joint.UpperLimit = 85f * Mathf.Deg2Rad; joint.LimitEnabled = true; joint.CollideConnected = false; // Lower arm to upper arm // L joint = JointFactory.CreateRevoluteJoint(FSWorldComponent.PhysicsWorld, upperArmL, lowerArmL, lowerArmL.GetLocalPoint(new FVector2((startX - 45f) / physScale, (startY - 20f) / physScale))); joint.LowerLimit = -130f * Mathf.Deg2Rad; joint.UpperLimit = 10f * Mathf.Deg2Rad; joint.LimitEnabled = true; joint.CollideConnected = false; // R joint = JointFactory.CreateRevoluteJoint(FSWorldComponent.PhysicsWorld, upperArmR, lowerArmR, lowerArmR.GetLocalPoint(new FVector2((startX + 45f) / physScale, (startY - 20f) / physScale))); joint.LowerLimit = -10f * Mathf.Deg2Rad; joint.UpperLimit = 130f * Mathf.Deg2Rad; joint.LimitEnabled = true; joint.CollideConnected = false; // Shoulders/stomach joint = JointFactory.CreateRevoluteJoint(FSWorldComponent.PhysicsWorld, torso1, torso2, torso2.GetLocalPoint(new FVector2((startX + 0f) / physScale, (startY - 35f) / physScale))); joint.LowerLimit = -15f * Mathf.Deg2Rad; joint.UpperLimit = 15f * Mathf.Deg2Rad; joint.LimitEnabled = true; joint.CollideConnected = false; // Stomach/hips joint = JointFactory.CreateRevoluteJoint(FSWorldComponent.PhysicsWorld, torso2, torso3, torso3.GetLocalPoint(new FVector2((startX + 0f) / physScale, (startY - 50f) / physScale))); joint.LowerLimit = -15f * Mathf.Deg2Rad; joint.UpperLimit = 15f * Mathf.Deg2Rad; joint.LimitEnabled = true; joint.CollideConnected = false; // Torso to upper leg // L joint = JointFactory.CreateRevoluteJoint(FSWorldComponent.PhysicsWorld, torso3, upperLegL, upperLegL.GetLocalPoint(new FVector2((startX - 8f) / physScale, (startY - 72f) / physScale))); joint.LowerLimit = -25f * Mathf.Deg2Rad; joint.UpperLimit = 45f * Mathf.Deg2Rad; joint.LimitEnabled = true; joint.CollideConnected = false; // R joint = JointFactory.CreateRevoluteJoint(FSWorldComponent.PhysicsWorld, torso3, upperLegR, upperLegR.GetLocalPoint(new FVector2((startX + 8f) / physScale, (startY - 72f) / physScale))); joint.LowerLimit = -45f * Mathf.Deg2Rad; joint.UpperLimit = 25f * Mathf.Deg2Rad; joint.LimitEnabled = true; joint.CollideConnected = false; // Upper leg to lower leg // L joint = JointFactory.CreateRevoluteJoint(FSWorldComponent.PhysicsWorld, upperLegL, lowerLegL, lowerLegL.GetLocalPoint(new FVector2((startX - 8f) / physScale, (startY - 105f) / physScale))); joint.LowerLimit = -25f * Mathf.Deg2Rad; joint.UpperLimit = 115f * Mathf.Deg2Rad; joint.LimitEnabled = true; joint.CollideConnected = false; // R joint = JointFactory.CreateRevoluteJoint(FSWorldComponent.PhysicsWorld, upperLegR, lowerLegR, lowerLegR.GetLocalPoint(new FVector2((startX + 8f) / physScale, (startY - 105f) / physScale))); joint.LowerLimit = -115f * Mathf.Deg2Rad; joint.UpperLimit = 25f * Mathf.Deg2Rad; joint.LimitEnabled = true; joint.CollideConnected = false; } // Add stairs on the left, these are static bodies so set the type accordingly for (int j = 1; j <= 10; j++) { FSBody body = new FSBody(FSWorldComponent.PhysicsWorld); box = new PolygonShape(1f); box.SetAsBox((10f * (float)j) / physScale, 10f / physScale); fixture = new FSFixture(body, box); body.Position = new FVector2((10f * (float)j) / physScale, ((150f + 20f * (float)j) / physScale) * -1f); } // Add stairs on the right for (int k = 1; k <= 10; k++) { FSBody body = new FSBody(FSWorldComponent.PhysicsWorld); box = new PolygonShape(1f); box.SetAsBox((10f * (float)k) / physScale, 10f / physScale); fixture = new FSFixture(body, box); body.Position = new FVector2((640f - 10f * (float)k) / physScale, ((150f + 20f * (float)k) / physScale) * -1f); } FSBody ground = new FSBody(FSWorldComponent.PhysicsWorld); box = new PolygonShape(1f); box.SetAsBox(30f / physScale, 40f / physScale); fixture = new FSFixture(ground, box); ground.Position = new FVector2(320f / physScale, (320f / physScale) * -1f); }
private Contact(FSFixture fA, int indexA, FSFixture fB, int indexB) { Reset(fA, indexA, fB, indexB); }
//Cutting a shape into two is based on the work of Daid and his prototype BoxCutter: http://www.box2d.org/forum/viewtopic.php?f=3&t=1473 /// <summary> /// Split a fixture into 2 vertice collections using the given entry and exit-point. /// </summary> /// <param name="fixture">The Fixture to split</param> /// <param name="entryPoint">The entry point - The start point</param> /// <param name="exitPoint">The exit point - The end point</param> /// <param name="splitSize">The size of the split. Think of this as the laser-width</param> /// <param name="first">The first collection of vertexes</param> /// <param name="second">The second collection of vertexes</param> public static void SplitShape(FSFixture fixture, FVector2 entryPoint, FVector2 exitPoint, float splitSize, out Vertices first, out Vertices second) { FVector2 localEntryPoint = fixture.Body.GetLocalPoint(ref entryPoint); FVector2 localExitPoint = fixture.Body.GetLocalPoint(ref exitPoint); PolygonShape shape = fixture.Shape as PolygonShape; if (shape == null) { first = new Vertices(); second = new Vertices(); return; } Vertices vertices = new Vertices(shape.Vertices); Vertices[] newPolygon = new Vertices[2]; for (int i = 0; i < newPolygon.Length; i++) { newPolygon[i] = new Vertices(vertices.Count); } int[] cutAdded = { -1, -1 }; int last = -1; for (int i = 0; i < vertices.Count; i++) { int n; //Find out if this vertex is on the old or new shape. if (FVector2.Dot(MathUtils.Cross(localExitPoint - localEntryPoint, 1), vertices[i] - localEntryPoint) > FSSettings.Epsilon) { n = 0; } else { n = 1; } if (last != n) { //If we switch from one shape to the other add the cut vertices. if (last == 0) { Debug.Assert(cutAdded[0] == -1); cutAdded[0] = newPolygon[last].Count; newPolygon[last].Add(localExitPoint); newPolygon[last].Add(localEntryPoint); } if (last == 1) { Debug.Assert(cutAdded[last] == -1); cutAdded[last] = newPolygon[last].Count; newPolygon[last].Add(localEntryPoint); newPolygon[last].Add(localExitPoint); } } newPolygon[n].Add(vertices[i]); last = n; } //Add the cut in case it has not been added yet. if (cutAdded[0] == -1) { cutAdded[0] = newPolygon[0].Count; newPolygon[0].Add(localExitPoint); newPolygon[0].Add(localEntryPoint); } if (cutAdded[1] == -1) { cutAdded[1] = newPolygon[1].Count; newPolygon[1].Add(localEntryPoint); newPolygon[1].Add(localExitPoint); } for (int n = 0; n < 2; n++) { FVector2 offset; if (cutAdded[n] > 0) { offset = (newPolygon[n][cutAdded[n] - 1] - newPolygon[n][cutAdded[n]]); } else { offset = (newPolygon[n][newPolygon[n].Count - 1] - newPolygon[n][0]); } offset.Normalize(); newPolygon[n][cutAdded[n]] += splitSize * offset; if (cutAdded[n] < newPolygon[n].Count - 2) { offset = (newPolygon[n][cutAdded[n] + 2] - newPolygon[n][cutAdded[n] + 1]); } else { offset = (newPolygon[n][0] - newPolygon[n][newPolygon[n].Count - 1]); } offset.Normalize(); newPolygon[n][cutAdded[n] + 1] += splitSize * offset; } first = newPolygon[0]; second = newPolygon[1]; }
public void Reset(FSTimeStep step, int count, Contact[] contacts, Position[] positions, Velocity[] velocities) { _step = step; _count = count; _positions = positions; _velocities = velocities; _contacts = contacts; // grow the array if (_velocityConstraints == null || _velocityConstraints.Length < count) { _velocityConstraints = new ContactVelocityConstraint[count * 2]; _positionConstraints = new ContactPositionConstraint[count * 2]; for (int i = 0; i < _velocityConstraints.Length; i++) { _velocityConstraints[i] = new ContactVelocityConstraint(); } for (int i = 0; i < _positionConstraints.Length; i++) { _positionConstraints[i] = new ContactPositionConstraint(); } } // Initialize position independent portions of the constraints. for (int i = 0; i < _count; ++i) { Contact contact = contacts[i]; FSFixture fixtureA = contact.FixtureA; FSFixture fixtureB = contact.FixtureB; Shape shapeA = fixtureA.Shape; Shape shapeB = fixtureB.Shape; float radiusA = shapeA.Radius; float radiusB = shapeB.Radius; FSBody bodyA = fixtureA.Body; FSBody bodyB = fixtureB.Body; Manifold manifold = contact.Manifold; int pointCount = manifold.PointCount; Debug.Assert(pointCount > 0); ContactVelocityConstraint vc = _velocityConstraints[i]; vc.friction = contact.Friction; vc.restitution = contact.Restitution; vc.tangentSpeed = contact.TangentSpeed; vc.indexA = bodyA.IslandIndex; vc.indexB = bodyB.IslandIndex; vc.invMassA = bodyA.InvMass; vc.invMassB = bodyB.InvMass; vc.invIA = bodyA.InvI; vc.invIB = bodyB.InvI; vc.contactIndex = i; vc.pointCount = pointCount; vc.K.SetZero(); vc.normalMass.SetZero(); ContactPositionConstraint pc = _positionConstraints[i]; pc.indexA = bodyA.IslandIndex; pc.indexB = bodyB.IslandIndex; pc.invMassA = bodyA.InvMass; pc.invMassB = bodyB.InvMass; pc.localCenterA = bodyA.Sweep.LocalCenter; pc.localCenterB = bodyB.Sweep.LocalCenter; pc.invIA = bodyA.InvI; pc.invIB = bodyB.InvI; pc.localNormal = manifold.LocalNormal; pc.localPoint = manifold.LocalPoint; pc.pointCount = pointCount; pc.radiusA = radiusA; pc.radiusB = radiusB; pc.type = manifold.Type; for (int j = 0; j < pointCount; ++j) { ManifoldPoint cp = manifold.Points[j]; VelocityConstraintPoint vcp = vc.points[j]; if (FSSettings.EnableWarmstarting) { vcp.normalImpulse = _step.dtRatio * cp.NormalImpulse; vcp.tangentImpulse = _step.dtRatio * cp.TangentImpulse; } else { vcp.normalImpulse = 0.0f; vcp.tangentImpulse = 0.0f; } vcp.rA = FVector2.Zero; vcp.rB = FVector2.Zero; vcp.normalMass = 0.0f; vcp.tangentMass = 0.0f; vcp.velocityBias = 0.0f; pc.localPoints[j] = cp.LocalPoint; } } }
public override void Start() { base.Start(); FSBody body; tScale = physScale * 2f; // St position in world space m_offset = new FVector2(180f / physScale, -200f / physScale); m_motorSpeed = 2f; m_motorOn = true; FVector2 pivot = new FVector2(0f, 24f / tScale); for (int i = 0; i < 50; i++) { body = BodyFactory.CreateCircle(FSWorldComponent.PhysicsWorld, 3.75f / physScale, 1f, new FVector2((Random.value * 620f + 10f) / physScale, -340f / physScale)); body.BodyType = BodyType.Dynamic; } // chassis { m_chassis = BodyFactory.CreateBody(FSWorldComponent.PhysicsWorld, FVector2.Add(pivot, m_offset)); m_chassis.BodyType = BodyType.Dynamic; FSFixture m_chassis_f = FixtureFactory.AttachRectangle(150f / tScale, 60f / tScale, 1f, FVector2.Zero, m_chassis); //m_chassis_f.CollisionGroup = -1; m_chassis_f.CollisionCategories = Category.Cat10; m_chassis_f.CollidesWith = Category.Cat1; } // wheel { m_wheel = BodyFactory.CreateBody(FSWorldComponent.PhysicsWorld, FVector2.Add(pivot, m_offset)); m_wheel.BodyType = BodyType.Dynamic; FSFixture m_wheel_f = FixtureFactory.AttachCircle(48f / tScale, 1f, m_wheel); //m_wheel_f.CollisionGroup = -1; m_wheel_f.CollisionCategories = Category.Cat10; m_wheel_f.CollidesWith = Category.Cat1; } // glue chassis & wheel { m_motorJoint = JointFactory.CreateRevoluteJoint(FSWorldComponent.PhysicsWorld, m_wheel, m_chassis, FVector2.Zero); m_motorJoint.MotorSpeed = m_motorSpeed; m_motorJoint.MaxMotorTorque = 400f; m_motorJoint.CollideConnected = false; m_motorJoint.MotorEnabled = m_motorOn; } FVector2 wheelAnchor; wheelAnchor = new FVector2(0f, -24f / tScale) + pivot; CreateLeg(-1f, wheelAnchor); CreateLeg(1f, wheelAnchor); m_wheel.Rotation = 120f * Mathf.Deg2Rad; CreateLeg(-1f, wheelAnchor); CreateLeg(1f, wheelAnchor); m_wheel.Rotation = -120f * Mathf.Deg2Rad; CreateLeg(-1f, wheelAnchor); CreateLeg(1f, wheelAnchor); }
internal static Contact Create(FSFixture fixtureA, int indexA, FSFixture fixtureB, int indexB) { ShapeType type1 = fixtureA.ShapeType; ShapeType type2 = fixtureB.ShapeType; Debug.Assert(ShapeType.Unknown < type1 && type1 < ShapeType.TypeCount); Debug.Assert(ShapeType.Unknown < type2 && type2 < ShapeType.TypeCount); Contact c; Queue<Contact> pool = fixtureA.Body.World.ContactPool; if (pool.Count > 0) { c = pool.Dequeue(); if ((type1 >= type2 || (type1 == ShapeType.Edge && type2 == ShapeType.Polygon)) && !(type2 == ShapeType.Edge && type1 == ShapeType.Polygon)) { c.Reset(fixtureA, indexA, fixtureB, indexB); } else { c.Reset(fixtureB, indexB, fixtureA, indexA); } } else { // Edge+Polygon is non-symetrical due to the way Erin handles collision type registration. if ((type1 >= type2 || (type1 == ShapeType.Edge && type2 == ShapeType.Polygon)) && !(type2 == ShapeType.Edge && type1 == ShapeType.Polygon)) { c = new Contact(fixtureA, indexA, fixtureB, indexB); } else { c = new Contact(fixtureB, indexB, fixtureA, indexA); } } c._type = _registers[(int)type1, (int)type2]; return c; }
/// <summary> /// Call this to draw shapes and other debug draw data. /// </summary> private void DrawDebugData() { if ((Flags & DebugViewFlags.Shape) == DebugViewFlags.Shape) { foreach (FSBody b in World.BodyList) { Transform xf; b.GetTransform(out xf); foreach (FSFixture f in b.FixtureList) { if (b.Enabled == false) { DrawShape(f, xf, InactiveShapeColor); } else if (b.BodyType == BodyType.Static) { DrawShape(f, xf, StaticShapeColor); } else if (b.BodyType == BodyType.Kinematic) { DrawShape(f, xf, KinematicShapeColor); } else if (b.Awake == false) { DrawShape(f, xf, SleepingShapeColor); } else { DrawShape(f, xf, DefaultShapeColor); } } } } if ((Flags & DebugViewFlags.ContactPoints) == DebugViewFlags.ContactPoints) { const float axisScale = 0.3f; for (int i = 0; i < _pointCount; ++i) { ContactPoint point = _points[i]; if (point.State == PointState.Add) { // Add DrawPoint(point.Position, 0.1f, new Color(0.3f, 0.95f, 0.3f)); } else if (point.State == PointState.Persist) { // Persist DrawPoint(point.Position, 0.1f, new Color(0.3f, 0.3f, 0.95f)); } if ((Flags & DebugViewFlags.ContactNormals) == DebugViewFlags.ContactNormals) { FVector2 p1 = point.Position; FVector2 p2 = p1 + axisScale * point.Normal; DrawSegment(p1, p2, new Color(0.4f, 0.9f, 0.4f)); } } _pointCount = 0; } if ((Flags & DebugViewFlags.PolygonPoints) == DebugViewFlags.PolygonPoints) { foreach (FSBody body in World.BodyList) { foreach (FSFixture f in body.FixtureList) { PolygonShape polygon = f.Shape as PolygonShape; if (polygon != null) { Transform xf; body.GetTransform(out xf); for (int i = 0; i < polygon.Vertices.Count; i++) { FVector2 tmp = MathUtils.Mul(ref xf, polygon.Vertices[i]); DrawPoint(tmp, 0.1f, Color.red); } } } } } if ((Flags & DebugViewFlags.Joint) == DebugViewFlags.Joint) { foreach (FarseerJoint j in World.JointList) { DrawJoint(j); } } if ((Flags & DebugViewFlags.Pair) == DebugViewFlags.Pair) { Color color = new Color(0.3f, 0.9f, 0.9f); for (int i = 0; i < World.ContactManager.ContactList.Count; i++) { Contact c = World.ContactManager.ContactList[i]; FSFixture fixtureA = c.FixtureA; FSFixture fixtureB = c.FixtureB; AABB aabbA; fixtureA.GetAABB(out aabbA, 0); AABB aabbB; fixtureB.GetAABB(out aabbB, 0); FVector2 cA = aabbA.Center; FVector2 cB = aabbB.Center; DrawSegment(cA, cB, color); } } if ((Flags & DebugViewFlags.AABB) == DebugViewFlags.AABB) { Color color = new Color(0.9f, 0.3f, 0.9f); IBroadPhase bp = World.ContactManager.BroadPhase; foreach (FSBody b in World.BodyList) { if (b.Enabled == false) { continue; } foreach (FSFixture f in b.FixtureList) { for (int t = 0; t < f.ProxyCount; ++t) { FixtureProxy proxy = f.Proxies[t]; AABB aabb; bp.GetFatAABB(proxy.ProxyId, out aabb); DrawAABB(ref aabb, color); } } } } if ((Flags & DebugViewFlags.CenterOfMass) == DebugViewFlags.CenterOfMass) { foreach (FSBody b in World.BodyList) { Transform xf; b.GetTransform(out xf); xf.p = b.WorldCenter; DrawTransform(ref xf); } } if ((Flags & DebugViewFlags.Controllers) == DebugViewFlags.Controllers) { for (int i = 0; i < World.ControllerList.Count; i++) { Controller controller = World.ControllerList[i]; BuoyancyController buoyancy = controller as BuoyancyController; if (buoyancy != null) { AABB container = buoyancy.Container; DrawAABB(ref container, new Color(0.3f, 0.5f, 1.0f)); } } } }
/// <summary> /// This makes the explosive explode /// </summary> /// <param name="pos"> /// The position where the explosion happens /// </param> /// <param name="radius"> /// The explosion radius /// </param> /// <param name="maxForce"> /// The explosion force at the explosion point /// (then is inversely proportional to the square of the distance) /// </param> /// <returns> /// A dictionnary containing all the "exploded" fixtures /// with a list of the applied impulses /// </returns> public Dictionary <FSFixture, List <FVector2> > Activate(FVector2 pos, float radius, float maxForce) { _exploded.Clear(); AABB aabb; aabb.LowerBound = pos + new FVector2(-radius, -radius); aabb.UpperBound = pos + new FVector2(radius, radius); FSFixture[] shapes = new FSFixture[MaxShapes]; // More than 5 shapes in an explosion could be possible, but still strange. FSFixture[] containedShapes = new FSFixture[5]; bool exit = false; int shapeCount = 0; int containedShapeCount = 0; // Query the world for overlapping shapes. World.QueryAABB( fixture => { if (fixture.TestPoint(ref pos)) { if (IgnoreWhenInsideShape) { exit = true; } else { containedShapes[containedShapeCount++] = fixture; } } else { shapes[shapeCount++] = fixture; } // Continue the query. return(true); }, ref aabb); if (exit) { return(_exploded); } // Per shape max/min angles for now. float[] vals = new float[shapeCount * 2]; int valIndex = 0; for (int i = 0; i < shapeCount; ++i) { PolygonShape ps; CircleShape cs = shapes[i].Shape as CircleShape; if (cs != null) { // We create a "diamond" approximation of the circle Vertices v = new Vertices(); FVector2 vec = FVector2.Zero + new FVector2(cs.Radius, 0); v.Add(vec); vec = FVector2.Zero + new FVector2(0, cs.Radius); v.Add(vec); vec = FVector2.Zero + new FVector2(-cs.Radius, cs.Radius); v.Add(vec); vec = FVector2.Zero + new FVector2(0, -cs.Radius); v.Add(vec); ps = new PolygonShape(v, 0); } else { ps = shapes[i].Shape as PolygonShape; } if ((shapes[i].Body.BodyType == BodyType.Dynamic) && ps != null) { FVector2 toCentroid = shapes[i].Body.GetWorldPoint(ps.MassData.Centroid) - pos; float angleToCentroid = (float)Math.Atan2(toCentroid.Y, toCentroid.X); float min = float.MaxValue; float max = float.MinValue; float minAbsolute = 0.0f; float maxAbsolute = 0.0f; for (int j = 0; j < (ps.Vertices.Count()); ++j) { FVector2 toVertex = (shapes[i].Body.GetWorldPoint(ps.Vertices[j]) - pos); float newAngle = (float)Math.Atan2(toVertex.Y, toVertex.X); float diff = (newAngle - angleToCentroid); diff = (diff - MathHelper.Pi) % (2 * MathHelper.Pi); // the minus pi is important. It means cutoff for going other direction is at 180 deg where it needs to be if (diff < 0.0f) { diff += 2 * MathHelper.Pi; // correction for not handling negs } diff -= MathHelper.Pi; if (Math.Abs(diff) > MathHelper.Pi) { throw new ArgumentException("OMG!"); } // Something's wrong, point not in shape but exists angle diff > 180 if (diff > max) { max = diff; maxAbsolute = newAngle; } if (diff < min) { min = diff; minAbsolute = newAngle; } } vals[valIndex] = minAbsolute; ++valIndex; vals[valIndex] = maxAbsolute; ++valIndex; } } Array.Sort(vals, 0, valIndex, _rdc); _data.Clear(); bool rayMissed = true; for (int i = 0; i < valIndex; ++i) { FSFixture shape = null; float midpt; int iplus = (i == valIndex - 1 ? 0 : i + 1); if (vals[i] == vals[iplus]) { continue; } if (i == valIndex - 1) { // the single edgecase midpt = (vals[0] + MathHelper.Pi * 2 + vals[i]); } else { midpt = (vals[i + 1] + vals[i]); } midpt = midpt / 2; FVector2 p1 = pos; FVector2 p2 = radius * new FVector2((float)Math.Cos(midpt), (float)Math.Sin(midpt)) + pos; // RaycastOne bool hitClosest = false; World.RayCast((f, p, n, fr) => { FSBody body = f.Body; if (!IsActiveOn(body)) { return(0); } if (body.UserData != null) { int index = (int)body.UserData; if (index == 0) { // filter return(-1.0f); } } hitClosest = true; shape = f; return(fr); }, p1, p2); //draws radius points if ((hitClosest) && (shape.Body.BodyType == BodyType.Dynamic)) { if ((_data.Count() > 0) && (_data.Last().Body == shape.Body) && (!rayMissed)) { int laPos = _data.Count - 1; ShapeData la = _data[laPos]; la.Max = vals[iplus]; _data[laPos] = la; } else { // make new ShapeData d; d.Body = shape.Body; d.Min = vals[i]; d.Max = vals[iplus]; _data.Add(d); } if ((_data.Count() > 1) && (i == valIndex - 1) && (_data.Last().Body == _data.First().Body) && (_data.Last().Max == _data.First().Min)) { ShapeData fi = _data[0]; fi.Min = _data.Last().Min; _data.RemoveAt(_data.Count() - 1); _data[0] = fi; while (_data.First().Min >= _data.First().Max) { fi.Min -= MathHelper.Pi * 2; _data[0] = fi; } } int lastPos = _data.Count - 1; ShapeData last = _data[lastPos]; while ((_data.Count() > 0) && (_data.Last().Min >= _data.Last().Max)) // just making sure min<max { last.Min = _data.Last().Min - 2 * MathHelper.Pi; _data[lastPos] = last; } rayMissed = false; } else { rayMissed = true; // raycast did not find a shape } } for (int i = 0; i < _data.Count(); ++i) { if (!IsActiveOn(_data[i].Body)) { continue; } float arclen = _data[i].Max - _data[i].Min; float first = MathHelper.Min(MaxEdgeOffset, EdgeRatio * arclen); int insertedRays = (int)Math.Ceiling(((arclen - 2.0f * first) - (MinRays - 1) * MaxAngle) / MaxAngle); if (insertedRays < 0) { insertedRays = 0; } float offset = (arclen - first * 2.0f) / ((float)MinRays + insertedRays - 1); //Note: This loop can go into infinite as it operates on floats. //Added FloatEquals with a large epsilon. for (float j = _data[i].Min + first; j < _data[i].Max || MathUtils.FloatEquals(j, _data[i].Max, 0.0001f); j += offset) { FVector2 p1 = pos; FVector2 p2 = pos + radius * new FVector2((float)Math.Cos(j), (float)Math.Sin(j)); FVector2 hitpoint = FVector2.Zero; float minlambda = float.MaxValue; List <FSFixture> fl = _data[i].Body.FixtureList; for (int x = 0; x < fl.Count; x++) { FSFixture f = fl[x]; RayCastInput ri; ri.Point1 = p1; ri.Point2 = p2; ri.MaxFraction = 50f; RayCastOutput ro; if (f.RayCast(out ro, ref ri, 0)) { if (minlambda > ro.Fraction) { minlambda = ro.Fraction; hitpoint = ro.Fraction * p2 + (1 - ro.Fraction) * p1; } } // the force that is to be applied for this particular ray. // offset is angular coverage. lambda*length of segment is distance. float impulse = (arclen / (MinRays + insertedRays)) * maxForce * 180.0f / MathHelper.Pi * (1.0f - Math.Min(1.0f, minlambda)); // We Apply the impulse!!! FVector2 vectImp = FVector2.Dot(impulse * new FVector2((float)Math.Cos(j), (float)Math.Sin(j)), -ro.Normal) * new FVector2((float)Math.Cos(j), (float)Math.Sin(j)); _data[i].Body.ApplyLinearImpulse(ref vectImp, ref hitpoint); // We gather the fixtures for returning them FVector2 val = FVector2.Zero; List <FVector2> vectorList; if (_exploded.TryGetValue(f, out vectorList)) { val.X += Math.Abs(vectImp.X); val.Y += Math.Abs(vectImp.Y); vectorList.Add(val); } else { vectorList = new List <FVector2>(); val.X = Math.Abs(vectImp.X); val.Y = Math.Abs(vectImp.Y); vectorList.Add(val); _exploded.Add(f, vectorList); } if (minlambda > 1.0f) { hitpoint = p2; } } } } // We check contained shapes for (int i = 0; i < containedShapeCount; ++i) { FSFixture fix = containedShapes[i]; if (!IsActiveOn(fix.Body)) { continue; } float impulse = MinRays * maxForce * 180.0f / MathHelper.Pi; FVector2 hitPoint; CircleShape circShape = fix.Shape as CircleShape; if (circShape != null) { hitPoint = fix.Body.GetWorldPoint(circShape.Position); } else { PolygonShape shape = fix.Shape as PolygonShape; hitPoint = fix.Body.GetWorldPoint(shape.MassData.Centroid); } FVector2 vectImp = impulse * (hitPoint - pos); List <FVector2> vectorList = new List <FVector2>(); vectorList.Add(vectImp); fix.Body.ApplyLinearImpulse(ref vectImp, ref hitPoint); if (!_exploded.ContainsKey(fix)) { _exploded.Add(fix, vectorList); } } return(_exploded); }