/** * * @param id * @param name * @param splineCurve3 * @param accel * @param maxSpeed * @param baseOffset * @param maxOffset * @param steeringSpeed * @constructor */ GameLib.D3.ComponentPathFollowing = function ComponentPathFollowing( id, name, splineCurve3, accel, maxSpeed, baseOffset, maxOffset, steeringSpeed ) { this.id = id || GameLib.D3.Tools.RandomId(); if (typeof name == 'undefined') { name = this.constructor.name; } this.name = name; this.parentEntity = null; this.splineCurve3 = splineCurve3; this.maxSpeed = maxSpeed || 10.0; this.accel = accel || 2.0; this.baseOffset = baseOffset || new GameLib.D3.Vector3(); this.maxOffset = maxOffset || new GameLib.D3.Vector3(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER); this.steeringSpeed = steeringSpeed || 1.0; //#ifdef RUNTIME__ // runtime code this.offset = new GameLib.D3.Vector3(); // this one is our destination offset this.currentOffset = new GameLib.D3.Vector3(); this.currentPathValue = 0.0; this.currentSpeed = 0.0; this.direction = 0; //#endif GameLib.D3.Utils.Extend(GameLib.D3.ComponentPathFollowing, GameLib.D3.ComponentInterface); }; //#ifdef RUNTIME__ ///////////////////////// Methods to override ////////////////////////// GameLib.D3.ComponentPathFollowing.prototype.onUpdate = function( deltaTime, parentEntity ) { if(this.splineCurve3) { if(this.currentPathValue >= 1 || this.currentPathValue < 0) { this.currentPathValue = 0; } //To maintain a constant speed, you use .getPointAt( t ) instead of .getPoint( t ). //http://stackoverflow.com/questions/18400667/three-js-object-following-a-spline-path-rotation-tanget-issues-constant-sp var position = this.splineCurve3.getPointAt(this.currentPathValue); var rotation = this.splineCurve3.getTangentAt(this.currentPathValue).normalize(); // extract rotation var forward = new THREE.Vector3(-1, 0, 0); var axis = new THREE.Vector3(); axis.crossVectors(forward, rotation).normalize(); var radians = Math.acos(forward.dot(rotation)); var quaternion = new THREE.Quaternion().setFromAxisAngle(axis, radians); { // update current speed var t = deltaTime * this.accel; t = t * t * t * (t * (6.0 * t - 15.0) + 10.0); this.currentSpeed = this.currentSpeed + (this.maxSpeed * this.direction - this.currentSpeed) * t; } { // update position var t = deltaTime * this.accel; t = t * t * t * (t * (6.0 * t - 15.0) + 10.0); var lerpedOffset = new THREE.Vector3( this.currentOffset.x, this.currentOffset.y, this.currentOffset.z ).lerp(new THREE.Vector3( this.maxOffset.x * this.offset.x, this.maxOffset.y * this.offset.y, this.maxOffset.z * this.offset.z ), t); this.currentOffset.x = lerpedOffset.x; this.currentOffset.y = lerpedOffset.y; this.currentOffset.z = lerpedOffset.z; var transformedOffset = new THREE.Vector3( this.baseOffset.x + lerpedOffset.x, this.baseOffset.y + lerpedOffset.y, this.baseOffset.z + lerpedOffset.z ).applyQuaternion(quaternion); // apply to parent rigidbody instead of direclty to the mesh. parentEntity.position.x = position.x + transformedOffset.x; parentEntity.position.y = position.y + transformedOffset.y; parentEntity.position.z = position.z + transformedOffset.z; } { // update rotation parentEntity.quaternion.x = quaternion.x; parentEntity.quaternion.y = quaternion.y; parentEntity.quaternion.z = quaternion.z; parentEntity.quaternion.w = quaternion.w; } // update current path value & check bounds this.currentPathValue += (this.currentSpeed); if(this.currentSpeed >= this.maxSpeed) { this.currentSpeed = this.maxSpeed; } else if (this.currentSpeed <= 0) { this.currentSpeed = 0.0; } } }; //#endif GameLib.D3.ComponentPathFollowing.prototype.onSetParentEntity = function( parentScene, parentEntity ) { if(!this.splineCurve3) { console.error("NO PATH GIVEN"); } };