123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137 |
- using System;
- using System.Collections.Generic;
- using FarseerPhysics.Collision.Shapes;
- using FarseerPhysics.Common;
- using FarseerPhysics.Dynamics.Contacts;
- using FarseerPhysics.Factories;
- using Microsoft.Xna.Framework;
- namespace FarseerPhysics.Dynamics
- {
- /// <summary>
- /// A type of body that supports multiple fixtures that can break apart.
- /// </summary>
- public class BreakableBody
- {
- public bool Broken;
- public Body MainBody;
- public List<Fixture> Parts = new List<Fixture>(8);
- /// <summary>
- /// The force needed to break the body apart.
- /// Default: 500
- /// </summary>
- public float Strength = 500.0f;
- private float[] _angularVelocitiesCache = new float[8];
- private bool _break;
- private Vector2[] _velocitiesCache = new Vector2[8];
- private World _world;
- public BreakableBody(IEnumerable<Vertices> vertices, World world, float density)
- : this(vertices, world, density, null)
- {
- }
- public BreakableBody(IEnumerable<Vertices> vertices, World world, float density, object userData)
- {
- _world = world;
- _world.ContactManager.PostSolve += PostSolve;
- MainBody = new Body(_world);
- MainBody.BodyType = BodyType.Dynamic;
- foreach (Vertices part in vertices)
- {
- PolygonShape polygonShape = new PolygonShape(part, density);
- Fixture fixture = MainBody.CreateFixture(polygonShape, userData);
- Parts.Add(fixture);
- }
- }
- private void PostSolve(Contact contact, ContactConstraint impulse)
- {
- if (!Broken)
- {
- if (Parts.Contains(contact.FixtureA) || Parts.Contains(contact.FixtureB))
- {
- float maxImpulse = 0.0f;
- int count = contact.Manifold.PointCount;
- for (int i = 0; i < count; ++i)
- {
- maxImpulse = Math.Max(maxImpulse, impulse.Points[i].NormalImpulse);
- }
- if (maxImpulse > Strength)
- {
- // Flag the body for breaking.
- _break = true;
- }
- }
- }
- }
- public void Update()
- {
- if (_break)
- {
- Decompose();
- Broken = true;
- _break = false;
- }
- // Cache velocities to improve movement on breakage.
- if (Broken == false)
- {
- //Enlarge the cache if needed
- if (Parts.Count > _angularVelocitiesCache.Length)
- {
- _velocitiesCache = new Vector2[Parts.Count];
- _angularVelocitiesCache = new float[Parts.Count];
- }
- //Cache the linear and angular velocities.
- for (int i = 0; i < Parts.Count; i++)
- {
- _velocitiesCache[i] = Parts[i].Body.LinearVelocity;
- _angularVelocitiesCache[i] = Parts[i].Body.AngularVelocity;
- }
- }
- }
- private void Decompose()
- {
- //Unsubsribe from the PostSolve delegate
- _world.ContactManager.PostSolve -= PostSolve;
- for (int i = 0; i < Parts.Count; i++)
- {
- Fixture fixture = Parts[i];
- Shape shape = fixture.Shape.Clone();
- object userdata = fixture.UserData;
- MainBody.DestroyFixture(fixture);
- Body body = BodyFactory.CreateBody(_world);
- body.BodyType = BodyType.Dynamic;
- body.Position = MainBody.Position;
- body.Rotation = MainBody.Rotation;
- body.UserData = MainBody.UserData;
- body.CreateFixture(shape, userdata);
- body.AngularVelocity = _angularVelocitiesCache[i];
- body.LinearVelocity = _velocitiesCache[i];
- }
- _world.RemoveBody(MainBody);
- _world.RemoveBreakableBody(this);
- }
- public void Break()
- {
- _break = true;
- }
- }
- }
|