diff --git a/src/game-lib-component-camera.js b/src/game-lib-component-camera.js new file mode 100644 index 0000000..24ab32d --- /dev/null +++ b/src/game-lib-component-camera.js @@ -0,0 +1,28 @@ +/** + * + * @param componentId + * @param threeCamera + * @constructor + */ +GameLib.D3.ComponentCamera = function( + componentId, + threeCamera +) { + this.componentId = componentId || GameLib.D3.Tools.RandomId(); + this.parentEntity = null; + + // Todo: this should be executed somewhere in game-lib-z, so that we don't execute it on every construction of an object. + GameLib.D3.Utils.Extend(GameLib.D3.ComponentCamera, GameLib.D3.ComponentInterface); + + // Component fields + this.threeCamera = threeCamera; +}; + +///////////////////////// Methods to override ////////////////////////// +GameLib.D3.ComponentCamera.prototype.onLateUpdate = function( + deltaTime, + parentEntity +) { + this.threeCamera.quaternion.copy(parentEntity.quaternion); + this.threeCamera.position.copy(parentEntity.position); +}; \ No newline at end of file diff --git a/src/game-lib-component-fly-controls.js b/src/game-lib-component-fly-controls.js new file mode 100644 index 0000000..7c919c0 --- /dev/null +++ b/src/game-lib-component-fly-controls.js @@ -0,0 +1,201 @@ +GameLib.D3.ComponentFlyControls = function( + componentId +) { + this.componentId = componentId || GameLib.D3.Tools.RandomId(); + this.parentEntity = null; + + // Todo: this should be executed somewhere in game-lib-z, so that we don't execute it on every construction of an object. + GameLib.D3.Utils.Extend(GameLib.D3.ComponentFlyControls, GameLib.D3.ComponentInterface); + + // Component fields + this.pitch = 0; + this.yaw = 0; + this.canRotate = false; + this.moveSpeed = 22.2; + this.moveForward = false; + this.moveBackward = false; + this.moveLeft = false; + this.moveRight = false; + this.moveUp = false; + this.moveDown = false; + +}; + +///////////////////////// Methods to override ////////////////////////// +GameLib.D3.ComponentFlyControls.prototype.onUpdate = function( + deltaTime, + parentEntity +) { + // Apply rotation + var rotation = new THREE.Euler( + this.pitch, + this.yaw, + 0, + "YXZ" + ); + + var quat = new THREE.Quaternion().setFromEuler( + rotation + ); + + parentEntity.quaternion.x = quat.x; + parentEntity.quaternion.y = quat.y; + parentEntity.quaternion.z = quat.z; + parentEntity.quaternion.w = quat.w; + + // Apply translation + var direction = new THREE.Vector3(0, 0, -1); + direction = direction.applyEuler(rotation).normalize(); + + if(this.moveForward) { + + parentEntity.position.x += direction.x * (deltaTime * this.moveSpeed); + parentEntity.position.y += direction.y * (deltaTime * this.moveSpeed); + parentEntity.position.z += direction.z * (deltaTime * this.moveSpeed); + + } else if(this.moveBackward) { + + parentEntity.position.x -= direction.x * (deltaTime * this.moveSpeed); + parentEntity.position.y -= direction.y * (deltaTime * this.moveSpeed); + parentEntity.position.z -= direction.z * (deltaTime * this.moveSpeed); + + } + + if(this.moveLeft) { + + var right = direction.cross(new THREE.Vector3(0, 1, 0)); + parentEntity.position.x -= right.x * (deltaTime * this.moveSpeed); + parentEntity.position.y -= right.y * (deltaTime * this.moveSpeed); + parentEntity.position.z -= right.z * (deltaTime * this.moveSpeed); + + } else if(this.moveRight) { + + var right = direction.cross(new THREE.Vector3(0, 1, 0)); + parentEntity.position.x += right.x * (deltaTime * this.moveSpeed); + parentEntity.position.y += right.y * (deltaTime * this.moveSpeed); + parentEntity.position.z += right.z * (deltaTime * this.moveSpeed); + + } + + // Absolute Y-Axis + if(this.moveUp) { + + parentEntity.position.y += (deltaTime * this.moveSpeed); + + } else if(this.moveDown) { + + parentEntity.position.y -= (deltaTime * this.moveSpeed); + + } +}; + +GameLib.D3.ComponentFlyControls.prototype.onSetParentEntity = function( + parentScene, + parentEntity +) { + var component = this; + + // Lock cursor + var havePointerLock = 'pointerLockElement' in document || 'mozPointerLockElement' in document || 'webkitPointerLockElement' in document; + var element = document.body; + + document.addEventListener('click', function(event) { + if(havePointerLock) { + if(event.button == 0) { + component.canRotate = true; + element.requestPointerLock(); + } else if(event.button == 2) { + component.canRotate = false; + document.exitPointerLock(); + } + } + }); + + if(havePointerLock) { + element.requestPointerLock = element.requestPointerLock || element.mozRequestPointerLock || element.webkitRequestPointerLock; + document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock || document.webkitExitPointerLock; + } + + + // Mouse move + document.addEventListener('mousemove', function (event) { + if(component.canRotate) { + var movementX = event.movementX || event.mozMovementX || event.webkitMovementX || 0; + var movementY = event.movementY || event.mozMovementY || event.webkitMovementY || 0; + + component.yaw -= movementX * 0.002; + component.pitch -= movementY * 0.002; + } + + // Save mouseCoords + sys.mouseCoords.set( + (event.clientX / window.innerWidth) * 2 - 1, + -(event.clientY / window.innerHeight) * 2 + 1 + ); + + }, false); + + + // Hook up keyboard controls + document.addEventListener('keydown', function (event) { + + switch (event.keyCode) { + case 87: // w + component.moveForward = true; + break; + + case 65: // a + component.moveLeft = true; + break; + + case 83: // s + component.moveBackward = true; + break; + + case 68: // d + component.moveRight = true; + break; + + case 32: // space + component.moveUp = true; + break; + + case 16: + component.moveDown = true; + break; + } + }, false); + + document.addEventListener('keyup', function (event) { + switch (event.keyCode) { + case 38: // up + case 87: // w + component.moveForward = false; + break; + + case 37: // left + case 65: // a + component.moveLeft = false; + break; + + case 40: // down + case 83: // s + component.moveBackward = false; + break; + + case 39: // right + case 68: // d + component.moveRight = false; + break; + + case 32: // space + component.moveUp = false; + break; + + case 16: + component.moveDown = false; + break; + } + }, false); + +}; \ No newline at end of file diff --git a/src/game-lib-component-follow.js b/src/game-lib-component-follow.js new file mode 100644 index 0000000..38a40a6 --- /dev/null +++ b/src/game-lib-component-follow.js @@ -0,0 +1,99 @@ +/** + * + * @param componentId + * @param targetEntity GameLib.D3.Entity + * @param targetOffset GameLib.D3.Vector3 + * @param minDistance + * @param moveSpeed + * @constructor + */ +GameLib.D3.ComponentFollow = function( + componentId, + targetEntity, + targetOffset, + minDistance, + moveSpeed +) { + this.componentId = componentId || GameLib.D3.Tools.RandomId(); + this.parentEntity = null; + + // Todo: this should be executed somewhere in game-lib-z, so that we don't execute it on every construction of an object. + GameLib.D3.Utils.Extend(GameLib.D3.ComponentFollow, GameLib.D3.ComponentInterface); + + // + this.targetEntity = targetEntity; + this.moveSpeed = moveSpeed || 12.5; + + + if(GameLib.D3.Utils.UndefinedOrNull(targetOffset)) { + targetOffset = new GameLib.D3.Vector3(0, 0, 0); + } + + this.targetOffset = targetOffset; + this.minDistance = minDistance || 0; +}; + +if(typeof THREE != "undefined") { + ComponentFollow_Target_Vec3 = new THREE.Vector3(); + ComponentFollow_TargetToParent_Vec3 = new THREE.Vector3(); + ComponentFollow_rotatedTargetOffset_Vec3 = new THREE.Vector3(); + ComponentFollow_tempQuaternion = new THREE.Quaternion(); +} + +///////////////////////// Methods to override ////////////////////////// +GameLib.D3.ComponentFollow.prototype.onUpdate = function( + deltaTime, + parentEntity +) { + + if(this.targetEntity) { + + ComponentFollow_tempQuaternion.set( + this.targetEntity.quaternion.x, + this.targetEntity.quaternion.y, + this.targetEntity.quaternion.z, + this.targetEntity.quaternion.w + ); + + ComponentFollow_rotatedTargetOffset_Vec3.set( + this.targetOffset.x, + this.targetOffset.y, + this.targetOffset.z + ); + + ComponentFollow_rotatedTargetOffset_Vec3 = + ComponentFollow_rotatedTargetOffset_Vec3.applyQuaternion( + ComponentFollow_tempQuaternion + ); + + ComponentFollow_Target_Vec3.set( + this.targetEntity.position.x + ComponentFollow_rotatedTargetOffset_Vec3.x, + this.targetEntity.position.y + ComponentFollow_rotatedTargetOffset_Vec3.y, + this.targetEntity.position.z + ComponentFollow_rotatedTargetOffset_Vec3.z + ); + + ComponentFollow_TargetToParent_Vec3.set( + parentEntity.position.x - this.targetEntity.position.x, + parentEntity.position.y - this.targetEntity.position.y, + parentEntity.position.z - this.targetEntity.position.z + ); + + ComponentFollow_TargetToParent_Vec3.normalize(); + + ComponentFollow_TargetToParent_Vec3.set( + ComponentFollow_TargetToParent_Vec3.x * this.minDistance, + ComponentFollow_TargetToParent_Vec3.y * this.minDistance, + ComponentFollow_TargetToParent_Vec3.z * this.minDistance + ); + + ComponentFollow_Target_Vec3.set( + ComponentFollow_Target_Vec3.x + ComponentFollow_TargetToParent_Vec3.x, + ComponentFollow_Target_Vec3.y + ComponentFollow_TargetToParent_Vec3.y, + ComponentFollow_Target_Vec3.z + ComponentFollow_TargetToParent_Vec3.z + ); + + var t = deltaTime * this.moveSpeed; + //t = t * t * t * (t * (6.0 * t - 15.0) + 10.0); + parentEntity.position = parentEntity.position.lerp(ComponentFollow_Target_Vec3, t); + } +}; \ No newline at end of file diff --git a/src/game-lib-component-look-at.js b/src/game-lib-component-look-at.js new file mode 100644 index 0000000..f64dc7e --- /dev/null +++ b/src/game-lib-component-look-at.js @@ -0,0 +1,100 @@ +GameLib.D3.ComponentLookAt = function( + componentId, + targetEntity, + targetOffset, + rotationSpeed +) { + this.componentId = componentId || GameLib.D3.Tools.RandomId(); + this.parentEntity = null; + + // Todo: this should be executed somewhere in game-lib-z, so that we don't execute it on every construction of an object. + GameLib.D3.Utils.Extend(GameLib.D3.ComponentLookAt, GameLib.D3.ComponentInterface); + + // todo: USE TARGET OFFSET. + this.targetEntity = targetEntity; + + if(GameLib.D3.Utils.UndefinedOrNull(targetOffset)) { + targetOffset = new GameLib.D3.Vector3(0, 0, 0); + } + this.targetOffset = targetOffset; + + this.lastTargetQuaternion = new GameLib.D3.Vector4(0, 0, 0, 1); + this.rotationSpeed = rotationSpeed || 22.0; +}; + +if(typeof THREE != "undefined") { + ComponentLookAt_rotatedTargetOffset = new THREE.Vector3(); + ComponentLookAt_currentPos = new THREE.Vector3(); + ComponentLookAt_targetPos = new THREE.Vector3(); + ComponentLookAt_upVector = new THREE.Vector3(0, 1, 0); + ComponentLookAt_targetQuaternion = new THREE.Quaternion(0, 0, 0, 1); + ComponentLookAt_tmpQuaternion = new THREE.Quaternion(0, 0, 0, 1); + ComponentLookAt_newRotationQuaternion = new THREE.Quaternion(0, 0, 0, 1); + ComponentLookAt_lastRotationQuaternion = new THREE.Quaternion(0, 0, 0, 1); + ComponentLookAt_lookAtMatrix = new THREE.Matrix4(); +} + +///////////////////////// Methods to override ////////////////////////// +GameLib.D3.ComponentLookAt.prototype.onUpdate = function( + deltaTime, + parentEntity +) { + if(this.targetEntity) { + var target = this.targetEntity.position; + + ComponentLookAt_currentPos.set( + parentEntity.position.x, + parentEntity.position.y, + parentEntity.position.z + ); + + ComponentLookAt_lastRotationQuaternion.set( + this.lastTargetQuaternion.x, + this.lastTargetQuaternion.y, + this.lastTargetQuaternion.z, + this.lastTargetQuaternion.w + ); + + ComponentLookAt_rotatedTargetOffset.set( + this.targetOffset.x, + this.targetOffset.y, + this.targetOffset.z + ); + + ComponentLookAt_targetQuaternion.set( + this.targetEntity.quaternion.x, + this.targetEntity.quaternion.y, + this.targetEntity.quaternion.z, + this.targetEntity.quaternion.w + ); + + ComponentLookAt_rotatedTargetOffset = + ComponentLookAt_rotatedTargetOffset.applyQuaternion( + ComponentLookAt_targetQuaternion + ); + + ComponentLookAt_targetPos.set( + target.x + ComponentLookAt_rotatedTargetOffset.x, + target.y + ComponentLookAt_rotatedTargetOffset.y, + target.z + ComponentLookAt_rotatedTargetOffset.z + ); + + ComponentLookAt_lookAtMatrix.lookAt( + ComponentLookAt_currentPos, + ComponentLookAt_targetPos, + ComponentLookAt_upVector + ); + + ComponentLookAt_tmpQuaternion.setFromRotationMatrix(ComponentLookAt_lookAtMatrix); + + var t = deltaTime * this.rotationSpeed; + t = t * t * t * (t * (6.0 * t - 15.0) + 10.0); + + THREE.Quaternion.slerp(ComponentLookAt_lastRotationQuaternion, ComponentLookAt_tmpQuaternion, ComponentLookAt_newRotationQuaternion, t); + + this.parentEntity.quaternion.x = this.lastTargetQuaternion.x = ComponentLookAt_newRotationQuaternion.x; + this.parentEntity.quaternion.y = this.lastTargetQuaternion.y = ComponentLookAt_newRotationQuaternion.y; + this.parentEntity.quaternion.z = this.lastTargetQuaternion.z = ComponentLookAt_newRotationQuaternion.z; + this.parentEntity.quaternion.w = this.lastTargetQuaternion.w = ComponentLookAt_newRotationQuaternion.w; + } +}; \ No newline at end of file diff --git a/src/game-lib-component-mesh-permutation.js b/src/game-lib-component-mesh-permutation.js index a90c2af..c614578 100644 --- a/src/game-lib-component-mesh-permutation.js +++ b/src/game-lib-component-mesh-permutation.js @@ -1,18 +1,30 @@ GameLib.D3.ComponentMeshPermutation = function( componentId, positionOffset, - quaternionOffset + quaternionOffset, + scaleOffset ) { this.componentId = componentId || GameLib.D3.Tools.RandomId(); this.parentEntity = null; this.positionOffset = positionOffset || new GameLib.D3.Vector3(0, 0, 0); this.quaternionOffset = quaternionOffset || new GameLib.D3.Quaternion(0, 0, 0, 1); + this.scaleOffset = scaleOffset || new GameLib.D3.Vector3(0, 0, 0); // Todo: this should be executed somewhere in game-lib-z, so that we don't execute it on every construction of an object. GameLib.D3.Utils.Extend(GameLib.D3.ComponentMeshPermutation, GameLib.D3.ComponentInterface); }; +if(typeof THREE != "undefined") { + ComponentMeshPermutation_quaternion = new THREE.Quaternion(); + ComponentMeshPermutation_quaternionCopy = new THREE.Quaternion(); + ComponentMeshPermutation_position = new THREE.Vector3(); + ComponentMeshPermutation_scale = new THREE.Vector3(); + ComponentMeshPermutation_offsetQuaternion = new THREE.Quaternion(); + ComponentMeshPermutation_offsetPosition = new THREE.Vector3(); + ComponentMeshPermutation_offsetScale = new THREE.Vector3(); +} + ///////////////////////// Methods to override ////////////////////////// GameLib.D3.ComponentMeshPermutation.prototype.onLateUpdate = function( deltaTime, @@ -20,23 +32,23 @@ GameLib.D3.ComponentMeshPermutation.prototype.onLateUpdate = function( ) { if(parentEntity && parentEntity.mesh) { - var quaternion = new THREE.Quaternion(); - quaternion.copy(parentEntity.mesh.quaternion); + ComponentMeshPermutation_quaternion.copy(parentEntity.mesh.quaternion); + ComponentMeshPermutation_quaternionCopy.copy(ComponentMeshPermutation_quaternion); + ComponentMeshPermutation_position.copy(parentEntity.mesh.position); - var quaternionCopy = quaternion.clone(); + ComponentMeshPermutation_offsetQuaternion.copy(this.quaternionOffset); + ComponentMeshPermutation_quaternion = ComponentMeshPermutation_quaternion.multiply(ComponentMeshPermutation_offsetQuaternion).normalize(); - var position = new THREE.Vector3(); - position.copy(parentEntity.mesh.position); + ComponentMeshPermutation_offsetPosition.copy(this.positionOffset); + ComponentMeshPermutation_position = ComponentMeshPermutation_position.add(ComponentMeshPermutation_offsetPosition.applyQuaternion(ComponentMeshPermutation_quaternionCopy)); - var offsetQuaternion = new THREE.Quaternion(); - offsetQuaternion.copy(this.quaternionOffset); - quaternion = quaternion.multiply(offsetQuaternion).normalize(); + ComponentMeshPermutation_scale.copy(parentEntity.mesh.scale); - var offsetPosition = new THREE.Vector3(); - offsetPosition.copy(this.positionOffset); - position = position.add(offsetPosition.applyQuaternion(quaternionCopy)); + ComponentMeshPermutation_offsetScale.copy(this.scaleOffset); + ComponentMeshPermutation_scale = ComponentMeshPermutation_scale.add(ComponentMeshPermutation_offsetScale); - parentEntity.mesh.position.copy(position); - parentEntity.mesh.quaternion.copy(quaternion); + parentEntity.mesh.position.copy(ComponentMeshPermutation_position); + parentEntity.mesh.quaternion.copy(ComponentMeshPermutation_quaternion); + parentEntity.mesh.scale.copy(ComponentMeshPermutation_scale); } }; \ No newline at end of file diff --git a/src/game-lib-component-raycast-vehicle-controls.js b/src/game-lib-component-raycast-vehicle-controls.js index 411adb6..84d0317 100644 --- a/src/game-lib-component-raycast-vehicle-controls.js +++ b/src/game-lib-component-raycast-vehicle-controls.js @@ -1,24 +1,90 @@ GameLib.D3.ComponentRaycastVehicleControls = function( - componentId + componentId, + frontLWheelIndex, + frontRWheelIndex, + backLWheelIndex, + backRWheelIndex, + maxForce, + steering ) { this.componentId = componentId || GameLib.D3.Tools.RandomId(); this.parentEntity = null; + // maybe we pass this in the constructor + this.raycastVehicleComponent = null; + this.frontLWheelIndex = frontLWheelIndex || 0; + this.frontRWheelIndex = frontRWheelIndex || 1; + this.backLWheelIndex = backLWheelIndex || 2; + this.backRWheelIndex = backRWheelIndex || 3; + + this.maxForce = maxForce || 400; + this.steering = steering || 0.5; + // Todo: this should be executed somewhere in game-lib-z, so that we don't execute it on every construction of an object. GameLib.D3.Utils.Extend(GameLib.D3.ComponentRaycastVehicleControls, GameLib.D3.ComponentInterface); }; ///////////////////////// Methods to override ////////////////////////// -GameLib.D3.ComponentRaycastVehicleControls.prototype.onUpdate = function( - deltaTime, +GameLib.D3.ComponentRaycastVehicleControls.prototype.onSetParentEntity = function( + parentScene, parentEntity ) { - this.parentEntity.mesh.material.color = new THREE.Color(Math.random(), Math.random(), Math.random()); -}; -GameLib.D3.ComponentRaycastVehicleControls.prototype.onRegistered = function( - parentScene -) { - // Hook in document.eventlisteners - // save values & in the update method we just apply them on the vehicle itself + console.log("Set parent!"); + + this.raycastVehicleComponent = parentEntity.getComponent(GameLib.D3.RaycastVehicle); + if(!this.raycastVehicleComponent) { + console.warn("NO RAYCAST VEHICLE FOUND!"); + } else { + + var component = this; + document.addEventListener('keydown', function(event) { + + if (event.keyCode == 73) { // Forward [i] + + component.raycastVehicleComponent.instance.applyEngineForce(-component.maxForce, component.backLWheelIndex); + component.raycastVehicleComponent.instance.applyEngineForce(-component.maxForce, component.backRWheelIndex); + + } else if (event.keyCode == 74) { // Left [j] + + component.raycastVehicleComponent.instance.setSteeringValue(component.steering, component.frontLWheelIndex); + component.raycastVehicleComponent.instance.setSteeringValue(component.steering, component.frontRWheelIndex); + + } else if (event.keyCode == 75) { // Back [k] + + component.raycastVehicleComponent.instance.applyEngineForce(component.maxForce, component.backLWheelIndex); + component.raycastVehicleComponent.instance.applyEngineForce(component.maxForce, component.backRWheelIndex); + + } else if (event.keyCode == 76) { // Right [l] + component.raycastVehicleComponent.instance.setSteeringValue(-component.steering, component.frontLWheelIndex); + component.raycastVehicleComponent.instance.setSteeringValue(-component.steering, component.frontRWheelIndex); + } + + }, false); + + document.addEventListener('keyup', function(event) { + + if (event.keyCode == 73) { // Forward [i] + + component.raycastVehicleComponent.instance.applyEngineForce(0, component.backLWheelIndex); + component.raycastVehicleComponent.instance.applyEngineForce(0, component.backRWheelIndex); + + } else if (event.keyCode == 74) { // Left [j] + + component.raycastVehicleComponent.instance.setSteeringValue(0, component.frontLWheelIndex); + component.raycastVehicleComponent.instance.setSteeringValue(0, component.frontRWheelIndex); + + } else if (event.keyCode == 75) { // Back [k] + + component.raycastVehicleComponent.instance.applyEngineForce(0, component.backLWheelIndex); + component.raycastVehicleComponent.instance.applyEngineForce(0, component.backRWheelIndex); + + } else if (event.keyCode == 76) { // Right [l] + component.raycastVehicleComponent.instance.setSteeringValue(0, component.frontLWheelIndex); + component.raycastVehicleComponent.instance.setSteeringValue(0, component.frontRWheelIndex); + } + + }, false); + + } }; \ No newline at end of file diff --git a/src/game-lib-component-trigger-box-sphere.js b/src/game-lib-component-trigger-box-sphere.js new file mode 100644 index 0000000..8ac3d7f --- /dev/null +++ b/src/game-lib-component-trigger-box-sphere.js @@ -0,0 +1,89 @@ +// +// this component operates on it's parent entity's bounding box. +// so, you can't use this component with a null-mesh. +// +GameLib.D3.ComponentTriggerBoxSphere = function( + componentId, + entitiesToCheck, + callback +) { + this.componentId = componentId || GameLib.D3.Tools.RandomId(); + this.parentEntity = null; + + // Todo: this should be executed somewhere in game-lib-z, so that we don't execute it on every construction of an object. + GameLib.D3.Utils.Extend(GameLib.D3.ComponentTriggerBoxSphere, GameLib.D3.ComponentInterface); + + this.entitiesToCheck = entitiesToCheck || []; + this.callback = callback || null; +}; + +if(typeof THREE != "undefined") { + ComponentTriggerBoxSphere_BoxInverseTransform = new THREE.Matrix4(); + ComponentTriggerBoxSphere_TargetPosition_Vec3 = new THREE.Vector3(); + ComponentTriggerBoxSphere_TargetRadius = 0.0; +} + +///////////////////////// Methods to override ////////////////////////// +GameLib.D3.ComponentTriggerBoxSphere.prototype.onUpdate = function( + deltaTime, + parentEntity +) { + + if(parentEntity.mesh) { + // Calculate the current transform here, using the position, orientation and scale of the entity. + + if(!parentEntity.mesh.geometry.boundingBox) { + parentEntity.mesh.geometry.computeBoundingBox(); + } + + ComponentTriggerBoxSphere_BoxInverseTransform.getInverse(parentEntity.mesh.matrix); + + for(var e in this.entitiesToCheck) { + var entityToCheck = this.entitiesToCheck[e]; + + if(entityToCheck.mesh) { + + if (!entityToCheck.mesh.geometry.boundingSphere) { + entityToCheck.mesh.geometry.computeBoundingSphere(); + } + + var spherePosition = new THREE.Vector3( + entityToCheck.position.x, + entityToCheck.position.y, + entityToCheck.position.z + ); + + spherePosition.applyMatrix4(ComponentTriggerBoxSphere_BoxInverseTransform); + + var sphere = new THREE.Sphere( + spherePosition, + entityToCheck.mesh.geometry.boundingSphere.radius + ); + + if(this.callback && parentEntity.mesh.geometry.boundingBox.intersectsSphere(sphere)) { + this.callback(parentEntity, entityToCheck); + } + + } else { // no target mesh geometry. + + var spherePosition = new THREE.Vector3( + entityToCheck.position.x, + entityToCheck.position.y, + entityToCheck.position.z + ); + + spherePosition.applyMatrix4(ComponentTriggerBoxSphere_BoxInverseTransform); + + var sphere = new THREE.Sphere( + spherePosition, + 1 + ); + + if(this.callback && parentEntity.mesh.geometry.boundingBox.intersectsSphere(sphere)) { + this.callback(parentEntity, entityToCheck); + } + + } + } + } +}; \ No newline at end of file diff --git a/src/game-lib-component-trigger-sphere-sphere.js b/src/game-lib-component-trigger-sphere-sphere.js new file mode 100644 index 0000000..f6419db --- /dev/null +++ b/src/game-lib-component-trigger-sphere-sphere.js @@ -0,0 +1,71 @@ +// +// uses the entity position + mesh bounding sphere to check if intersections +// +GameLib.D3.ComponentTriggerSphereSphere = function( + componentId, + sphereRadius, + entitiesToCheck, + callback +) { + this.componentId = componentId || GameLib.D3.Tools.RandomId(); + this.parentEntity = null; + + // Todo: this should be executed somewhere in game-lib-z, so that we don't execute it on every construction of an object. + GameLib.D3.Utils.Extend(GameLib.D3.ComponentTriggerSphereSphere, GameLib.D3.ComponentInterface); + + this.entitiesToCheck = entitiesToCheck || []; + this.sphereRadius = sphereRadius || 1.0; + this.callback = callback || null; +}; + +if(typeof THREE != "undefined") { + ComponentTriggerSphereSphere_spherePosition_Vector3 = new THREE.Vector3(); + ComponentTriggerSphereSphere_targetBoundingSpherePosition_Vector3 = new THREE.Vector3(); + ComponentTriggerSphereSphere_targetBoundingSphereRadius = 0.0; + ComponentTriggerSphereSphere_sphereToSphere_Vector3 = new THREE.Vector3(); +} + +///////////////////////// Methods to override ////////////////////////// +GameLib.D3.ComponentTriggerSphereSphere.prototype.onUpdate = function( + deltaTime, + parentEntity +) { + + ComponentTriggerSphereSphere_spherePosition_Vector3.set( + parentEntity.position.x, + parentEntity.position.y, + parentEntity.position.z + ); + + for(var e in this.entitiesToCheck) { + var entityToCheck = this.entitiesToCheck[e]; + + ComponentTriggerSphereSphere_targetBoundingSpherePosition_Vector3.set( + entityToCheck.position.x, + entityToCheck.position.y, + entityToCheck.position.z + ); + + if(entityToCheck.mesh && entityToCheck.mesh.geometry.boundingSphere) { + ComponentTriggerSphereSphere_targetBoundingSphereRadius = entityToCheck.mesh.geometry.boundingSphere.radius; + } else { + ComponentTriggerSphereSphere_targetBoundingSphereRadius = 0.0; + } + + // do sphere sphere collision + + ComponentTriggerSphereSphere_sphereToSphere_Vector3.set( + ComponentTriggerSphereSphere_targetBoundingSpherePosition_Vector3.x - ComponentTriggerSphereSphere_spherePosition_Vector3.x, + ComponentTriggerSphereSphere_targetBoundingSpherePosition_Vector3.y - ComponentTriggerSphereSphere_spherePosition_Vector3.y, + ComponentTriggerSphereSphere_targetBoundingSpherePosition_Vector3.z - ComponentTriggerSphereSphere_spherePosition_Vector3.z + ); + + var length = ComponentTriggerSphereSphere_sphereToSphere_Vector3.length(); + + if((length - (ComponentTriggerSphereSphere_targetBoundingSphereRadius + this.sphereRadius)) < 0) { + if(this.callback) { + this.callback(parentEntity, entityToCheck); + } + } + } +}; \ No newline at end of file diff --git a/src/game-lib-entity.js b/src/game-lib-entity.js index 75fc2a4..dc3c4b2 100644 --- a/src/game-lib-entity.js +++ b/src/game-lib-entity.js @@ -1,6 +1,9 @@ GameLib.D3.Entity = function( meshId, - componentIds + componentIds, + position, + quaternion, + scale ) { this.meshId = meshId; @@ -14,15 +17,20 @@ GameLib.D3.Entity = function( this.parentScene = null; this.mesh = null; - // todo: - // add position, rotation & scale properties to entity itself! + if(GameLib.D3.Utils.UndefinedOrNull(position)) { + position = new GameLib.D3.Vector3(0, 0, 0); + } + this.position = position; - this.permutate = { - offset : { - position : null, - quaternion : null - } - }; + if(GameLib.D3.Utils.UndefinedOrNull(quaternion)) { + quaternion = new GameLib.D3.Vector4(0, 0, 0, 1); + } + this.quaternion = quaternion; + + if(GameLib.D3.Utils.UndefinedOrNull(scale)) { + scale = new GameLib.D3.Vector3(1, 1, 1); + } + this.scale = scale; }; /** @@ -40,6 +48,12 @@ GameLib.D3.Entity.prototype.update = function( } } + if(this.mesh) { + this.mesh.position.set(this.position.x, this.position.y, this.position.z); + this.mesh.quaternion.set(this.quaternion.x, this.quaternion.y, this.quaternion.z, this.quaternion.w); + this.mesh.scale.set(this.scale.x, this.scale.y, this.scale.z); + } + this.onUpdate(deltaTime); }; @@ -71,7 +85,7 @@ GameLib.D3.Entity.prototype.register = function( this.parentScene = parentScene; if(this.meshId != null && parentScene.meshIdToMesh[this.meshId]) { - parentScene.threeScene.add(parentScene.meshIdToMesh[this.meshId]); + parentScene.instance.add(parentScene.meshIdToMesh[this.meshId]); this.mesh = parentScene.meshIdToMesh[this.meshId]; } @@ -105,6 +119,20 @@ GameLib.D3.Entity.prototype.addComponent = function( }; +GameLib.D3.Entity.prototype.getComponent = function( + componentType +) { + for(var c in this.componentIds) { + var componentId = this.componentIds[c]; + var component = this.parentScene.componentIdToComponent[componentId]; + if (component instanceof componentType) { + return component; + } + } + + return null; +}; + ///////////////////////// Methods to override ////////////////////////// GameLib.D3.Entity.prototype.onUpdate = function( diff --git a/src/game-lib-game.js b/src/game-lib-game.js index 1c8a19c..70cdadd 100644 --- a/src/game-lib-game.js +++ b/src/game-lib-game.js @@ -44,7 +44,8 @@ GameLib.D3.Game.prototype.update = function( for(var w in scene.worlds) { var world = scene.worlds[w]; - world.step(fixedDt); + // NOTE: We are calling the step function with a variable timestep! + world.step(dt); } scene.update(dt); diff --git a/src/game-lib-raycast-vehicle.js b/src/game-lib-raycast-vehicle.js index bfbcf2c..f84ce77 100644 --- a/src/game-lib-raycast-vehicle.js +++ b/src/game-lib-raycast-vehicle.js @@ -8,7 +8,8 @@ GameLib.D3.RaycastVehicle = function( engine, chassisBody, - wheels + wheels, + wheelBodies ) { this.engine = engine; this.engine.isNotCannonThrow(); @@ -22,6 +23,11 @@ GameLib.D3.RaycastVehicle = function( } this.wheels = wheels; + if(GameLib.D3.Utils.UndefinedOrNull(wheelBodies)) { + wheelBodies = []; + } + this.wheelBodies = wheelBodies; + this.instance = this.createInstance(); GameLib.D3.Utils.Extend(GameLib.D3.RaycastVehicle, GameLib.D3.ComponentInterface); @@ -40,11 +46,14 @@ GameLib.D3.RaycastVehicle.prototype.createInstance = function() { /** * Adds a raycast wheel to this vehicle * @param wheel GameLib.D3.RaycastWheel + * @param wheelRigidBody GameLib.D3.RigidBody */ GameLib.D3.RaycastVehicle.prototype.addWheel = function ( - wheel + wheel, + wheelRigidBody ) { this.wheels.push(wheel); + this.wheelBodies.push(wheelRigidBody); wheel.wheelIndex = this.instance.addWheel(wheel.instance); }; @@ -64,9 +73,13 @@ GameLib.D3.RaycastVehicle.prototype.onUpdate = function( deltaTime, parentEntity ) { - /*for (var i = 0; i < this.getWheelInfo().length; i++) { + for (var i = 0; i < this.getWheelInfo().length; i++) { this.instance.updateWheelTransform(i); - }*/ + var t = this.getWheelInfo()[i].worldTransform; + var wheelBody = this.wheelBodies[i].instance; + wheelBody.position.copy(t.position); + wheelBody.quaternion.copy(t.quaternion); + } }; GameLib.D3.RaycastVehicle.prototype.onRegistered = function( diff --git a/src/game-lib-rigid-body.js b/src/game-lib-rigid-body.js index 7e750b9..4c94abf 100644 --- a/src/game-lib-rigid-body.js +++ b/src/game-lib-rigid-body.js @@ -149,14 +149,20 @@ GameLib.D3.RigidBody.prototype.onUpdate = function( deltaTime, parentEntity ) { - if(parentEntity.mesh) { + if(parentEntity) { var quaternion = new THREE.Quaternion(); quaternion.copy(this.instance.quaternion); var position = new THREE.Vector3(); position.copy(this.instance.position); - parentEntity.mesh.position.copy(position); - parentEntity.mesh.quaternion.copy(quaternion); + parentEntity.position.x = position.x; + parentEntity.position.y = position.y; + parentEntity.position.z = position.z; + + parentEntity.quaternion.x = quaternion.x; + parentEntity.quaternion.y = quaternion.y; + parentEntity.quaternion.z = quaternion.z; + parentEntity.quaternion.w = quaternion.w; } }; \ No newline at end of file diff --git a/src/game-lib-scene.js b/src/game-lib-scene.js index 82ad00e..1662b8b 100644 --- a/src/game-lib-scene.js +++ b/src/game-lib-scene.js @@ -96,10 +96,7 @@ GameLib.D3.Scene = function( } this.entities = entities; - // todo: remove this from the scene class - // changes - this.threeScene = new THREE.Scene(); - this.threeScene.render = true; + this.instance = this.createInstance(); // assoc array this.meshIdToMesh = {}; @@ -713,3 +710,89 @@ GameLib.D3.Scene.FromAPIScene = function( uploadUrl ) }; + +/** + * Updates the scene + * @param deltaTime + */ +GameLib.D3.Scene.prototype.update = function( + deltaTime +) { + for(var e in this.entities) { + this.entities[e].update(deltaTime); + } +}; + +/** + * Updates the scene + * @param deltaTime + */ +GameLib.D3.Scene.prototype.lateUpdate = function( + deltaTime +) { + for(var e in this.entities) { + this.entities[e].lateUpdate(deltaTime); + } +}; + +/** + * renders the scene + * @param deltaTime + * @param renderer + * @param camera + */ +GameLib.D3.Scene.prototype.render = function( + deltaTime, + renderer, + camera +) { + renderer.render(this.instance, camera); +}; + +/** + * Registers an entity to the scene. + * This method also links the entity and it's components, + * if they are defined inside the componentIds array. + * The setParentEntity and onSetParentEntity methods are being called here. + * @param entity GameLib.D3.Entity + */ +GameLib.D3.Scene.prototype.registerEntity = function( + entity +) { + this.entities.push(entity); + entity.register(this); + + // link components to entity + for(var c in entity.componentIds) { + var componentId = entity.componentIds[c]; + + var component = this.componentIdToComponent[componentId]; + if(component) { + component.setParentEntity(this, entity); + } + } +}; + +/** + * Registers a component to the scene. + * This method also calls the onRegistered-method on the component + * @param component GameLib.D3.ComponentInterface + */ +GameLib.D3.Scene.prototype.registerComponent = function( + component +) { + this.componentIdToComponent[component.componentId] = component; + if(component.onRegistered && typeof component.onRegistered == 'function') { + component.onRegistered(this); + } +}; + +/** + * Registers a light to the scene + * @param light THREE.Light + */ +GameLib.D3.Scene.prototype.registerLight = function( + light +) { + this.instance.add(light); +}; \ No newline at end of file diff --git a/src/game-lib-shape.js b/src/game-lib-shape.js index 3ae8381..1734411 100644 --- a/src/game-lib-shape.js +++ b/src/game-lib-shape.js @@ -99,6 +99,7 @@ GameLib.D3.Shape.SHAPE_TYPE_TRIMESH = 3; GameLib.D3.Shape.SHAPE_TYPE_CYLINDER = 4; GameLib.D3.Shape.SHAPE_TYPE_HEIGHT_MAP = 5; GameLib.D3.Shape.SHAPE_TYPE_CONVEX_HULL = 6; +GameLib.D3.Shape.SHAPE_TYPE_PLANE = 7; /** * @@ -139,8 +140,13 @@ GameLib.D3.Shape.prototype.createInstance = function() { } ); } else if (this.shapeType == GameLib.D3.Shape.SHAPE_TYPE_CONVEX_HULL) { - console.warn('Shape type not implemented: ' + this.shapeType); - throw new Error('Shape type not implemented: ' + this.shapeType); + + instance = new this.engine.instance.ConvexPolyhedron( + this.vertices, this.indices + ); + + } else if(this.shapeType == GameLib.D3.Shape.SHAPE_TYPE_PLANE) { + instance = new this.engine.instance.Plane(); } else { console.warn('Shape type not implemented: ' + this.shapeType); throw new Error('Shape type not implemented: ' + this.shapeType); diff --git a/src/game-lib-vector-3.js b/src/game-lib-vector-3.js index fee45c1..8ca7cfe 100644 --- a/src/game-lib-vector-3.js +++ b/src/game-lib-vector-3.js @@ -90,6 +90,14 @@ GameLib.D3.Vector3.prototype.copy = function () { ); }; +GameLib.D3.Vector3.prototype.lerp = function ( v, alpha ) { + return new GameLib.D3.Vector3( + this.x + ( v.x - this.x ) * alpha, + this.y + ( v.y - this.y ) * alpha, + this.z + ( v.z - this.z ) * alpha + ); +}; + GameLib.D3.Vector3.prototype.multiply = function (s) { if (s instanceof GameLib.D3.Vector3) { this.x *= s.x; diff --git a/src/game-lib-world.js b/src/game-lib-world.js index 1ea9861..1052503 100644 --- a/src/game-lib-world.js +++ b/src/game-lib-world.js @@ -106,10 +106,12 @@ GameLib.D3.World.prototype.step = function( timeStep ) { // todo: figure out, why this call to internal step is more stable for trimesh collisions..... - //this.worldObject.internalStep(timeStep); + //this.instance.internalStep(timeStep); //return; + //console.log("this should not be called."); - var now = performance.now() / 1000; + //var now = Date.now() / 1000; + var now = null; if(!this.lastCallTime){ // last call time not saved, cant guess elapsed time. Take a simple step. this.instance.step(timeStep); @@ -448,6 +450,68 @@ GameLib.D3.World.prototype.generateTriangleMeshShapeDivided = function( } }; +GameLib.D3.World.prototype.generateConvexPolyShape = function( + graphics, + mesh +) { + var processedFaces = 0; + var facesPerSubSection = 2; // *2 -> SUBDIVISION MESH + var subMeshesToMerge = 4; // *2 -> SUBDIVISION MESH + var facesToProcess = subMeshesToMerge * facesPerSubSection; + + var vertices = []; + var indicies = []; + + for(var i = 0; i <= mesh.geometry.faces.length; i++) { + if(processedFaces == facesToProcess || i == mesh.geometry.faces.length) { + + // try and create convex poly........... + var convexIndices = []; + for(var index = 0; index < indicies.length / 3; index++) { + convexIndices.push([ indicies[index * 3], indicies[index * 3 + 1], indicies[index * 3 + 2] ]); + } + + var convexVertices = []; + for(var vert = 0; vert < vertices.length / 3; vert++) { + convexVertices[vert] = new CANNON.Vec3(vertices[vert * 3] * mesh.scale.x, vertices[vert * 3 + 1] * mesh.scale.y, vertices[vert * 3 + 2] * mesh.scale.z); + } + + var meshShape = new GameLib.D3.Shape(this.engine, GameLib.D3.Shape.SHAPE_TYPE_CONVEX_HULL, {x:1,y:1,z:1},convexVertices, convexIndices); + + var body = new GameLib.D3.RigidBody(this.engine, 0, 1); + body.addShape(meshShape); + + this.addRigidBody(body); + + vertices = []; + indicies = []; + processedFaces = 0; + + console.log("SPLIT MESH TO CONVEX POLY"); + + if(i == mesh.geometry.faces.length) { + break; + } + } + + var face = mesh.geometry.faces[i]; + indicies.push(indicies.length); + indicies.push(indicies.length); + indicies.push(indicies.length); + + var v0 = mesh.geometry.vertices[face.a]; + var v1 = mesh.geometry.vertices[face.b]; + var v2 = mesh.geometry.vertices[face.c]; + + vertices.push(v0.x, v0.y, v0.z); + vertices.push(v1.x, v1.y, v1.z); + vertices.push(v2.x, v2.y, v2.z); + + processedFaces++; + } + +}; + /** * @param graphics GameLib.D3.Graphics * @param graphicsMesh THREE.Mesh