sphere-collider.js 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  1. (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
  2. AFRAME.registerComponent('sphere-collider', require('./src/misc/sphere-collider'));
  3. },{"./src/misc/sphere-collider":2}],2:[function(require,module,exports){
  4. /**
  5. * Based on aframe/examples/showcase/tracked-controls.
  6. *
  7. * Implement bounding sphere collision detection for entities with a mesh.
  8. * Sets the specified state on the intersected entities.
  9. *
  10. * @property {string} objects - Selector of the entities to test for collision.
  11. * @property {string} state - State to set on collided entities.
  12. *
  13. */
  14. module.exports = {
  15. schema: {
  16. objects: {default: ''},
  17. state: {default: 'collided'},
  18. radius: {default: 0.05},
  19. watch: {default: true}
  20. },
  21. init: function () {
  22. /** @type {MutationObserver} */
  23. this.observer = null;
  24. /** @type {Array<Element>} Elements to watch for collisions. */
  25. this.els = [];
  26. /** @type {Array<Element>} Elements currently in collision state. */
  27. this.collisions = [];
  28. this.handleHit = this.handleHit.bind(this);
  29. this.handleHitEnd = this.handleHitEnd.bind(this);
  30. },
  31. remove: function () {
  32. this.pause();
  33. },
  34. play: function () {
  35. var sceneEl = this.el.sceneEl;
  36. if (this.data.watch) {
  37. this.observer = new MutationObserver(this.update.bind(this, null));
  38. this.observer.observe(sceneEl, {childList: true, subtree: true});
  39. }
  40. },
  41. pause: function () {
  42. if (this.observer) {
  43. this.observer.disconnect();
  44. this.observer = null;
  45. }
  46. },
  47. /**
  48. * Update list of entities to test for collision.
  49. */
  50. update: function () {
  51. var data = this.data;
  52. var objectEls;
  53. // Push entities into list of els to intersect.
  54. if (data.objects) {
  55. objectEls = this.el.sceneEl.querySelectorAll(data.objects);
  56. } else {
  57. // If objects not defined, intersect with everything.
  58. objectEls = this.el.sceneEl.children;
  59. }
  60. // Convert from NodeList to Array
  61. this.els = Array.prototype.slice.call(objectEls);
  62. },
  63. tick: (function () {
  64. var position = new THREE.Vector3(),
  65. meshPosition = new THREE.Vector3(),
  66. meshScale = new THREE.Vector3(),
  67. colliderScale = new THREE.Vector3(),
  68. distanceMap = new Map();
  69. return function () {
  70. var el = this.el,
  71. data = this.data,
  72. mesh = el.getObject3D('mesh'),
  73. colliderRadius,
  74. collisions = [];
  75. if (!mesh) { return; }
  76. distanceMap.clear();
  77. position.copy(el.object3D.getWorldPosition());
  78. el.object3D.getWorldScale(colliderScale);
  79. colliderRadius = data.radius * scaleFactor(colliderScale);
  80. // Update collision list.
  81. this.els.forEach(intersect);
  82. // Emit events and add collision states, in order of distance.
  83. collisions
  84. .sort(function (a, b) {
  85. return distanceMap.get(a) > distanceMap.get(b) ? 1 : -1;
  86. })
  87. .forEach(this.handleHit);
  88. // Remove collision state from current element.
  89. if (collisions.length === 0) { el.emit('hit', {el: null}); }
  90. // Remove collision state from other elements.
  91. this.collisions.filter(function (el) {
  92. return !distanceMap.has(el);
  93. }).forEach(this.handleHitEnd);
  94. // Store new collisions
  95. this.collisions = collisions;
  96. // Bounding sphere collision detection
  97. function intersect (el) {
  98. var radius, mesh, distance, box, extent, size;
  99. if (!el.isEntity) { return; }
  100. mesh = el.getObject3D('mesh');
  101. if (!mesh) { return; }
  102. box = new THREE.Box3().setFromObject(mesh);
  103. size = box.getSize();
  104. extent = Math.max(size.x, size.y, size.z) / 2;
  105. radius = Math.sqrt(2 * extent * extent);
  106. box.getCenter(meshPosition);
  107. if (!radius) { return; }
  108. distance = position.distanceTo(meshPosition);
  109. if (distance < radius + colliderRadius) {
  110. collisions.push(el);
  111. distanceMap.set(el, distance);
  112. }
  113. }
  114. // use max of scale factors to maintain bounding sphere collision
  115. function scaleFactor (scaleVec) {
  116. return Math.max.apply(null, scaleVec.toArray());
  117. }
  118. };
  119. })(),
  120. handleHit: function (targetEl) {
  121. targetEl.emit('hit');
  122. targetEl.addState(this.data.state);
  123. this.el.emit('hit', {el: targetEl});
  124. },
  125. handleHitEnd: function (targetEl) {
  126. targetEl.emit('hitend');
  127. targetEl.removeState(this.data.state);
  128. this.el.emit('hitend', {el: targetEl});
  129. }
  130. };
  131. },{}]},{},[1]);