Merge pull request #8 from jesstelford/children
Support dragging child entities
This commit is contained in:
commit
e0e8c23bea
4 changed files with 89 additions and 15 deletions
|
@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
|||
|
||||
## [Unreleased][]
|
||||
|
||||
### Added
|
||||
|
||||
- Support click and drag for children of entities and the camera
|
||||
|
||||
## [1.3.3][] - 2016-11-05
|
||||
|
||||
### Fixed
|
||||
|
|
25
examples/children/index.html
Normal file
25
examples/children/index.html
Normal file
|
@ -0,0 +1,25 @@
|
|||
<html>
|
||||
<head>
|
||||
<title>A-Frame Click & Drag Component - Basic</title>
|
||||
<script src="../build.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a-scene>
|
||||
|
||||
<a-cylinder click-drag position="1 0.75 1" radius="0.5" height="1.5" color="#FFC65D"></a-cylinder>
|
||||
<a-plane rotation="-90 0 0" width="4" height="4" color="#7BC8A4"></a-plane>
|
||||
|
||||
<a-sky color="#ECECEC"></a-sky>
|
||||
|
||||
<a-entity position="0 0 3.8">
|
||||
<a-camera look-controls-enabled="false" keyboard-controls="mode: fps">
|
||||
|
||||
<a-sphere click-drag position="0 0.5 -4" radius="1.25" color="#EF2D5E">
|
||||
<a-box click-drag position="-1 0.5 1" rotation="0 45 0" width="1" height="1" depth="1" color="#4CC3D9"></a-box>
|
||||
</a-sphere>
|
||||
|
||||
</a-camera>
|
||||
</a-entity>
|
||||
</a-scene>
|
||||
</body>
|
||||
</html>
|
|
@ -35,6 +35,12 @@
|
|||
|
||||
<hr />
|
||||
|
||||
<a class="demo-link" href="children/">Children Demo</a>
|
||||
<p>Child entities can be dragged around too!</p>
|
||||
<p>In this example, the cube is a child of the sphere, which is a child of the camera.</p>
|
||||
|
||||
<hr />
|
||||
|
||||
<a class="demo-link" href="physics/">Physics Demo</a>
|
||||
<p>Calculating the velocity at the time of drag end.</p>
|
||||
<p>Combined with a physics library (for example; <a href="https://github.com/donmccurdy/aframe-extras/tree/master/src/physics">aframe-extras physics</a>), we get some very nice interactions.</p>
|
||||
|
|
63
src/index.js
63
src/index.js
|
@ -19,19 +19,31 @@ function forceWorldUpdate(threeElement) {
|
|||
element.updateMatrixWorld(true);
|
||||
}
|
||||
|
||||
function forEachParent(element, lambda) {
|
||||
while (element.attachedToParent) {
|
||||
element = element.parentElement;
|
||||
lambda(element);
|
||||
}
|
||||
}
|
||||
|
||||
function someParent(element, lambda) {
|
||||
while (element.attachedToParent) {
|
||||
element = element.parentElement;
|
||||
if (lambda(element)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cameraPositionToVec3(camera, vec3) {
|
||||
|
||||
let element = camera;
|
||||
|
||||
vec3.set(
|
||||
element.components.position.data.x,
|
||||
element.components.position.data.y,
|
||||
element.components.position.data.z
|
||||
camera.components.position.data.x,
|
||||
camera.components.position.data.y,
|
||||
camera.components.position.data.z
|
||||
);
|
||||
|
||||
while (element.attachedToParent) {
|
||||
|
||||
element = element.parentElement;
|
||||
forEachParent(camera, element => {
|
||||
|
||||
if (element.components && element.components.position) {
|
||||
vec3.set(
|
||||
|
@ -41,7 +53,7 @@ function cameraPositionToVec3(camera, vec3) {
|
|||
);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
|
@ -310,6 +322,10 @@ function dragItem(THREE, element, offset, camera, depth, mouseInfo, lockToLocalR
|
|||
z: THREE.Math.radToDeg(rotationEuler.z),
|
||||
};
|
||||
|
||||
const activeCamera = element.sceneEl.systems.camera.activeCameraEl;
|
||||
|
||||
const isChildOfActiveCamera = someParent(element, parent => parent === activeCamera);
|
||||
|
||||
function onMouseMove({clientX, clientY}) {
|
||||
|
||||
lastMouseInfo = {clientX, clientY};
|
||||
|
@ -330,26 +346,49 @@ function dragItem(THREE, element, offset, camera, depth, mouseInfo, lockToLocalR
|
|||
|
||||
if (lockToLocalRotation) {
|
||||
|
||||
let rotationDiff;
|
||||
|
||||
// Start by rotating backwards from the initial camera rotation
|
||||
const rotationDiff = rotationQuaternion.copy(startCameraRotationInverse)
|
||||
// Then add the current camera rotation
|
||||
.multiply(threeCamera.getWorldQuaternion());
|
||||
rotationDiff = rotationQuaternion.copy(startCameraRotationInverse);
|
||||
|
||||
// rotate the offset
|
||||
offsetVector.set(offset.x, offset.y, offset.z);
|
||||
|
||||
// Then add the current camera rotation
|
||||
rotationDiff = rotationQuaternion.multiply(threeCamera.getWorldQuaternion());
|
||||
|
||||
offsetVector.applyQuaternion(rotationDiff);
|
||||
|
||||
if (!isChildOfActiveCamera) {
|
||||
// And correctly offset rotation
|
||||
rotationDiff.multiply(startElementRotation);
|
||||
|
||||
rotationEuler.setFromQuaternion(rotationDiff, elementRotationOrder);
|
||||
}
|
||||
|
||||
nextRotation.x = THREE.Math.radToDeg(rotationEuler.x);
|
||||
nextRotation.y = THREE.Math.radToDeg(rotationEuler.y);
|
||||
nextRotation.z = THREE.Math.radToDeg(rotationEuler.z);
|
||||
|
||||
}
|
||||
|
||||
const nextPosition = {x: x - offsetVector.x, y: y - offsetVector.y, z: z - offsetVector.z};
|
||||
|
||||
// When the element has parents, we need to convert its new world position
|
||||
// into new local position of its parent element
|
||||
if (element.parentEl !== element.sceneEl) {
|
||||
|
||||
// The new world position
|
||||
offsetVector.set(nextPosition.x, nextPosition.y, nextPosition.z);
|
||||
|
||||
// Converted
|
||||
element.parentEl.object3D.worldToLocal(offsetVector);
|
||||
|
||||
nextPosition.x = offsetVector.x;
|
||||
nextPosition.y = offsetVector.y;
|
||||
nextPosition.z = offsetVector.z;
|
||||
}
|
||||
|
||||
element.emit(DRAG_MOVE_EVENT, {nextPosition, nextRotation, clientX, clientY});
|
||||
|
||||
element.setAttribute('position', nextPosition);
|
||||
|
|
Loading…
Reference in a new issue