parent
103e404dd9
commit
c96d57ccb2
File diff suppressed because one or more lines are too long
@ -0,0 +1,105 @@ |
||||
/* global AFRAME, THREE */ |
||||
|
||||
/** |
||||
* Implement AABB collision detection for entities with a mesh. |
||||
* (https://en.wikipedia.org/wiki/Minimum_bounding_box#Axis-aligned_minimum_bounding_box)
|
||||
* It sets the specified state on the intersected entities. |
||||
* |
||||
* @property {string} objects - Selector of the entities to test for collision. |
||||
* @property {string} state - State to set on collided entities. |
||||
* |
||||
*/ |
||||
AFRAME.registerComponent('aabb-collider', { |
||||
schema: { |
||||
objects: {default: ''}, |
||||
state: {default: 'collided'} |
||||
}, |
||||
|
||||
init: function () { |
||||
this.els = []; |
||||
this.collisions = []; |
||||
this.elMax = new THREE.Vector3(); |
||||
this.elMin = new THREE.Vector3(); |
||||
}, |
||||
|
||||
/** |
||||
* Update list of entities to test for collision. |
||||
*/ |
||||
update: function () { |
||||
var data = this.data; |
||||
var objectEls; |
||||
|
||||
// Push entities into list of els to intersect.
|
||||
if (data.objects) { |
||||
objectEls = this.el.sceneEl.querySelectorAll(data.objects); |
||||
} else { |
||||
// If objects not defined, intersect with everything.
|
||||
objectEls = this.el.sceneEl.children; |
||||
} |
||||
// Convert from NodeList to Array
|
||||
this.els = Array.prototype.slice.call(objectEls); |
||||
}, |
||||
|
||||
tick: (function () { |
||||
var boundingBox = new THREE.Box3(); |
||||
return function () { |
||||
var collisions = []; |
||||
var el = this.el; |
||||
var mesh = el.getObject3D('mesh'); |
||||
var self = this; |
||||
// No mesh, no collisions
|
||||
if (!mesh) { return; } |
||||
// Update the bounding box to account for rotations and
|
||||
// position changes.
|
||||
updateBoundingBox(); |
||||
// Update collisions.
|
||||
this.els.forEach(intersect); |
||||
// Emit events.
|
||||
collisions.forEach(handleHit); |
||||
// No collisions.
|
||||
if (collisions.length === 0) { self.el.emit('hit', {el: null}); } |
||||
// Updated the state of the elements that are not intersected anymore.
|
||||
this.collisions.filter(function (el) { |
||||
return collisions.indexOf(el) === -1; |
||||
}).forEach(function removeState (el) { |
||||
el.removeState(self.data.state); |
||||
el.emit('hitend'); |
||||
}); |
||||
// Store new collisions
|
||||
this.collisions = collisions; |
||||
|
||||
// AABB collision detection
|
||||
function intersect (el) { |
||||
var intersected; |
||||
var mesh = el.getObject3D('mesh'); |
||||
var elMin; |
||||
var elMax; |
||||
if (!mesh) { return; } |
||||
boundingBox.setFromObject(mesh); |
||||
elMin = boundingBox.min; |
||||
elMax = boundingBox.max; |
||||
// Bounding boxes are always aligned with the world coordinate system.
|
||||
// The collision test checks for the conditions where cubes intersect.
|
||||
// It's an extension to 3 dimensions of this approach (with the condition negated)
|
||||
// https://www.youtube.com/watch?v=ghqD3e37R7E
|
||||
intersected = (self.elMin.x <= elMax.x && self.elMax.x >= elMin.x) && |
||||
(self.elMin.y <= elMax.y && self.elMax.y >= elMin.y) && |
||||
(self.elMin.z <= elMax.z && self.elMax.z >= elMin.z); |
||||
if (!intersected) { return; } |
||||
collisions.push(el); |
||||
} |
||||
|
||||
function handleHit (hitEl) { |
||||
hitEl.emit('hit'); |
||||
hitEl.addState(self.data.state); |
||||
self.el.emit('hit', {el: hitEl}); |
||||
} |
||||
|
||||
function updateBoundingBox () { |
||||
boundingBox.setFromObject(mesh); |
||||
self.elMin.copy(boundingBox.min); |
||||
self.elMax.copy(boundingBox.max); |
||||
} |
||||
}; |
||||
})() |
||||
}); |
@ -1,19 +0,0 @@ |
||||
AFRAME.registerComponent('drag-controls', { |
||||
schema: {objects: {type: 'string', default: 'a-entity'}}, |
||||
|
||||
init: function () { |
||||
var objects = []; |
||||
var el = this.el; |
||||
var els; |
||||
var dragControls; |
||||
els = el.sceneEl.querySelectorAll(this.data.objects); |
||||
for (var i = 0; i < els.length; i++) { |
||||
console.log(i); |
||||
objects.push(els[i].object3D); |
||||
} |
||||
|
||||
el.sceneEl.addEventListener('renderstart', function () { |
||||
dragControls = new THREE.DragControls(objects, el.sceneEl.camera, el.sceneEl.renderer.domElement); |
||||
}); |
||||
} |
||||
}); |
@ -1,282 +0,0 @@ |
||||
/* |
||||
* @author zz85 / https://github.com/zz85
|
||||
* @author mrdoob / http://mrdoob.com
|
||||
* Running this will allow you to drag three.js objects around the screen. |
||||
*/ |
||||
|
||||
THREE.DragControls = function ( _objects, _camera, _domElement ) { |
||||
|
||||
if ( _objects instanceof THREE.Camera ) { |
||||
|
||||
console.warn( 'THREE.DragControls: Constructor now expects ( objects, camera, domElement )' ); |
||||
var temp = _objects; _objects = _camera; _camera = temp; |
||||
|
||||
} |
||||
|
||||
var _plane = new THREE.Plane(); |
||||
var _raycaster = new THREE.Raycaster(); |
||||
|
||||
var _mouse = new THREE.Vector2(); |
||||
var _offset = new THREE.Vector3(); |
||||
var _intersection = new THREE.Vector3(); |
||||
|
||||
var _selected = null, _hovered = null; |
||||
|
||||
//
|
||||
|
||||
var scope = this; |
||||
|
||||
function activate() { |
||||
|
||||
_domElement.addEventListener( 'mousemove', onDocumentMouseMove, false ); |
||||
_domElement.addEventListener( 'mousedown', onDocumentMouseDown, false ); |
||||
_domElement.addEventListener( 'mouseup', onDocumentMouseCancel, false ); |
||||
_domElement.addEventListener( 'mouseleave', onDocumentMouseCancel, false ); |
||||
_domElement.addEventListener( 'touchmove', onDocumentTouchMove, false ); |
||||
_domElement.addEventListener( 'touchstart', onDocumentTouchStart, false ); |
||||
_domElement.addEventListener( 'touchend', onDocumentTouchEnd, false ); |
||||
|
||||
} |
||||
|
||||
function deactivate() { |
||||
|
||||
_domElement.removeEventListener( 'mousemove', onDocumentMouseMove, false ); |
||||
_domElement.removeEventListener( 'mousedown', onDocumentMouseDown, false ); |
||||
_domElement.removeEventListener( 'mouseup', onDocumentMouseCancel, false ); |
||||
_domElement.removeEventListener( 'mouseleave', onDocumentMouseCancel, false ); |
||||
_domElement.removeEventListener( 'touchmove', onDocumentTouchMove, false ); |
||||
_domElement.removeEventListener( 'touchstart', onDocumentTouchStart, false ); |
||||
_domElement.removeEventListener( 'touchend', onDocumentTouchEnd, false ); |
||||
|
||||
} |
||||
|
||||
function dispose() { |
||||
|
||||
deactivate(); |
||||
|
||||
} |
||||
|
||||
function onDocumentMouseMove( event ) { |
||||
|
||||
event.preventDefault(); |
||||
|
||||
var rect = _domElement.getBoundingClientRect(); |
||||
|
||||
_mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1; |
||||
_mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1; |
||||
|
||||
_raycaster.setFromCamera( _mouse, _camera ); |
||||
|
||||
if ( _selected && scope.enabled ) { |
||||
|
||||
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { |
||||
|
||||
_selected.position.copy( _intersection.sub( _offset ) ); |
||||
|
||||
} |
||||
|
||||
scope.dispatchEvent( { type: 'drag', object: _selected } ); |
||||
|
||||
return; |
||||
|
||||
} |
||||
|
||||
_raycaster.setFromCamera( _mouse, _camera ); |
||||
|
||||
var intersects = _raycaster.intersectObjects( _objects, true ); |
||||
|
||||
if ( intersects.length > 0 ) { |
||||
|
||||
var object = intersects[ 0 ].object.parent; |
||||
|
||||
_plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), object.position ); |
||||
|
||||
if ( _hovered !== object ) { |
||||
|
||||
scope.dispatchEvent( { type: 'hoveron', object: object } ); |
||||
|
||||
_domElement.style.cursor = 'pointer'; |
||||
_hovered = object; |
||||
|
||||
} |
||||
|
||||
} else { |
||||
|
||||
if ( _hovered !== null ) { |
||||
|
||||
scope.dispatchEvent( { type: 'hoveroff', object: _hovered } ); |
||||
|
||||
_domElement.style.cursor = 'auto'; |
||||
_hovered = null; |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
function onDocumentMouseDown( event ) { |
||||
|
||||
event.preventDefault(); |
||||
|
||||
_raycaster.setFromCamera( _mouse, _camera ); |
||||
|
||||
var intersects = _raycaster.intersectObjects( _objects, true ); |
||||
|
||||
if ( intersects.length > 0 ) { |
||||
|
||||
_selected = intersects[ 0 ].object.parent; |
||||
|
||||
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { |
||||
|
||||
_offset.copy( _intersection ).sub( _selected.position ); |
||||
|
||||
} |
||||
|
||||
_domElement.style.cursor = 'move'; |
||||
|
||||
scope.dispatchEvent( { type: 'dragstart', object: _selected } ); |
||||
|
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
function onDocumentMouseCancel( event ) { |
||||
|
||||
event.preventDefault(); |
||||
|
||||
if ( _selected ) { |
||||
|
||||
scope.dispatchEvent( { type: 'dragend', object: _selected } ); |
||||
|
||||
_selected = null; |
||||
|
||||
} |
||||
|
||||
_domElement.style.cursor = 'auto'; |
||||
|
||||
} |
||||
|
||||
function onDocumentTouchMove( event ) { |
||||
|
||||
event.preventDefault(); |
||||
event = event.changedTouches[ 0 ]; |
||||
|
||||
var rect = _domElement.getBoundingClientRect(); |
||||
|
||||
_mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1; |
||||
_mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1; |
||||
|
||||
_raycaster.setFromCamera( _mouse, _camera ); |
||||
|
||||
if ( _selected && scope.enabled ) { |
||||
|
||||
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { |
||||
|
||||
_selected.position.copy( _intersection.sub( _offset ) ); |
||||
|
||||
} |
||||
|
||||
scope.dispatchEvent( { type: 'drag', object: _selected } ); |
||||
|
||||
return; |
||||
|
||||
} |
||||
|
||||
} |
||||
|
||||
function onDocumentTouchStart( event ) { |
||||
|
||||
event.preventDefault(); |
||||
event = event.changedTouches[ 0 ]; |
||||
|
||||
var rect = _domElement.getBoundingClientRect(); |
||||
|
||||
_mouse.x = ( ( event.clientX - rect.left ) / rect.width ) * 2 - 1; |
||||
_mouse.y = - ( ( event.clientY - rect.top ) / rect.height ) * 2 + 1; |
||||
|
||||
_raycaster.setFromCamera( _mouse, _camera ); |
||||
|
||||
var intersects = _raycaster.intersectObjects( _objects, true ); |
||||
|
||||
if ( intersects.length > 0 ) { |
||||
|
||||
_selected = intersects[ 0 ].object.parent; |
||||
|
||||
_plane.setFromNormalAndCoplanarPoint( _camera.getWorldDirection( _plane.normal ), _selected.position ); |
||||
|
||||
if ( _raycaster.ray.intersectPlane( _plane, _intersection ) ) { |
||||
|
||||
_offset.copy( _intersection ).sub( _selected.position ); |
||||
|
||||
} |
||||
|
||||
_domElement.style.cursor = 'move'; |
||||
|
||||
scope.dispatchEvent( { type: 'dragstart', object: _selected } ); |
||||
|
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
function onDocumentTouchEnd( event ) { |
||||
|
||||
event.preventDefault(); |
||||
|
||||
if ( _selected ) { |
||||
|
||||
scope.dispatchEvent( { type: 'dragend', object: _selected } ); |
||||
|
||||
_selected = null; |
||||
|
||||
} |
||||
|
||||
_domElement.style.cursor = 'auto'; |
||||
|
||||
} |
||||
|
||||
activate(); |
||||
|
||||
// API
|
||||
|
||||
this.enabled = true; |
||||
|
||||
this.activate = activate; |
||||
this.deactivate = deactivate; |
||||
this.dispose = dispose; |
||||
|
||||
// Backward compatibility
|
||||
|
||||
this.setObjects = function () { |
||||
|
||||
console.error( 'THREE.DragControls: setObjects() has been removed.' ); |
||||
|
||||
}; |
||||
|
||||
this.on = function ( type, listener ) { |
||||
|
||||
console.warn( 'THREE.DragControls: on() has been deprecated. Use addEventListener() instead.' ); |
||||
scope.addEventListener( type, listener ); |
||||
|
||||
}; |
||||
|
||||
this.off = function ( type, listener ) { |
||||
|
||||
console.warn( 'THREE.DragControls: off() has been deprecated. Use removeEventListener() instead.' ); |
||||
scope.removeEventListener( type, listener ); |
||||
|
||||
}; |
||||
|
||||
this.notify = function ( type ) { |
||||
|
||||
console.error( 'THREE.DragControls: notify() has been deprecated. Use dispatchEvent() instead.' ); |
||||
scope.dispatchEvent( { type: type } ); |
||||
|
||||
}; |
||||
|
||||
}; |
||||
|
||||
THREE.DragControls.prototype = Object.create( THREE.EventDispatcher.prototype ); |
||||
THREE.DragControls.prototype.constructor = THREE.DragControls; |
Loading…
Reference in new issue