diff --git a/src/game-lib-component-vehicle-ai-object-avoidance.js b/src/game-lib-component-vehicle-ai-object-avoidance.js index 1d920b5..473f709 100644 --- a/src/game-lib-component-vehicle-ai-object-avoidance.js +++ b/src/game-lib-component-vehicle-ai-object-avoidance.js @@ -54,7 +54,7 @@ GameLib.D3.ComponentVehicleAIObjectAvoidance.prototype.onSetParentEntity = funct // this should be configurable inside the editor var carBoxScaleModifier = { x : 3 / 4, y : 1 / 2, z : 0.90 }; - var sensorLength = 0.65; + var sensorLength = 7.0; var sensorColor = new THREE.Color(0, 0, 1); // . . . . . . . . . . FRONT . . . . . . . . . . @@ -75,7 +75,7 @@ GameLib.D3.ComponentVehicleAIObjectAvoidance.prototype.onSetParentEntity = funct sensorPositionOffset : new THREE.Vector3( boundingBox.max.x * this.parentEntity.mesh.scale.x * carBoxScaleModifier.x, boundingBox.max.z * this.parentEntity.mesh.scale.z * carBoxScaleModifier.z, - boundingBox.max.y * this.parentEntity.mesh.scale.y * carBoxScaleModifier.y // this is still swapped with y, because cannon. + 0//boundingBox.max.y * this.parentEntity.mesh.scale.y * carBoxScaleModifier.y // this is still swapped with y, because cannon. ) } ); @@ -97,7 +97,7 @@ GameLib.D3.ComponentVehicleAIObjectAvoidance.prototype.onSetParentEntity = funct sensorPositionOffset : new THREE.Vector3( boundingBox.max.x * this.parentEntity.mesh.scale.x * carBoxScaleModifier.x, -boundingBox.max.z * this.parentEntity.mesh.scale.z * carBoxScaleModifier.z, - boundingBox.max.y * this.parentEntity.mesh.scale.y * carBoxScaleModifier.y // this is still swapped with y, because cannon. + 0//boundingBox.max.y * this.parentEntity.mesh.scale.y * carBoxScaleModifier.y // this is still swapped with y, because cannon. ) } ); @@ -142,7 +142,7 @@ GameLib.D3.ComponentVehicleAIObjectAvoidance.prototype.onSetParentEntity = funct sensorPositionOffset : new THREE.Vector3( boundingBox.max.x * this.parentEntity.mesh.scale.x * carBoxScaleModifier.x, boundingBox.max.z * this.parentEntity.mesh.scale.z * carBoxScaleModifier.z, - boundingBox.max.y * this.parentEntity.mesh.scale.y * carBoxScaleModifier.y // this is still swapped with y, because cannon. + 0//boundingBox.max.y * this.parentEntity.mesh.scale.y * carBoxScaleModifier.y // this is still swapped with y, because cannon. ) } ); @@ -164,7 +164,7 @@ GameLib.D3.ComponentVehicleAIObjectAvoidance.prototype.onSetParentEntity = funct sensorPositionOffset : new THREE.Vector3( boundingBox.max.x * this.parentEntity.mesh.scale.x * carBoxScaleModifier.x, -boundingBox.max.z * this.parentEntity.mesh.scale.z * carBoxScaleModifier.z, - boundingBox.max.y * this.parentEntity.mesh.scale.y * carBoxScaleModifier.y // this is still swapped with y, because cannon. + 0//boundingBox.max.y * this.parentEntity.mesh.scale.y * carBoxScaleModifier.y // this is still swapped with y, because cannon. ) } ); @@ -185,7 +185,7 @@ GameLib.D3.ComponentVehicleAIObjectAvoidance.prototype.onSetParentEntity = funct sensorPositionOffset : new THREE.Vector3( boundingBox.max.x * this.parentEntity.mesh.scale.x * carBoxScaleModifier.x, boundingBox.max.z * this.parentEntity.mesh.scale.z * carBoxScaleModifier.z, - boundingBox.max.y * this.parentEntity.mesh.scale.y * carBoxScaleModifier.y // this is still swapped with y, because cannon. + 0//boundingBox.max.y * this.parentEntity.mesh.scale.y * carBoxScaleModifier.y // this is still swapped with y, because cannon. ) } ); @@ -207,7 +207,7 @@ GameLib.D3.ComponentVehicleAIObjectAvoidance.prototype.onSetParentEntity = funct sensorPositionOffset : new THREE.Vector3( boundingBox.max.x * this.parentEntity.mesh.scale.x * carBoxScaleModifier.x, -boundingBox.max.z * this.parentEntity.mesh.scale.z * carBoxScaleModifier.z, - boundingBox.max.y * this.parentEntity.mesh.scale.y * carBoxScaleModifier.y // this is still swapped with y, because cannon. + 0//boundingBox.max.y * this.parentEntity.mesh.scale.y * carBoxScaleModifier.y // this is still swapped with y, because cannon. ) } ); @@ -228,7 +228,7 @@ GameLib.D3.ComponentVehicleAIObjectAvoidance.prototype.onSetParentEntity = funct sensorPositionOffset : new THREE.Vector3( boundingBox.max.x * this.parentEntity.mesh.scale.x * carBoxScaleModifier.x, boundingBox.max.z * this.parentEntity.mesh.scale.z * carBoxScaleModifier.z, - boundingBox.max.y * this.parentEntity.mesh.scale.y * carBoxScaleModifier.y // this is still swapped with y, because cannon. + 0//boundingBox.max.y * this.parentEntity.mesh.scale.y * carBoxScaleModifier.y // this is still swapped with y, because cannon. ) } ); @@ -250,7 +250,7 @@ GameLib.D3.ComponentVehicleAIObjectAvoidance.prototype.onSetParentEntity = funct sensorPositionOffset : new THREE.Vector3( boundingBox.max.x * this.parentEntity.mesh.scale.x * carBoxScaleModifier.x, -boundingBox.max.z * this.parentEntity.mesh.scale.z * carBoxScaleModifier.z, - boundingBox.max.y * this.parentEntity.mesh.scale.y * carBoxScaleModifier.y // this is still swapped with y, because cannon. + 0//boundingBox.max.y * this.parentEntity.mesh.scale.y * carBoxScaleModifier.y // this is still swapped with y, because cannon. ) } ); @@ -265,15 +265,27 @@ GameLib.D3.ComponentVehicleAIObjectAvoidance.prototype.onUpdate = function( parentEntity ) { if(this.raycastVehicleComponent && this.physicsWorld) { + // debug + this.debugArrows.avgDirection = this.debugArrows.avgDirection || {}; + this.debugArrows.sensors = this.debugArrows.sensors || []; + var vehicleVelocity = this.parentEntity.getComponent(GameLib.D3.RigidBody).instance.velocity; var vehicleVelocityLength = 12; - // shoot rays for each sensor & check collisions. var world = this.physicsWorld.instance; var result = new CANNON.RaycastResult(); + this.debugArrows.avgDirection.vector = new THREE.Vector3(); + for(var s = 0, l = this.sensors.length; s < l; ++s) { + + // debug + if(!this.debugArrows.sensors[s]) { + this.debugArrows.sensors[s] = {}; + } + + var sensor = this.sensors[s]; var from = new THREE.Vector3( @@ -306,7 +318,7 @@ GameLib.D3.ComponentVehicleAIObjectAvoidance.prototype.onUpdate = function( this.parentEntity.quaternion.y, this.parentEntity.quaternion.z, this.parentEntity.quaternion.w - )).normalize().multiplyScalar(sensor.sensorLength * vehicleVelocityLength); + )).normalize().multiplyScalar(sensor.sensorLength); var toC = new CANNON.Vec3( @@ -329,23 +341,124 @@ GameLib.D3.ComponentVehicleAIObjectAvoidance.prototype.onUpdate = function( if(result.hasHit) { sensor.sensorColor = new THREE.Color(1, 0, 0); + + var direction = new THREE.Vector3( + sensor.sensorDirection.x, + sensor.sensorDirection.y, + sensor.sensorDirection.z + ).applyQuaternion(new THREE.Quaternion( + this.parentEntity.quaternion.x, + this.parentEntity.quaternion.y, + this.parentEntity.quaternion.z, + this.parentEntity.quaternion.w + )).normalize(); + + /*var reflection = direction.reflect( + new THREE.Vector3( + result.hitNormalWorld.x, + result.hitNormalWorld.y, + result.hitNormalWorld.z + ) + ).normalize();*/ + + var reflection = direction.reflect( + new THREE.Vector3( + result.hitPointWorld.x, + result.hitPointWorld.y, + result.hitPointWorld.z + ).normalize().cross(direction) + ).normalize().negate(); + + var origin = new THREE.Vector3( + this.parentEntity.position.x, + this.parentEntity.position.y, + this.parentEntity.position.z + ).add(new THREE.Vector3( + sensor.sensorPositionOffset.x, + sensor.sensorPositionOffset.y, + sensor.sensorPositionOffset.z + ).applyQuaternion(new THREE.Quaternion( + this.parentEntity.quaternion.x, + this.parentEntity.quaternion.y, + this.parentEntity.quaternion.z, + this.parentEntity.quaternion.w + ))); + + var moveDirection = direction.add(reflection).setY(0).normalize(); + this.debugArrows.avgDirection.vector = this.debugArrows.avgDirection.vector.add(moveDirection); + + if(this.debugArrows.sensors[s].intersectionArrow && this.debugArrows.sensors[s].mesh) { + this.debugArrows.sensors[s].mesh.remove(this.debugArrows.sensors[s].intersectionArrow); + } + + if(this.debugArrows.sensors[s].mesh){ + + var arrow = new THREE.ArrowHelper( + + moveDirection, + + origin, + + 22, + + new THREE.Color(1, 1, 0) + ); + + this.debugArrows.sensors[s].intersectionArrow = arrow; + this.debugArrows.sensors[s].mesh.add(this.debugArrows.sensors[s].intersectionArrow); + } + } else { sensor.sensorColor = new THREE.Color(0, 0, 1); + + if(this.debugArrows.sensors[s].intersectionArrow && this.debugArrows.sensors[s].mesh) { + this.debugArrows.sensors[s].mesh.remove(this.debugArrows.sensors[s].intersectionArrow); + } } } + this.debugArrows.avgDirection.vector = this.debugArrows.avgDirection.vector.normalize(); + // draw the avg move direction + + if(!this.debugArrows.avgDirection.mesh) { + this.debugArrows.avgDirection.mesh = new THREE.Mesh( + new THREE.Geometry(), + new THREE.MeshBasicMaterial( + { + color : 0x00ffff, + wireframe : true + } + ) + ); + + sys.game.scenes["MainScene"].instance.add(this.debugArrows.avgDirection.mesh); + } + + if(this.debugArrows.avgDirection.arrow && this.debugArrows.avgDirection.mesh) { + this.debugArrows.avgDirection.mesh.remove(this.debugArrows.avgDirection.arrow); + } + + this.debugArrows.avgDirection.arrow = new THREE.ArrowHelper( + this.debugArrows.avgDirection.vector, + + new THREE.Vector3( + this.parentEntity.position.x, + this.parentEntity.position.y, + this.parentEntity.position.z + ), + + 12, + + this.debugArrows.avgDirection.mesh.material.color + ); + + this.debugArrows.avgDirection.mesh.add(this.debugArrows.avgDirection.arrow); // draw sensors { - this.debugArrows.sensors = this.debugArrows.sensors || []; - for(var s = 0, l = this.sensors.length; s < l; ++s) { - if(!this.debugArrows.sensors[s]) { - this.debugArrows.sensors[s] = {}; - } - if(!this.debugArrows.sensors[s].mesh) { var geometry = new THREE.Geometry(); @@ -399,7 +512,7 @@ GameLib.D3.ComponentVehicleAIObjectAvoidance.prototype.onUpdate = function( this.parentEntity.quaternion.w ))), - sensorLength * vehicleVelocityLength, + sensorLength, sensor.sensorColor ); @@ -407,5 +520,47 @@ GameLib.D3.ComponentVehicleAIObjectAvoidance.prototype.onUpdate = function( this.debugArrows.sensors[s].mesh.add(this.debugArrows.sensors[s].arrow); } } + + + // . . . . . . . . . . . . correct the path . . . . . . . . . . . . . . + if( this.debugArrows.avgDirection.vector.x != 0 + || this.debugArrows.avgDirection.vector.y != 0 + || this.debugArrows.avgDirection.vector.z != 0 + ) { + + // get forward direction OR better the velocity angle of the car + + var avgMoveVector = this.debugArrows.avgDirection.vector; + var forward = new THREE.Vector3( + 1, + 0, + 0 + ).applyQuaternion(new THREE.Quaternion( + this.parentEntity.quaternion.x, + this.parentEntity.quaternion.y, + this.parentEntity.quaternion.z, + this.parentEntity.quaternion.w + )).setY(0).normalize(); + + // get angle and steer. + var cos = avgMoveVector.dot(forward); + + var angleRadians = Math.acos(cos); + var steerAngleModifier = GameLib.D3.Vector3.AngleDirection( + forward, + avgMoveVector, + new GameLib.D3.Vector3( + 0, + 1, + 0 + ) + ); + + var steerAngle = Math.min(angleRadians, 0.5) * steerAngleModifier; + + this.raycastVehicleComponent.instance.setSteeringValue(steerAngle, 0); + this.raycastVehicleComponent.instance.setSteeringValue(steerAngle, 1); + } + } }; \ No newline at end of file diff --git a/src/game-lib-component-vehicle-ai-path-steering.js b/src/game-lib-component-vehicle-ai-path-steering.js index 7e28974..095b02b 100644 --- a/src/game-lib-component-vehicle-ai-path-steering.js +++ b/src/game-lib-component-vehicle-ai-path-steering.js @@ -135,10 +135,6 @@ GameLib.D3.ComponentVehicleAIPathSteering.prototype.onUpdate = function( this.raycastVehicleComponent.instance.setSteeringValue(steerAngle, 1); //} - this.raycastVehicleComponent.instance.applyEngineForce(-2000, 2); - this.raycastVehicleComponent.instance.applyEngineForce(-2000, 3); - - // - - - - - - - - - - - DEBUG ARROW 1 - - - - - - - - - { if(!this.debugArrows.v1) { @@ -240,4 +236,7 @@ GameLib.D3.ComponentVehicleAIPathSteering.prototype.onUpdate = function( this.debugArrows.v2.mesh.add( this.debugArrows.v2.arrow ); } } + + this.raycastVehicleComponent.instance.applyEngineForce(-3500, 2); + this.raycastVehicleComponent.instance.applyEngineForce(-3500, 3); }; \ No newline at end of file diff --git a/src/game-lib-vector-2.js b/src/game-lib-vector-2.js index 460e5a9..1d18583 100644 --- a/src/game-lib-vector-2.js +++ b/src/game-lib-vector-2.js @@ -1,15 +1,6 @@ GameLib.D3.Vector2 = function(x, y) { - - this.x = 0; - this.y = 0; - - if (x) { - this.x = x; - } - - if (y) { - this.y = y; - } + this.x = x || 0; + this.y = y || 0; }; GameLib.D3.Vector2.prototype.copy = function() { @@ -25,3 +16,95 @@ GameLib.D3.Vector2.prototype.equals = function(v) { ((this.y == v.x) && (this.x == v.y))); }; + +GameLib.D3.Vector2.prototype.add = function(v) { + return new GameLib.D3.Vector2( + this.x + v.x, + this.y + v.y + ); +}; + +GameLib.D3.Vector2.prototype.subtract = function(v) { + return new GameLib.D3.Vector2( + this.x - v.x, + this.y - v.y + ); +}; + +GameLib.D3.Vector2.prototype.multiply = function(v) { + if (v instanceof GameLib.D3.Vector2) { + return new GameLib.D3.Vector2( + this.x * v.x, + this.y * v.y + ); + } else if (isNumber(v)) { + return new GameLib.D3.Vector2( + this.x * v, + this.y * v + ); + } +}; + +GameLib.D3.Vector2.prototype.divide = function(v) { + if (v instanceof GameLib.D3.Vector2) { + return new GameLib.D3.Vector2( + this.x * (1.0 / v.x), + this.y * (1.0 / v.y) + ); + } else if (isNumber(v)) { + var invS = 1.0 / v; + return new GameLib.D3.Vector2( + this.x * invS, + this.y * invS + ); + } +}; + +GameLib.D3.Vector2.prototype.clone = function() { + return new GameLib.D3.Vector2( + this.x, + this.y + ); +}; + +GameLib.D3.Vector2.prototype.copy = function(v) { + this.x = v.x; + this.y = v.y; +}; + +GameLib.D3.Vector2.prototype.set = function(x, y) { + this.x = x; + this.y = y; +}; + +GameLib.D3.Vector2.prototype.clamp = function(min, max) { + return new GameLib.D3.Vector2( + Math.max(min.x, Math.min(max.x, this.x)), + Math.max(min.y, Math.min(max.y, this.y)) + ); +}; + +GameLib.D3.Vector2.prototype.length = function() { + return Math.sqrt(this.x * this.x + this.y * this.y); +}; + +GameLib.D3.Vector2.prototype.dot = function(v) { + return this.x * v.x + this.y * v.y; +}; + +GameLib.D3.Vector2.prototype.normalize = function() { + return this.multiply(1.0 / this.length()); +}; + +GameLib.D3.Vector2.prototype.angle = function() { + var angle = Math.atan2(this.y, this.x); + if ( angle < 0 ) angle += 2 * Math.PI; + return angle; +}; + +GameLib.D3.Vector2.prototype.lerp = function ( v, alpha ) { + return new GameLib.D3.Vector2( + this.x + ( v.x - this.x ) * alpha, + this.y + ( v.y - this.y ) * alpha + ); +}; \ No newline at end of file diff --git a/src/game-lib-vector-3.js b/src/game-lib-vector-3.js index 32ecee8..fc7ebf5 100644 --- a/src/game-lib-vector-3.js +++ b/src/game-lib-vector-3.js @@ -1,35 +1,15 @@ GameLib.D3.Vector3 = function(x, y, z) { - - this.x = 0; - this.y = 0; - this.z = 0; - - if (x) { - this.x = x; - } - - if (y) { - this.y = y; - } - - if (z) { - this.z = z; - } + this.x = x || 0; + this.y = y || 0; + this.z = z || 0; }; GameLib.D3.Vector3.prototype.subtract = function (v) { - - if (v instanceof GameLib.D3.Vector3) { - this.x -= v.x; - this.y -= v.y; - this.z -= v.z; - } - - if (v instanceof GameLib.D3.Vector4) { - console.warn("trying to subtract vector of bigger length (4 vs 3))"); - } - - return this; + return new GameLib.D3.Vector3( + this.x - v.x, + this.y - v.y, + this.z - v.z + ); }; GameLib.D3.Vector3.prototype.cross = function (v) { @@ -40,21 +20,11 @@ GameLib.D3.Vector3.prototype.cross = function (v) { ); }; -GameLib.D3.Vector3.prototype.negative = function () { - this.x *= -1; - this.y *= -1; - this.z *= -1; - return this; -}; GameLib.D3.Vector3.clockwise = function (u, v, w, viewPoint) { - var normal = GameLib.D3.Vector3.normal(u, v, w); - var uv = u.copy(); - var winding = normal.dot(uv.subtract(viewPoint)); - return (winding > 0); }; @@ -65,10 +35,8 @@ GameLib.D3.Vector3.normal = function (u, v, w) { }; GameLib.D3.Vector3.prototype.lookAt = function (at, up) { - var lookAtMatrix = GameLib.D3.Matrix4.lookAt(this, at, up); - - this.multiply(lookAtMatrix); + return this.multiply(lookAtMatrix); }; GameLib.D3.Vector3.prototype.translate = function (v) { @@ -78,6 +46,14 @@ GameLib.D3.Vector3.prototype.translate = function (v) { return this; }; +GameLib.D3.Vector3.prototype.add = function (v) { + return new GameLib.D3.Vector3( + this.x + v.x, + this.y + v.y, + this.z + v.z + ); +}; + GameLib.D3.Vector3.prototype.squared = function () { return this.x * this.x + this.y * this.y + this.z * this.z; }; @@ -102,10 +78,12 @@ GameLib.D3.Vector3.prototype.distanceTo = function(v) { var dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z; - return Math.sqrt(dx * dx + dy * dy + dz * dz); }; +/** + * @return {number} + */ GameLib.D3.Vector3.AngleDirection = function(forward, directionToCheck, up) { var perp = forward.cross(directionToCheck); var dir = perp.dot(up); @@ -122,21 +100,51 @@ GameLib.D3.Vector3.AngleDirection = function(forward, directionToCheck, up) { GameLib.D3.Vector3.prototype.multiply = function (s) { if (s instanceof GameLib.D3.Vector3) { - this.x *= s.x; - this.y *= s.y; - this.z *= s.z; + + return new GameLib.D3.Vector3( + this.x * s.x, + this.y * s.y, + this.z * s.z + ) + } else if (s instanceof GameLib.D3.Matrix4) { + + var x = s.rows[0].x * this.x + s.rows[0].y * this.y + s.rows[0].z * this.z + s.rows[0].w; + var y = s.rows[1].x * this.x + s.rows[1].y * this.y + s.rows[1].z * this.z + s.rows[1].w; + var z = s.rows[2].x * this.x + s.rows[2].y * this.y + s.rows[2].z * this.z + s.rows[2].w; + + return new GameLib.D3.Vector3( + x, + y, + z + ); + + } else if (s instanceof GameLib.D3.Matrix3) { + var x = s.rows[0].x * this.x + s.rows[0].y * this.y + s.rows[0].z * this.z; var y = s.rows[1].x * this.x + s.rows[1].y * this.y + s.rows[1].z * this.z; var z = s.rows[2].x * this.x + s.rows[2].y * this.y + s.rows[2].z * this.z; - this.x = x; - this.y = y; - this.z = z; + + return new GameLib.D3.Vector3( + x, + y, + z + ); + + } else if(isNumber(s)) { + + return new GameLib.D3.Vector3( + this.x * s, + this.y * s, + this.z * s + ); + } else { + console.log("functionality not implemented - please do this"); throw new Error("not implemented"); + return this; } - return this; }; @@ -145,20 +153,73 @@ GameLib.D3.Vector3.prototype.dot = function (v) { }; GameLib.D3.Vector3.prototype.normalize = function () { - var EPSILON = 0.000001; - var v2 = this.squared(); if (v2 < EPSILON) { return this; //do nothing for zero vector } - var invLength = 1 / Math.sqrt(v2); + var invLength = 1.0 / Math.sqrt(v2); + return new GameLib.D3.Vector3( + this.x * invLength, + this.y * invLength, + this.z * invLength + ); +}; - this.x *= invLength; - this.y *= invLength; - this.z *= invLength; +GameLib.D3.Vector3.prototype.clone = function () { + return new GameLib.D3.Vector3( + this.x, + this.y, + this.z + ); +}; + +GameLib.D3.Vector3.prototype.applyQuaternion = function(q) { + var x = this.x, y = this.y, z = this.z; + var qx = q.x, qy = q.y, qz = q.z, qw = q.w; + + // calculate quat * vector + + var ix = qw * x + qy * z - qz * y; + var iy = qw * y + qz * x - qx * z; + var iz = qw * z + qx * y - qy * x; + var iw = - qx * x - qy * y - qz * z; + + // calculate result * inverse quat + + return new GameLib.D3.Vector3( + ix * qw + iw * - qx + iy * - qz - iz * - qy, + iy * qw + iw * - qy + iz * - qx - ix * - qz, + iz * qw + iw * - qz + ix * - qy - iy * - qx + ); +}; + +GameLib.D3.Vector3.prototype.clamp = function(min, max) { + this.x = Math.max( min.x, Math.min( max.x, this.x ) ); + this.y = Math.max( min.y, Math.min( max.y, this.y ) ); + this.z = Math.max( min.z, Math.min( max.z, this.z ) ); return this; }; + +GameLib.D3.Vector3.prototype.negate = function() { + this.x = -this.x; + this.y = -this.y; + this.z = -this.z; + return this; +}; + +GameLib.D3.Vector3.prototype.length = function() { + return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z ); +}; + +GameLib.D3.Vector3.prototype.reflect = function(normal) { + return this.sub( v1.copy( normal ).multiply( 2 * this.dot( normal ) ) ); +}; + +GameLib.D3.Vector3.prototype.angleTo = function (v) { + var theta = this.dot( v ) / ( Math.sqrt( this.lengthSq() * v.lengthSq() ) ); + return Math.acos( exports.Math.clamp( theta, - 1, 1 ) ); +}; \ No newline at end of file