2
0

PhysicsWorld.hx 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. package arm.plugin;
  2. #if arm_physics
  3. import iron.system.Time;
  4. import iron.math.Vec4;
  5. import iron.math.RayCaster;
  6. @:access(arm.plugin.PhysicsBody)
  7. class PhysicsWorld extends iron.Trait {
  8. public static var active: PhysicsWorld = null;
  9. static var vec1: Bt.Vector3 = null;
  10. static var vec2: Bt.Vector3 = null;
  11. static var v1 = new iron.math.Vec4();
  12. static var v2 = new iron.math.Vec4();
  13. var world: Bt.DiscreteDynamicsWorld;
  14. var dispatcher: Bt.CollisionDispatcher;
  15. var contacts: Array<TPair> = [];
  16. var bodyMap = new Map<Int, PhysicsBody>();
  17. var timeScale = 1.0;
  18. var timeStep = 1 / 60;
  19. var maxSteps = 1;
  20. public function new() {
  21. super();
  22. active = this;
  23. vec1 = new Bt.Vector3(0, 0, 0);
  24. vec2 = new Bt.Vector3(0, 0, 0);
  25. init();
  26. // Ensure physics are updated first in the lateUpdate list
  27. _lateUpdate = [lateUpdate];
  28. @:privateAccess iron.App.traitLateUpdates.insert(0, lateUpdate);
  29. }
  30. public function reset() {
  31. for (body in bodyMap) removeBody(body);
  32. }
  33. function init() {
  34. var broadphase = new Bt.DbvtBroadphase();
  35. var collisionConfiguration = new Bt.DefaultCollisionConfiguration();
  36. dispatcher = new Bt.CollisionDispatcher(collisionConfiguration);
  37. var solver = new Bt.SequentialImpulseConstraintSolver();
  38. world = new Bt.DiscreteDynamicsWorld(dispatcher, broadphase, solver, collisionConfiguration);
  39. setGravity(new Vec4(0, 0, -9.81));
  40. }
  41. public function setGravity(v: Vec4) {
  42. vec1.setValue(v.x, v.y, v.z);
  43. world.setGravity(vec1);
  44. }
  45. public function addBody(pb: PhysicsBody) {
  46. world.addRigidBodyToGroup(pb.body, pb.group, pb.mask);
  47. bodyMap.set(pb.id, pb);
  48. }
  49. public function removeBody(pb: PhysicsBody) {
  50. if (pb.destroyed) return;
  51. pb.destroyed = true;
  52. if (world != null) world.removeRigidBody(pb.body);
  53. bodyMap.remove(pb.id);
  54. pb.delete();
  55. }
  56. public function getContacts(pb: PhysicsBody): Array<PhysicsBody> {
  57. if (contacts.length == 0) return null;
  58. var res: Array<PhysicsBody> = [];
  59. for (i in 0...contacts.length) {
  60. var c = contacts[i];
  61. var pb: PhysicsBody = null;
  62. if (c.a == untyped pb.body.userIndex) pb = bodyMap.get(c.b);
  63. else if (c.b == untyped pb.body.userIndex) pb = bodyMap.get(c.a);
  64. if (pb != null && res.indexOf(pb) == -1) res.push(pb);
  65. }
  66. return res;
  67. }
  68. public function getContactPairs(pb: PhysicsBody): Array<TPair> {
  69. if (contacts.length == 0) return null;
  70. var res: Array<TPair> = [];
  71. for (i in 0...contacts.length) {
  72. var c = contacts[i];
  73. if (c.a == untyped pb.body.userIndex) res.push(c);
  74. else if (c.b == untyped pb.body.userIndex) res.push(c);
  75. }
  76. return res;
  77. }
  78. function lateUpdate() {
  79. var t = Time.delta * timeScale;
  80. if (t == 0.0) return; // Simulation paused
  81. world.stepSimulation(timeStep, maxSteps, t);
  82. updateContacts();
  83. for (body in bodyMap) @:privateAccess body.physicsUpdate();
  84. }
  85. function updateContacts() {
  86. contacts = [];
  87. var disp: Bt.Dispatcher = dispatcher;
  88. var numManifolds = disp.getNumManifolds();
  89. for (i in 0...numManifolds) {
  90. var contactManifold = disp.getManifoldByIndexInternal(i);
  91. var body0 = untyped Bt.Ammo.btRigidBody.prototype.upcast(contactManifold.getBody0());
  92. var body1 = untyped Bt.Ammo.btRigidBody.prototype.upcast(contactManifold.getBody1());
  93. var numContacts = contactManifold.getNumContacts();
  94. var pt: Bt.ManifoldPoint = null;
  95. var posA: Bt.Vector3 = null;
  96. var posB: Bt.Vector3 = null;
  97. var nor: Bt.Vector3 = null;
  98. for (j in 0...numContacts) {
  99. pt = contactManifold.getContactPoint(j);
  100. posA = pt.get_m_positionWorldOnA();
  101. posB = pt.get_m_positionWorldOnB();
  102. nor = pt.get_m_normalWorldOnB();
  103. var cp: TPair = {
  104. a: untyped body0.userIndex,
  105. b: untyped body1.userIndex,
  106. posA: new Vec4(posA.x(), posA.y(), posA.z()),
  107. posB: new Vec4(posB.x(), posB.y(), posB.z()),
  108. normOnB: new Vec4(nor.x(), nor.y(), nor.z()),
  109. impulse: pt.getAppliedImpulse(),
  110. distance: pt.getDistance()
  111. };
  112. contacts.push(cp);
  113. }
  114. }
  115. }
  116. public function pickClosest(inputX: Float, inputY: Float): PhysicsBody {
  117. var camera = iron.Scene.active.camera;
  118. var start = new Vec4();
  119. var end = new Vec4();
  120. RayCaster.getDirection(start, end, inputX, inputY, camera);
  121. var hit = rayCast(camera.transform.world.getLoc(), end);
  122. var body = (hit != null) ? hit.body : null;
  123. return body;
  124. }
  125. public function rayCast(from: Vec4, to: Vec4, group: Int = 0x00000001, mask = 0xffffffff): THit {
  126. var rayFrom = vec1;
  127. var rayTo = vec2;
  128. rayFrom.setValue(from.x, from.y, from.z);
  129. rayTo.setValue(to.x, to.y, to.z);
  130. var rayCallback = new Bt.ClosestRayResultCallback(rayFrom, rayTo);
  131. rayCallback.set_m_collisionFilterGroup(group);
  132. rayCallback.set_m_collisionFilterMask(mask);
  133. var worldDyn: Bt.DynamicsWorld = world;
  134. var worldCol: Bt.CollisionWorld = worldDyn;
  135. worldCol.rayTest(rayFrom, rayTo, rayCallback);
  136. var pb: PhysicsBody = null;
  137. var hitInfo: THit = null;
  138. var rc: Bt.RayResultCallback = rayCallback;
  139. if (rc.hasHit()) {
  140. var co = rayCallback.get_m_collisionObject();
  141. var body = untyped Bt.Ammo.btRigidBody.prototype.upcast(co);
  142. var hit = rayCallback.get_m_hitPointWorld();
  143. v1.set(hit.x(), hit.y(), hit.z());
  144. var norm = rayCallback.get_m_hitNormalWorld();
  145. v2.set(norm.x(), norm.y(), norm.z());
  146. pb = bodyMap.get(untyped body.userIndex);
  147. hitInfo = {
  148. body: pb,
  149. pos: v1,
  150. normal: v2
  151. };
  152. }
  153. Bt.Ammo.destroy(rayCallback);
  154. return hitInfo;
  155. }
  156. }
  157. typedef THit = {
  158. public var body: PhysicsBody;
  159. public var pos: Vec4;
  160. public var normal: Vec4;
  161. }
  162. typedef TPair = {
  163. public var a: Int;
  164. public var b: Int;
  165. public var posA: Vec4;
  166. public var posB: Vec4;
  167. public var normOnB: Vec4;
  168. public var impulse: Float;
  169. public var distance: Float;
  170. }
  171. #end