2
0

BreakableBody.cs 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. using System;
  2. using System.Collections.Generic;
  3. using FarseerPhysics.Collision.Shapes;
  4. using FarseerPhysics.Common;
  5. using FarseerPhysics.Dynamics.Contacts;
  6. using FarseerPhysics.Factories;
  7. using Microsoft.Xna.Framework;
  8. namespace FarseerPhysics.Dynamics
  9. {
  10. /// <summary>
  11. /// A type of body that supports multiple fixtures that can break apart.
  12. /// </summary>
  13. public class BreakableBody
  14. {
  15. public bool Broken;
  16. public Body MainBody;
  17. public List<Fixture> Parts = new List<Fixture>(8);
  18. /// <summary>
  19. /// The force needed to break the body apart.
  20. /// Default: 500
  21. /// </summary>
  22. public float Strength = 500.0f;
  23. private float[] _angularVelocitiesCache = new float[8];
  24. private bool _break;
  25. private Vector2[] _velocitiesCache = new Vector2[8];
  26. private World _world;
  27. public BreakableBody(IEnumerable<Vertices> vertices, World world, float density)
  28. : this(vertices, world, density, null)
  29. {
  30. }
  31. public BreakableBody(IEnumerable<Vertices> vertices, World world, float density, object userData)
  32. {
  33. _world = world;
  34. _world.ContactManager.PostSolve += PostSolve;
  35. MainBody = new Body(_world);
  36. MainBody.BodyType = BodyType.Dynamic;
  37. foreach (Vertices part in vertices)
  38. {
  39. PolygonShape polygonShape = new PolygonShape(part, density);
  40. Fixture fixture = MainBody.CreateFixture(polygonShape, userData);
  41. Parts.Add(fixture);
  42. }
  43. }
  44. private void PostSolve(Contact contact, ContactConstraint impulse)
  45. {
  46. if (!Broken)
  47. {
  48. if (Parts.Contains(contact.FixtureA) || Parts.Contains(contact.FixtureB))
  49. {
  50. float maxImpulse = 0.0f;
  51. int count = contact.Manifold.PointCount;
  52. for (int i = 0; i < count; ++i)
  53. {
  54. maxImpulse = Math.Max(maxImpulse, impulse.Points[i].NormalImpulse);
  55. }
  56. if (maxImpulse > Strength)
  57. {
  58. // Flag the body for breaking.
  59. _break = true;
  60. }
  61. }
  62. }
  63. }
  64. public void Update()
  65. {
  66. if (_break)
  67. {
  68. Decompose();
  69. Broken = true;
  70. _break = false;
  71. }
  72. // Cache velocities to improve movement on breakage.
  73. if (Broken == false)
  74. {
  75. //Enlarge the cache if needed
  76. if (Parts.Count > _angularVelocitiesCache.Length)
  77. {
  78. _velocitiesCache = new Vector2[Parts.Count];
  79. _angularVelocitiesCache = new float[Parts.Count];
  80. }
  81. //Cache the linear and angular velocities.
  82. for (int i = 0; i < Parts.Count; i++)
  83. {
  84. _velocitiesCache[i] = Parts[i].Body.LinearVelocity;
  85. _angularVelocitiesCache[i] = Parts[i].Body.AngularVelocity;
  86. }
  87. }
  88. }
  89. private void Decompose()
  90. {
  91. //Unsubsribe from the PostSolve delegate
  92. _world.ContactManager.PostSolve -= PostSolve;
  93. for (int i = 0; i < Parts.Count; i++)
  94. {
  95. Fixture fixture = Parts[i];
  96. Shape shape = fixture.Shape.Clone();
  97. object userdata = fixture.UserData;
  98. MainBody.DestroyFixture(fixture);
  99. Body body = BodyFactory.CreateBody(_world);
  100. body.BodyType = BodyType.Dynamic;
  101. body.Position = MainBody.Position;
  102. body.Rotation = MainBody.Rotation;
  103. body.UserData = MainBody.UserData;
  104. body.CreateFixture(shape, userdata);
  105. body.AngularVelocity = _angularVelocitiesCache[i];
  106. body.LinearVelocity = _velocitiesCache[i];
  107. }
  108. _world.RemoveBody(MainBody);
  109. _world.RemoveBreakableBody(this);
  110. }
  111. public void Break()
  112. {
  113. _break = true;
  114. }
  115. }
  116. }