diff --git a/examples/assets/images/red-tank-diffuse.jpg b/examples/assets/images/red-tank-diffuse.jpg new file mode 100644 index 0000000..685cc41 Binary files /dev/null and b/examples/assets/images/red-tank-diffuse.jpg differ diff --git a/examples/assets/procedural-sphere.js b/examples/assets/procedural-sphere.js new file mode 100644 index 0000000..aa71436 --- /dev/null +++ b/examples/assets/procedural-sphere.js @@ -0,0 +1,26 @@ +function proc( options ) { + + options = options || {}; + options.type = options.type || "sphere"; + options.radius = options.radius || 0.5; + options.latDetail = options.latDetail || 24; + options.lonDetail = options.lonDetail || 24; + + var mesh = + { + primitive: { + type: options.type, + radius: options.radius, + lat: options.latDetail, + lon: options.lonDetail, + uvmapper: { + projectionMode: "cubic", + scale: [1, 1, 1] + } + }, + compile: true + }; + + return mesh; + +} \ No newline at end of file diff --git a/examples/cube-collision/cube-collision.js b/examples/cube-collision/cube-collision.js index db393e7..d22e711 100644 --- a/examples/cube-collision/cube-collision.js +++ b/examples/cube-collision/cube-collision.js @@ -32,12 +32,12 @@ document.addEventListener( "DOMContentLoaded", function( e ) { var box2dOptions = { resolver: { - gravity: [0,-0.5] + dimensionMap: box2dExtension.services.resolver.service.prototype.DimensionMaps.XY } }; engine.registerExtension( cubicvrExtension, cubicvrOptions ); - engine.registerExtension( box2dExtension);//, box2dOptions); + engine.registerExtension( box2dExtension, box2dOptions); var resources = {}; @@ -102,13 +102,14 @@ document.addEventListener( "DOMContentLoaded", function( e ) { var lightDefinition = new cubicvr.LightDefinition({ intensity: 1, + distance: 20, light_type: cubicvr.LightDefinition.LightTypes.POINT, method: cubicvr.LightDefinition.LightingMethods.DYNAMIC }); space.add( new engine.Entity( "camera", [ - new engine.core.Transform( [0, 0, 5] ), + new engine.core.Transform( [0, 0, 10] ), new cubicvr.Light( lightDefinition ), new cubicvr.Camera( { targeted:false @@ -117,7 +118,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { )); var bodyDefinition = new box2d.BodyDefinition(); - var fixtureDefinition = new box2d.FixtureDefinition({shape:new box2d.BoxShape(0.25,0.25)}); + var fixtureDefinition = new box2d.FixtureDefinition({shape:new box2d.BoxShape(1,1)}); for (var cubeIndex = 0; cubeIndex < 5; cubeIndex++){ @@ -132,7 +133,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { }; var firstCube = new engine.Entity( "cube1", [ - new engine.core.Transform( [3 + cubeIndex * 1.5, 0.125, 0], [0, 0, 0], [0.5, 0.5, 0.5] ), + new engine.core.Transform( [3 + cubeIndex * 3, 0.25, 0], [0, 0, 0]), firstBody, new cubicvr.Model( resources.mesh, resources.material ) ] @@ -151,14 +152,14 @@ document.addEventListener( "DOMContentLoaded", function( e ) { var secondCube = new engine.Entity( "cube2", [ - new engine.core.Transform( [-3 - cubeIndex * 1.5, -0.125, 0], [0, 0, 0], [0.5, 0.5, 0.5] ), + new engine.core.Transform( [-3 - cubeIndex * 3, -0.25, 0], [0, 0, 0]), secondBody, new cubicvr.Model( resources.mesh, resources.material ) ] ); space.add( secondCube ); - new engine.Event("LinearImpulse", {impulse: [-0.25,0]}).dispatch(firstCube); - new engine.Event("LinearImpulse", {impulse: [0.25,0]}).dispatch(secondCube); + new engine.Event("LinearImpulse", {impulse: [-1,0]}).dispatch(firstCube); + new engine.Event("LinearImpulse", {impulse: [1,0]}).dispatch(secondCube); } var task = new engine.FunctionTask( function() { diff --git a/examples/tank/index.html b/examples/tank/index.html index 81f2028..5193d4d 100644 --- a/examples/tank/index.html +++ b/examples/tank/index.html @@ -15,7 +15,9 @@

Tank controls

Press S to move the tank backwards
Press A to turn the tank left
Press D to turn the tank right
- Press Space to trigger a fire event (viewable in the console) + Press the left arrow key to turn the turret to the left
+ Press the right arrow key to turn the turret to the right
+ Press Space to fire

diff --git a/examples/tank/tank-controls.json b/examples/tank/tank-controls.json index 21cf1e1..7d948ed 100644 --- a/examples/tank/tank-controls.json +++ b/examples/tank/tank-controls.json @@ -4,7 +4,9 @@ "MoveBackward": [ "S" ], "TurnLeft": [ "A" ], "TurnRight": [ "D" ], - "StrafeModifier": [ "SHIFT" ] + "StrafeModifier": [ "SHIFT" ], + "TurnTurretLeft": [ "LEFT" ], + "TurnTurretRight": [ "RIGHT" ] }, "Actions": { "Fire": [ "SPACE" ] diff --git a/examples/tank/tank.js b/examples/tank/tank.js index be926ea..3e70b85 100644 --- a/examples/tank/tank.js +++ b/examples/tank/tank.js @@ -7,8 +7,9 @@ document.addEventListener( "DOMContentLoaded", function( e ) { require( [ "gladius-core", "gladius-cubicvr", - "gladius-input" ], - function( Gladius, cubicvrExtension, inputExtension ) { + "gladius-input", + "gladius-box2d" ], + function( Gladius, cubicvrExtension, inputExtension, box2dExtension ) { var engine = new Gladius(); @@ -37,19 +38,34 @@ document.addEventListener( "DOMContentLoaded", function( e ) { } engine.registerExtension( inputExtension, inputOptions ); + engine.registerExtension( box2dExtension ); + var cubicvr = engine.findExtension( "gladius-cubicvr" ); var input = engine.findExtension( "gladius-input" ); + var box2d = engine.findExtension( "gladius-box2d" ); var resources = {}; + var bulletMaterialArgs = '?colorTexture=../assets/images/cube-diffuse.jpg' + + '&bumpTexture=../assets/images/cube-bump.jpg' + + '&normalTexture=../assets/images/cube-normal.jpg'; + var materialArgs = '?colorTexture=../assets/images/tank-diffuse.jpg' + '&bumpTexture=../assets/images/tank-bump.jpg' + '&normalTexture=../assets/images/tank-normal.jpg'; + var redMaterialArgs = '?colorTexture=../assets/images/red-tank-diffuse.jpg' + + '&bumpTexture=../assets/images/tank-bump.jpg' + + '&normalTexture=../assets/images/tank-normal.jpg'; + + var wallMaterialArgs = '?colorTexture=../assets/images/cube-impulse-diffuse.jpg' + + '&bumpTexture=../assets/images/cube-impulse-bump.jpg' + + '&normalTexture=../assets/images/cube-impulse-normal.jpg'; + engine.get( [ { type: cubicvr.Mesh, - url: "../assets/procedural-prism.js?length=2.0&width=1.0&depth=0.5", + url: "../assets/procedural-prism.js?length=1.0&width=0.5&depth=0.25", load: engine.loaders.procedural, onsuccess: function( mesh ) { resources.tankBody = mesh; @@ -59,7 +75,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { }, { type: cubicvr.Mesh, - url: "../assets/procedural-prism.js?length=1.7&width=0.4&depth=0.7", + url: "../assets/procedural-prism.js?length=0.85&width=0.2&depth=0.35", load: engine.loaders.procedural, onsuccess: function( mesh ) { resources.tankTread = mesh; @@ -69,7 +85,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { }, { type: cubicvr.Mesh, - url: "../assets/procedural-prism.js?length=1.0&width=0.7&depth=0.3", + url: "../assets/procedural-prism.js?length=0.5&width=0.35&depth=0.15", load: engine.loaders.procedural, onsuccess: function( mesh ) { resources.tankTurret = mesh; @@ -79,7 +95,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { }, { type: cubicvr.Mesh, - url: "../assets/procedural-prism.js?length=0.8&width=0.2&depth=0.1", + url: "../assets/procedural-prism.js?length=0.4&width=0.1&depth=0.05", load: engine.loaders.procedural, onsuccess: function( mesh ) { resources.tankBarrel = mesh; @@ -87,6 +103,26 @@ document.addEventListener( "DOMContentLoaded", function( e ) { onfailure: function( error ) { } }, + { + type: cubicvr.Mesh, + url: "../assets/procedural-prism.js?length=10&width=1&depth=1", + load: engine.loaders.procedural, + onsuccess: function( mesh ) { + resources.wall = mesh; + }, + onfailure: function( error ) { + } + }, + { + type: cubicvr.Mesh, + url: "../assets/procedural-sphere.js?type=sphere&radius=0.25", + load: engine.loaders.procedural, + onsuccess: function( mesh ) { + resources.bullet = mesh; + }, + onfailure: function( error ) { + } + }, { type: cubicvr.MaterialDefinition, url: "../assets/procedural-material.js" + materialArgs, @@ -97,6 +133,36 @@ document.addEventListener( "DOMContentLoaded", function( e ) { onfailure: function( error ) { } }, + { + type: cubicvr.MaterialDefinition, + url: "../assets/procedural-material.js" + redMaterialArgs, + load: engine.loaders.procedural, + onsuccess: function( material ) { + resources.redMaterial = material; + }, + onfailure: function( error ) { + } + }, + { + type: cubicvr.MaterialDefinition, + url: "../assets/procedural-material.js" + wallMaterialArgs, + load: engine.loaders.procedural, + onsuccess: function( material ) { + resources.wallMaterial = material; + }, + onfailure: function( error ) { + } + }, + { + type: cubicvr.MaterialDefinition, + url: "../assets/procedural-material.js" + bulletMaterialArgs, + load: engine.loaders.procedural, + onsuccess: function( material ) { + resources.bulletMaterial = material; + }, + onfailure: function( error ) { + } + }, { type: input.Map, url: "tank-controls.json", @@ -115,124 +181,415 @@ document.addEventListener( "DOMContentLoaded", function( e ) { }); function game( engine, resources ) { + function getRandom(min, max) + { + return Math.random() * (max - min) + min; + } + var math = engine.math; var space = new engine.SimulationSpace(); var cubicvr = engine.findExtension( "gladius-cubicvr" ); var input = engine.findExtension( "gladius-input" ); + var box2d = engine.findExtension( "gladius-box2d" ); var Entity = engine.Entity; + var lastBulletTime = 0; + var lastRedBulletTime = 0; + var greenTankFiringInterval = 500; + var redTankFiringInterval = 1000; + var tankMovementSpeed = 3; + var tankRotationSpeed = 2; + var greenTankTurretRotationSpeed = 2; + var redTankTurretRotationSpeed = 1.1; + var minRedTankStunTime = 1; + var maxRedTankStunTime = 2.25; + var minGreenTankStunTime = 0.5; + var maxGreenTankStunTime = 1; + var bulletVelocity = [3,0,0]; + + var tankVelocity = [0,0,0]; + var rotation = 0; + var lightDefinition = new cubicvr.LightDefinition({ - intensity: 2, + intensity: 1.5, + distance: 30, light_type: cubicvr.LightDefinition.LightTypes.POINT, method: cubicvr.LightDefinition.LightingMethods.DYNAMIC }); var tankLogic = { "Update": function( event ) { - if( this.owner.hasComponent( "Controller" ) ) { + var elapsedTime = space.clock.delta/1000; + var greenTank = space.findNamed( "tank" ); + var turretTransform = space.findNamed ("tank-turret").findComponent( "Transform" ); + if (greenTank.stunned){ + greenTank.stunnedTime -= elapsedTime; + if (greenTank.stunnedTime < 0){ + greenTank.stunned = false; + }else{ + turretTransform.rotation.z += greenTank.stunnedTurretRotationSpeed * elapsedTime * greenTank.stunnedTurretRotationDirection; + } + }else if( this.owner.hasComponent( "Controller" ) ) { var controller = this.owner.findComponent( "Controller" ); - var transform = space.findNamed( "tank-body" ).findComponent( "Transform" ); + var physBody = this.owner.findComponent( "Body" ); + var transform = greenTank.findComponent( "Transform" ); + tankVelocity[0] = 0; + tankVelocity[1] = 0; + tankVelocity[2] = 0; + rotation = 0; + if( controller.states["MoveForward"] ) { - console.log( this.owner.id, "Move forward!" ); - transform.position.add( transform.directionToLocal( [space.clock.delta * 0.001, 0, 0] ) ); + tankVelocity[0]+=tankMovementSpeed; } if( controller.states["MoveBackward"] ) { - console.log( this.owner.id, "Move backward!" ); - transform.position.add( transform.directionToLocal( [space.clock.delta * -0.001, 0, 0] )); + tankVelocity[0]-=tankMovementSpeed; } if( controller.states["TurnLeft"] ) { if( controller.states["StrafeModifier"] ) { - console.log( this.owner.id, "Strafe left!" ); - transform.position.add( transform.directionToLocal( [0, space.clock.delta * -0.001, 0] )); + tankVelocity[1]-=tankMovementSpeed; } else { - console.log( this.owner.id, "Turn left!" ); - var rotation = transform.rotation; - transform.rotation.add([0, 0, space.clock.delta * -0.001] ); + rotation+=tankRotationSpeed; } } if( controller.states["TurnRight"] ) { if( controller.states["StrafeModifier"] ) { - console.log( this.owner.id, "Strafe right!" ); - transform.position.add( transform.directionToLocal( [0, space.clock.delta * 0.001, 0] )); + tankVelocity[1]+=tankMovementSpeed; } else { - console.log( this.owner.id, "Turn right!" ); - var rotation = transform.rotation; - transform.rotation.add([0, 0, space.clock.delta * 0.001] ); + rotation-=tankRotationSpeed; } } + transform.pointToWorld(tankVelocity, tankVelocity); + physBody.setLinearVelocity(tankVelocity[0],tankVelocity[1]); + physBody.setAngularVelocity(rotation); + if (controller.states["TurnTurretLeft"] ) { + turretTransform.rotation.add([0, 0, (space.clock.delta/1000) * greenTankTurretRotationSpeed]); + } + if (controller.states["TurnTurretRight"] ) { + turretTransform.rotation.add([0, 0, (space.clock.delta/1000) * -greenTankTurretRotationSpeed]); + } + } }, "Fire": function( event ) { - console.log( this.owner.id, "Fire!" ); + if (space.clock.time > lastBulletTime + greenTankFiringInterval){ + lastBulletTime = space.clock.time; + var physicsBody = new box2d.Body({bodyDefinition: new box2d.BodyDefinition({bullet:true}), + fixtureDefinition: new box2d.FixtureDefinition( + { + shape:new box2d.CircleShape(0.25), + friction:0.1, + //restitution determines the elasticity of collisions + //0 = inelastic, 1 = completely elastic, >1 = very high velocities + restitution:0.7, + //The collision filters here are defined using bitwise masking. + //Please see http://www.box2d.org/manual.html#_Toc258082972 for more details + //In this case the mask of 23 means it'll collide with + //tank b, walls, and with bullets from the green tank and the red tank + //which are categories 16, 4, 2, and 1 + //16+4+2+1 = 23 + //Note that all the component numbers here are and must be powers of 2 + filter:{categoryBits:2, maskBits:23} + })}); + physicsBody.tankBulletCollisions = 0; + var barrelTransform = space.findNamed("tank-barrel").findComponent( "Transform"); + var bulletFiringPoint = math.vector3.add(barrelTransform.toWorldPoint(), barrelTransform.pointToWorld([0.3,0,0])); + var newBullet = new Entity("bullet", + [ + new engine.core.Transform(bulletFiringPoint), + new cubicvr.Model(resources.bullet, resources.bulletMaterial), + physicsBody + ] + ); + physicsBody.onContactBegin = function(event){ + this.tankBulletCollisions++; + if (this.tankBulletCollisions === 3){ + //This is how you remove something from the space properly + this.owner.setActive(false); + space.remove(this.owner); + } + }; + space.add(newBullet); + bulletVelocity = [3,0,0]; + space.findNamed("tank-barrel").findComponent( "Transform").pointToWorld(bulletVelocity, bulletVelocity); + var impEvent = new engine.Event('LinearImpulse',{impulse: [bulletVelocity[0], bulletVelocity[1]]}); + impEvent.dispatch(newBullet); + } } }; - // This parent entity will let us adjust the position and orientation of the - // tank, and handle game logic events - space.add( new Entity( "tank", - [ - new engine.core.Transform( [0, 0, 5], [math.TAU/6, 0, 0], [0.5, 0.5, 0.5] ), - new input.Controller( resources.tankControls ), - new engine.logic.Actor( tankLogic ) - ], - ["tank"] - )); - space.add( new Entity( "tank-body", - [ - new engine.core.Transform(), - new cubicvr.Model( resources.tankBody, resources.material ) - ], - ["tank"], - space.findNamed( "tank" ) - )); - space.add( new Entity( "tank-tread", + function createTank(name, position, material, hasControls, collisionCategory) { + // This parent entity will let us adjust the position and orientation of the + // tank, and handle game logic events + space.add(new Entity(name, + [ + new engine.core.Transform(position), + new engine.logic.Actor(tankLogic), + new box2d.Body({bodyDefinition: new box2d.BodyDefinition(), + fixtureDefinition: new box2d.FixtureDefinition( + {shape:new box2d.BoxShape(1,1), + filter:{categoryBits:collisionCategory} + })}) + ], + [name] + )); + if (hasControls){ + space.findNamed(name).addComponent(new input.Controller(resources.tankControls)); + } + space.add(new Entity(name + "-body", + [ + new engine.core.Transform(), + new cubicvr.Model(resources.tankBody, material) + ], + [name], + space.findNamed(name) + )); + space.add(new Entity(name + "-tread", + [ + new engine.core.Transform([0, 0.4, 0]), + new cubicvr.Model(resources.tankTread, material) + ], + [name], + space.findNamed(name + "-body") + )); + space.add(new Entity(name + "-tread", + [ + new engine.core.Transform([0, -0.4, 0]), + new cubicvr.Model(resources.tankTread, material) + ], + [name], + space.findNamed(name + "-body") + )); + space.add(new Entity(name+"-turret", + [ + new engine.core.Transform([-0.1, 0, 0.3]), + new cubicvr.Model(resources.tankTurret, material) + ], + [name], + space.findNamed(name + "-body") + )); + space.add(new Entity(name + "-barrel", + [ + new engine.core.Transform([0.4, 0, 0]), + new cubicvr.Model(resources.tankBarrel, material) + ], + [name], + space.findNamed(name + "-turret") + )); + } + createTank("tank", [-3,-3], resources.material, true, 8); + createTank("red-tank", [3,3,0], resources.redMaterial, false, 16); + var redTank = space.findNamed( "red-tank" ); + redTank.doneRotation = true; + redTank.doneMovement = true; + redTank.stunned = false; + redTank.stunnedTurretRotationDirection = -1; + redTank.findComponent("Body").onContactBegin = function(event){ + if (!this.owner.stunned){ + this.owner.stunnedTime = getRandom(minRedTankStunTime, maxRedTankStunTime); + this.owner.stunnedTurretRotationSpeed = math.TAU / this.owner.stunnedTime; + this.owner.stunnedTurretRotationDirection = this.owner.stunnedTurretRotationDirection * -1; + this.owner.stunned = true; + } + }; + + var greenTank = space.findNamed( "tank" ); + greenTank.stunned = false; + greenTank.stunnedTurretRotationDirection = -1; + greenTank.findComponent("Body").onContactBegin = function(event){ + if (!this.owner.stunned){ + this.owner.stunnedTime = getRandom(minGreenTankStunTime, maxGreenTankStunTime); + this.owner.stunnedTurretRotationSpeed = math.TAU / this.owner.stunnedTime; + this.owner.stunnedTurretRotationDirection = this.owner.stunnedTurretRotationDirection * -1; + this.owner.stunned = true; + } + }; + + //TODO: Make these walls have tiling textures + var bodyDefinition = new box2d.BodyDefinition({type:box2d.BodyDefinition.BodyTypes.STATIC}); + var fixtureDefinition = new box2d.FixtureDefinition({ + shape:new box2d.BoxShape(10,1), + filter:{categoryBits:1, maskBits:30}, + restitution:0.7 + }); + + var body = new box2d.Body({bodyDefinition: bodyDefinition, fixtureDefinition: fixtureDefinition}); + + space.add( new Entity( "wallLeft", [ - new engine.core.Transform( [0, 0.8, 0] ), - new cubicvr.Model( resources.tankTread, resources.material ) - ], - ["tank"], - space.findNamed( "tank-body" ) + new engine.core.Transform([-5,0,0], [0,0,math.TAU/4]), + new cubicvr.Model(resources.wall, resources.wallMaterial), + new box2d.Body({bodyDefinition: bodyDefinition, fixtureDefinition: fixtureDefinition}) + ] )); - space.add( new Entity( "tank-tread", + space.add( new Entity( "wallRight", [ - new engine.core.Transform( [0, -0.8, 0] ), - new cubicvr.Model( resources.tankTread, resources.material ) - ], - ["tank"], - space.findNamed( "tank-body" ) + new engine.core.Transform([5,0,0], [0,0,math.TAU/4]), + new cubicvr.Model(resources.wall, resources.wallMaterial), + new box2d.Body({bodyDefinition: bodyDefinition, fixtureDefinition: fixtureDefinition}) + ] )); - space.add( new Entity( "tank-turret", + space.add( new Entity( "wallTop", [ - new engine.core.Transform( [-0.2, 0, -0.6] ), - new cubicvr.Model( resources.tankTurret, resources.material ) - ], - ["tank"], - space.findNamed( "tank-body" ) + new engine.core.Transform([0,-5,0], [math.TAU/4,0,0]), + new cubicvr.Model(resources.wall, resources.wallMaterial), + new box2d.Body({bodyDefinition: bodyDefinition, fixtureDefinition: fixtureDefinition}) + ] )); - space.add( new Entity( "tank-barrel", + space.add( new Entity( "wallBottom", [ - new engine.core.Transform( [0.8, 0, 0] ), - new cubicvr.Model( resources.tankBarrel, resources.material ) - ], - ["tank"], - space.findNamed( "tank-turret" ) + new engine.core.Transform([0,5,0], [math.TAU/4,0,0]), + new cubicvr.Model(resources.wall, resources.wallMaterial), + new box2d.Body({bodyDefinition: bodyDefinition, fixtureDefinition: fixtureDefinition}) + ] )); space.add( new Entity( "camera", [ - new engine.core.Transform( [0, 0, 0] ), - new cubicvr.Camera({ - targeted: true - }), - new cubicvr.Light() + new engine.core.Transform( [0, 0, 10], [0, 0, 0] ), + new cubicvr.Camera(), + new cubicvr.Light(lightDefinition) ] )); - // space.findNamed( "camera" ).findComponent( "Camera" ).setTarget( 0, 0, 0 ); + + var elapsedTime; + var redTank = space.findNamed( "red-tank" ); + var redTankTransform = redTank.findComponent("Transform"); + var redTankTurret = space.findNamed( "red-tank-turret" ); + var redTankTurretTransform = redTankTurret.findComponent("Transform"); + var redTankBarrelTransform = space.findNamed("red-tank-barrel").findComponent("Transform"); + var position = redTankTransform.position; + var physicsBody = redTank.findComponent("Body"); + var greenTank = space.findNamed( "tank" ); + var greenTankTransform = greenTank.findComponent("Transform"); + var newPosition = []; + var changeInDirection; + + function removeExcessRotation(rotation){ + //If the change in direction is greater than 180 degrees then just rotate the other way instead + var reducedRotation = (rotation - (Math.floor(rotation / math.TAU) * math.TAU)); + if (reducedRotation > math.PI){ + reducedRotation = (math.TAU - reducedRotation) * -1; + }else if (reducedRotation < -math.PI){ + reducedRotation = (-math.TAU - reducedRotation) * -1; + } + return reducedRotation; + } var task = new engine.FunctionTask( function() { + elapsedTime = space.clock.delta/1000; + + if (redTank.stunned){ + redTank.stunnedTime -= elapsedTime; + if (redTank.stunnedTime < 0){ + redTank.stunned = false; + redTank.doneMovement = true; + }else{ + redTankTurretTransform.rotation.z += redTank.stunnedTurretRotationSpeed * elapsedTime * redTank.stunnedTurretRotationDirection; + } + } + if (!redTank.stunned){ + //Rotate the red turret to point at the green tank + var greenTankInRedTankTurretLocalSpace = redTankTurretTransform.relativeTo(greenTankTransform); + var directionOfGreenTank = Math.atan2(greenTankInRedTankTurretLocalSpace[1], greenTankInRedTankTurretLocalSpace[0]); + var currentDirection = redTankTurretTransform.rotation.z; + var differenceBetweenDirections = removeExcessRotation(currentDirection - directionOfGreenTank); + var newRotation; + if (differenceBetweenDirections > 0 && differenceBetweenDirections > (redTankTurretRotationSpeed * elapsedTime)){ + newRotation = currentDirection - (redTankTurretRotationSpeed * elapsedTime); + }else if (differenceBetweenDirections < 0 && (-differenceBetweenDirections) > (redTankTurretRotationSpeed * elapsedTime)){ + newRotation = currentDirection + (redTankTurretRotationSpeed * elapsedTime); + }else{ + newRotation = directionOfGreenTank; + } + redTankTurretTransform.rotation.z = newRotation; + + if (space.clock.time > lastRedBulletTime + redTankFiringInterval){ + lastRedBulletTime = space.clock.time; + var bulletBody = new box2d.Body({bodyDefinition: new box2d.BodyDefinition({bullet:true}), + fixtureDefinition: new box2d.FixtureDefinition( + { + shape:new box2d.CircleShape(0.25), + friction:0.1, + restitution:0.7, + filter:{categoryBits:2, maskBits:15} + })}); + bulletBody.tankBulletCollisions = 0; + var bulletFiringPoint = math.vector3.add(redTankBarrelTransform.toWorldPoint(), redTankBarrelTransform.pointToWorld([0.3,0,0])); + var newBullet = new Entity("bullet", + [ + new engine.core.Transform(bulletFiringPoint), + new cubicvr.Model(resources.bullet, resources.bulletMaterial), + bulletBody + ] + ); + bulletBody.onContactBegin = function(event){ + this.tankBulletCollisions++; + if (this.tankBulletCollisions === 2){ + //This is how you remove something from the space properly + this.owner.setActive(false); + space.remove(this.owner); + } + }; + space.add(newBullet); + bulletVelocity = [2,0,0]; + redTankBarrelTransform.pointToWorld(bulletVelocity, bulletVelocity); + var impEvent = new engine.Event('LinearImpulse',{impulse: [bulletVelocity[0], bulletVelocity[1]]}); + impEvent.dispatch(newBullet); + } + + if (redTank.doneMovement){ + //Done moving, make up a new destination + newPosition[0] = getRandom(-3, 3); + newPosition[1] = getRandom(-3, 3); + newPosition[2] = position.z; + //Uncomment this to make bullets appear at the tank's new destination. Useful for debugging +// space.add(new Entity("bullet", +// [ +// new engine.core.Transform(newPosition), +// new cubicvr.Model(resources.bullet, resources.bulletMaterial) +// ] +// )); + + //Multiply by negative 1 due to handedness differences between what atan2 will give us and what rotation.z is + var currentRotation = redTankTransform.rotation.z * -1; + var directionToNewPosition = Math.atan2(newPosition[1] - position.y, newPosition[0] - position.x); + + changeInDirection = removeExcessRotation(directionToNewPosition + currentRotation); + //Because we are only telling the tank to stop rotating/moving at the end of a frame, this does NOT result in deterministic movement + //The tank will turn/move more or less depending on how high the frame rate is + redTank.timeToRotate = Math.abs(changeInDirection)/tankRotationSpeed; + redTank.timeToMove = position.distance(newPosition) / tankMovementSpeed; + redTank.rotationDirection = changeInDirection > 0 ? 1 : -1; + redTank.doneRotation = false; + redTank.doneMovement = false; + physicsBody.setAngularVelocity(tankRotationSpeed * redTank.rotationDirection); + physicsBody.setLinearVelocity(0,0); + } + //Rotate until we reach the desired direction + if (!redTank.doneRotation){ + redTank.timeToRotate -= elapsedTime; + if (redTank.timeToRotate < 0){ + redTank.doneRotation = true; + redTank.tankVelocity = [tankMovementSpeed, 0, 0]; + redTankTransform.pointToWorld(redTank.tankVelocity, redTank.tankVelocity); + physicsBody.setAngularVelocity(0); + physicsBody.setLinearVelocity(redTank.tankVelocity[0], redTank.tankVelocity[1]); + } + } + //Move until we reach the desired destination + if (redTank.doneRotation){ + redTank.timeToMove -= elapsedTime; + if (redTank.timeToMove < 0){ + redTank.doneMovement = true; + physicsBody.setLinearVelocity(0,0); + } + } + } + }, { tags: ["@update"] - }).start(); + }); + task.start(); engine.resume(); } diff --git a/gladius-box2d.js b/gladius-box2d.js index cfa9b43..7d06dff 100644 --- a/gladius-box2d.js +++ b/gladius-box2d.js @@ -99613,7 +99613,6 @@ define('src/services/resolver',['require','base/service','core/event','_math','b }; Service.call( this, scheduler, schedules ); - options.gravity = options.gravity || [0, 0]; this.gravity = new Box2D.b2Vec2(); this.world = new Box2D.b2World( this.gravity ); this._timeStep = 30; // time step, in milliseconds @@ -99830,6 +99829,8 @@ define('src/components/body',['require','box2d','common/extend','base/component' var that = this; var i; + this.service = service; + if( options.bodyDefinition) { this.box2dBody = service.world.CreateBody( options.bodyDefinition ); } else { @@ -99855,12 +99856,28 @@ define('src/components/body',['require','box2d','common/extend','base/component' Body.prototype = new Component(); Body.prototype.constructor = Body; - var linearImpulse = new Box2D.b2Vec2( 0, 0 ); + var b2Vector = new Box2D.b2Vec2( 0, 0 ); + + function setAngularVelocity(rotation){ + this.box2dBody.SetAngularVelocity(rotation); + } + + function setLinearVelocity(arg1, arg2) { + var argc = arguments.length; + if( 1 === argc ) { + b2Vector.Set( arg1[0], arg1[1] ); + }else{ + b2Vector.Set( arg1, arg2); + } + this.box2dBody.SetLinearVelocity( b2Vector ); + b2Vector.Set( 0, 0 ); + } + function onLinearImpulse( event ) { var impulse = event.data.impulse; - linearImpulse.Set( impulse[0], impulse[1] ); - this.box2dBody.ApplyLinearImpulse( linearImpulse, this.box2dBody.GetPosition() ); - linearImpulse.Set( 0, 0 ); + b2Vector.Set( impulse[0], impulse[1] ); + this.box2dBody.ApplyLinearImpulse( b2Vector, this.box2dBody.GetPosition() ); + b2Vector.Set( 0, 0 ); } function onAngularImpulse( event ) { @@ -99871,7 +99888,7 @@ define('src/components/body',['require','box2d','common/extend','base/component' var position2 = this.box2dBody.GetPosition(); var angle2 = this.box2dBody.GetAngle(); - // TD: This will cause the transform to emit an event that we handle below. Blech! + var transform = this.owner.findComponent( "Transform" ); //Note: It is currently okay to read from buffers, but writing to them will result in things breaking transform.position = [ position2.get_x(), position2.get_y(), transform.position.buffer[2] ]; @@ -99928,6 +99945,8 @@ define('src/components/body',['require','box2d','common/extend','base/component' } var prototype = { + setAngularVelocity: setAngularVelocity, + setLinearVelocity: setLinearVelocity, onLinearImpulse: onLinearImpulse, onAngularImpulse: onAngularImpulse, onUpdate: onUpdate, @@ -100021,6 +100040,8 @@ define('src/resources/body-definition',['require','box2d'],function ( require ) var box2dBodyDef = new Box2D.b2BodyDef(); box2dBodyDef._gladius = {}; + box2dBodyDef.set_bullet(options.hasOwnProperty( 'bullet' ) ? + options.bullet : false); box2dBodyDef.set_type( options.hasOwnProperty( 'type' ) ? options.type : Box2D.b2_dynamicBody ); box2dBodyDef.set_linearDamping( options.hasOwnProperty( 'linearDamping' ) ? @@ -100058,6 +100079,20 @@ define('src/resources/fixture-definition',['require','box2d'],function ( require var box2dFixtureDef = new Box2D.b2FixtureDef(); box2dFixtureDef._gladius = {}; box2dFixtureDef.set_density( options.hasOwnProperty( 'density' ) ? options.density : 1 ); + box2dFixtureDef.set_friction( options.hasOwnProperty( 'friction' ) ? options.friction : 0.2); + box2dFixtureDef.set_restitution( options.hasOwnProperty( 'restitution' ) ? options.restitution : 0); + if (options.hasOwnProperty( 'filter' )){ + var filter = box2dFixtureDef.get_filter(); + if (options.filter.hasOwnProperty( 'groupIndex' )){ + filter.set_groupIndex(options.filter.groupIndex); + } + if (options.filter.hasOwnProperty( 'categoryBits' )){ + filter.set_categoryBits(options.filter.categoryBits); + } + if (options.filter.hasOwnProperty( 'maskBits' )){ + filter.set_maskBits(options.filter.maskBits); + } + } box2dFixtureDef.set_shape( options.shape ); return box2dFixtureDef; }; @@ -100073,8 +100108,8 @@ if ( typeof define !== "function" ) { define('src/resources/box-shape',['require','box2d'],function ( require ) { require( "box2d" ); var BoxShape = function( hx, hy ) { - hx = hx || 1; - hy = hy || 1; + hx = hx/2 || 0.5; + hy = hy/2 || 0.5; var box2dPolygonShape = new Box2D.b2PolygonShape(); box2dPolygonShape._gladius = {}; box2dPolygonShape.SetAsBox( hx, hy ); @@ -100082,11 +100117,26 @@ define('src/resources/box-shape',['require','box2d'],function ( require ) { }; return BoxShape; }); + +if ( typeof define !== "function" ) { + var define = require( "amdefine" )( module ); +} + +define('src/resources/circle-shape',['require','box2d'],function ( require ) { + require( "box2d" ); + var CircleShape = function( radius ) { + var box2dCircleShape = new Box2D.b2CircleShape(); + box2dCircleShape._gladius = {}; + box2dCircleShape.set_m_radius(radius); + return box2dCircleShape; + }; + return CircleShape; +}); if ( typeof define !== "function" ) { var define = require( "amdefine" )( module ); } -define('../src/gladius-box2d',['require','base/extension','src/services/resolver','src/components/body','src/components/force','src/resources/body-definition','src/resources/fixture-definition','src/resources/box-shape'],function ( require ) { +define('../src/gladius-box2d',['require','base/extension','src/services/resolver','src/components/body','src/components/force','src/resources/body-definition','src/resources/fixture-definition','src/resources/box-shape','src/resources/circle-shape'],function ( require ) { var Extension = require( "base/extension" ); @@ -100110,7 +100160,8 @@ define('../src/gladius-box2d',['require','base/extension','src/services/resolver resources: { "BodyDefinition": require( "src/resources/body-definition" ), "FixtureDefinition": require( "src/resources/fixture-definition" ), - "BoxShape": require( "src/resources/box-shape" ) + "BoxShape": require( "src/resources/box-shape" ), + "CircleShape": require( "src/resources/circle-shape" ) } }); diff --git a/gladius-core.js b/gladius-core.js index 1754244..d5be028 100644 --- a/gladius-core.js +++ b/gladius-core.js @@ -4490,6 +4490,11 @@ define('vector/vector2-api',['require','common/not-implemented','vector/v2'],fun return v; } + + function distance( v1, v2 ) { + return Math.sqrt((v1[0] - v2[0]) * (v1[0] - v2[0]) + + (v1[1] - v2[1]) * (v1[1] - v2[1])); + } function dot( v1, v2 ) { var r = 0; @@ -4526,7 +4531,24 @@ define('vector/vector2-api',['require','common/not-implemented','vector/v2'],fun return Math.sqrt( r ); } - + + function limit(v, max, result){ + result = result || new V2(); + var length; + length = Math.sqrt( v[0] * v[0] + + v[1] * v[1]); + + if (length > max){ + var ratio = max/length; + result[0] = v[0] * ratio; + result[1] = v[1] * ratio; + }else{ + result[0] = v[0]; + result[1] = v[1]; + } + return result; + } + function multiply( v, s, result ) { result = result || new V2(); @@ -4592,11 +4614,11 @@ define('vector/vector2-api',['require','common/not-implemented','vector/v2'],fun add: add, angle: angle, clear: clear, - distance: notImplemented, + distance: distance, dot: dot, equal: equal, length: length, - limit: notImplemented, + limit: limit, multiply: multiply, negate: negate, normalize: normalize, @@ -4698,6 +4720,16 @@ define('vector/vector2',['require','../../lib/lodash','common/not-implemented',' return new Vector2( this ); } + function distance(arg) { + var other; + if( arg instanceof Vector2 ) { + other = arg.buffer; + } else { + other = arg; + } + return vector2.distance(this.buffer, other); + } + function dot( arg ) { var other; if( arg instanceof Vector2 ) { @@ -4724,6 +4756,19 @@ define('vector/vector2',['require','../../lib/lodash','common/not-implemented',' return vector2.length( this.buffer ); } + function limit(max, result) { + result = result || this; + var other; + if( result instanceof Vector2 ) { + other = result.buffer; + result.modified = true; + } else { + other = result; + } + vector2.limit(this.buffer, max, other); + return result; + } + function multiply( arg, result ) { result = result || this; vector2.multiply( this.buffer, arg, result.buffer ); @@ -4806,10 +4851,11 @@ define('vector/vector2',['require','../../lib/lodash','common/not-implemented',' angle: angle, clear: clear, clone: clone, - distance: notImplemented, + distance: distance, dot: dot, equal: equal, length: length, + limit: limit, multiply: multiply, negate: negate, normalize: normalize, @@ -4930,6 +4976,12 @@ define('vector/vector3-api',['require','common/not-implemented','vector/v3'],fun return result; } + function distance( v1, v2 ) { + return Math.sqrt((v1[0] - v2[0]) * (v1[0] - v2[0]) + + (v1[1] - v2[1]) * (v1[1] - v2[1]) + + (v1[2] - v2[2]) * (v1[2] - v2[2])); + } + function dot( v1, v2 ) { return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2]; } @@ -4964,6 +5016,26 @@ define('vector/vector3-api',['require','common/not-implemented','vector/v3'],fun return Math.sqrt( r ); } + function limit(v, max, result){ + result = result || new V3(); + var length; + length = Math.sqrt( v[0] * v[0] + + v[1] * v[1] + + v[2] * v[2]); + + if (length > max){ + var ratio = max/length; + result[0] = v[0] * ratio; + result[1] = v[1] * ratio; + result[2] = v[2] * ratio; + }else{ + result[0] = v[0]; + result[1] = v[1]; + result[2] = v[2]; + } + return result; + } + function multiply( v, s, result ) { result = result || new V3(); @@ -5039,11 +5111,11 @@ define('vector/vector3-api',['require','common/not-implemented','vector/v3'],fun angle: angle, clear: clear, cross: cross, - distance: notImplemented, + distance: distance, dot: dot, equal: equal, length: length, - limit: notImplemented, + limit: limit, multiply: multiply, negate: negate, normalize: normalize, @@ -5165,6 +5237,16 @@ define('vector/vector3',['require','../../lib/lodash','common/not-implemented',' return this; } + function distance(arg) { + var other; + if( arg instanceof Vector3 ) { + other = arg.buffer; + } else { + other = arg; + } + return vector3.distance(this.buffer, other); + } + function dot( arg ) { var other; if( arg instanceof Vector3 ) { @@ -5191,6 +5273,19 @@ define('vector/vector3',['require','../../lib/lodash','common/not-implemented',' return vector3.length( this.buffer ); } + function limit(max, result) { + result = result || this; + var other; + if( result instanceof Vector3 ) { + other = result.buffer; + result.modified = true; + } else { + other = result; + } + vector3.limit(this.buffer, max, other); + return result; + } + function multiply( arg, result ) { result = result || this; vector3.multiply( this.buffer, arg, result.buffer ); @@ -5277,10 +5372,11 @@ define('vector/vector3',['require','../../lib/lodash','common/not-implemented',' clear: clear, clone: clone, cross: cross, - distance: notImplemented, + distance: distance, dot: dot, equal: equal, length: length, + limit: limit, multiply: multiply, negate: negate, normalize: normalize, @@ -5378,6 +5474,13 @@ define('vector/vector4-api',['require','common/not-implemented','vector/v4'],fun return v; } + function distance( v1, v2 ) { + return Math.sqrt((v1[0] - v2[0]) * (v1[0] - v2[0]) + + (v1[1] - v2[1]) * (v1[1] - v2[1]) + + (v1[2] - v2[2]) * (v1[2] - v2[2]) + + (v1[3] - v2[3]) * (v1[3] - v2[3])); + } + function dot( v1, v2 ) { return v1[0] * v2[0] + v1[1] * v2[1] + v1[2] * v2[2] + v1[3] * v2[3]; } @@ -5406,13 +5509,35 @@ define('vector/vector4-api',['require','common/not-implemented','vector/v4'],fun function length( v ) { var r = 0; - + r += v[0] * v[0]; r += v[1] * v[1]; r += v[2] * v[2]; - r += v[2] * v[2]; - - return Math.sqrt( r ); + r += v[3] * v[3]; + + return Math.sqrt( r ); + } + + function limit(v, max, result){ + result = result || new V4(); + var length; + length = Math.sqrt( v[0] * v[0] + + v[1] * v[1] + + v[2] * v[2] + + v[3] * v[3]); + if (length > max){ + var ratio = max/length; + result[0] = v[0] * ratio; + result[1] = v[1] * ratio; + result[2] = v[2] * ratio; + result[3] = v[3] * ratio; + }else{ + result[0] = v[0]; + result[1] = v[1]; + result[2] = v[2]; + result[3] = v[3]; + } + return result; } function multiply( v, s, result ) { @@ -5496,11 +5621,11 @@ define('vector/vector4-api',['require','common/not-implemented','vector/v4'],fun add: add, angle: angle, clear: clear, - distance: notImplemented, + distance: distance, dot: dot, equal: equal, length: length, - limit: notImplemented, + limit: limit, multiply: multiply, negate: negate, normalize: normalize, @@ -5613,6 +5738,16 @@ define('vector/vector4',['require','../../lib/lodash','common/not-implemented',' return new Vector4( this ); } + function distance(arg) { + var other; + if( arg instanceof Vector4 ) { + other = arg.buffer; + } else { + other = arg; + } + return vector4.distance(this.buffer, other); + } + function dot( arg ) { var other; if( arg instanceof Vector4 ) { @@ -5639,6 +5774,19 @@ define('vector/vector4',['require','../../lib/lodash','common/not-implemented',' return vector4.length( this.buffer ); } + function limit(max, result) { + result = result || this; + var other; + if( result instanceof Vector4 ) { + other = result.buffer; + result.modified = true; + } else { + other = result; + } + vector4.limit(this.buffer, max, other); + return result; + } + function multiply( arg, result ) { result = result || this; vector4.multiply( this.buffer, arg, result.buffer ); @@ -5727,10 +5875,11 @@ define('vector/vector4',['require','../../lib/lodash','common/not-implemented',' angle: angle, clear: clear, clone: clone, - distance: notImplemented, + distance: distance, dot: dot, equal: equal, length: length, + limit: limit, multiply: multiply, negate: negate, normalize: normalize, @@ -13953,7 +14102,7 @@ define('core/components/transform',['require','_math','common/extend','base/comp this.__defineSetter__( "position", function( value ) { this._position.set( value ); this._cachedLocalMatrixIsValid = false; - this._cachedWorldMatrixIsvalid = false; + this._cachedWorldMatrixIsValid = false; }); // Local rotation @@ -13964,7 +14113,7 @@ define('core/components/transform',['require','_math','common/extend','base/comp this.__defineSetter__( "rotation", function( value ) { this._rotation.set( value ); this._cachedLocalMatrixIsValid = false; - this._cachedWorldMatrixIsvalid = false; + this._cachedWorldMatrixIsValid = false; }); this._rotationMatrix = new math.transform.rotate( this._rotation ); this._rotationMatrixIsValid = true; @@ -13977,13 +14126,15 @@ define('core/components/transform',['require','_math','common/extend','base/comp this.__defineSetter__( "scale", function( value ) { this._scale.set( value ); this._cachedLocalMatrixIsValid = false; - this._cachedWorldMatrixIsvalid = false; + this._cachedWorldMatrixIsValid = false; }); this._cachedLocalMatrix = new math.T(); this._cachedLocalMatrixIsValid = false; this._cachedWorldMatrix = new math.T(); - this._cachedWorldMatrixIsvalid = false; + //TODO: Make the world matrix caching actually do something + this._cachedWorldMatrixIsValid = false; + this._tempMatrix = new math.T(); }; Transform.prototype = new Component(); Transform.prototype.constructor = Transform; @@ -14015,7 +14166,9 @@ define('core/components/transform',['require','_math','common/extend','base/comp return this._cachedWorldMatrix; } + //This calculates the rotation of the object relative to world space function computeWorldRotation(){ + //TODO: Add caching of results in here once we have a way of detecting changes in the parents if( this.owner && this.owner.parent && this.owner.parent.hasComponent( "Transform" ) ) { return math.matrix4.multiply(this.owner.parent.findComponent( "Transform").worldRotation(), @@ -14025,32 +14178,76 @@ define('core/components/transform',['require','_math','common/extend','base/comp } } - function directionToWorld(direction, result) { + //TODO: Should produce a unit vector showing the orientation of things in world space + function directionToWorld(){ + + } + + function pointToWorld(direction, result) { result = result || new math.V3(); - var transformedDirection = math.matrix4.multiply( + direction = direction || new math.V3(); + math.matrix4.multiply( computeWorldRotation.call(this), - math.transform.translate( direction )); - math.vector3.set(result, transformedDirection[3], transformedDirection[7], transformedDirection[11]); + math.transform.translate( direction ), + this._tempMatrix); + math.vector3.set(result, this._tempMatrix[3], this._tempMatrix[7], this._tempMatrix[11]); return result; } - function directionToLocal(direction, result) { + function pointToLocal(direction, result) { result = result || new math.V3(); - var transformedDirection = math.matrix4.multiply( - math.transform.rotate(this._rotation.buffer), - math.transform.translate( direction )); - math.vector3.set(result, transformedDirection[3], transformedDirection[7], transformedDirection[11]); + if( this.owner && this.owner.parent && + this.owner.parent.hasComponent( "Transform" ) ) { + var thisParentWorldMatrix = this.owner.parent.findComponent( "Transform").worldMatrix(); + //Multiply the inverse of the parent's world matrix by the other transform's world matrix, + // putting the result in the temp matrix + //Solution grabbed from http://www.macaronikazoo.com/?p=419 + math.matrix4.multiply(math.matrix4.inverse(thisParentWorldMatrix,this._tempMatrix), math.transform.translate(direction), this._tempMatrix); + //Subtract this turret's position so that everything is offset properly + math.vector3.set(result, this._tempMatrix[3] - this._position.buffer[0], this._tempMatrix[7] - this._position.buffer[1], this._tempMatrix[11] - this._position.buffer[2]); + } + else{ + math.vector3.set(result, direction[0], direction[1], direction[2]); + } + return result; + } + + function toWorldPoint() { + var worldMatrix = computeWorldMatrix.call(this); + return [worldMatrix[3], worldMatrix[7], worldMatrix[11]]; + } + + function relativeTo(otherTransform, result) + { + result = result || new math.V3(); + var otherWorldMatrix = otherTransform.worldMatrix(); + if( this.owner && this.owner.parent && + this.owner.parent.hasComponent( "Transform" ) ) { + var thisParentWorldMatrix = this.owner.parent.findComponent( "Transform").worldMatrix(); + //Multiply the inverse of the parent's world matrix by the other transform's world matrix, + // putting the result in the temp matrix + // Solution grabbed from http://www.macaronikazoo.com/?p=419 + math.matrix4.multiply(math.matrix4.inverse(thisParentWorldMatrix,this._tempMatrix), otherWorldMatrix, this._tempMatrix); + //Subtract this turret's position so that everything is offset properly + math.vector3.set(result, this._tempMatrix[3] - this._position.buffer[0], this._tempMatrix[7] - this._position.buffer[1], this._tempMatrix[11] - this._position.buffer[2]); + } + else{ + math.vector3.set(result, otherWorldMatrix[3], otherWorldMatrix[7], otherWorldMatrix[11]); + } return result; } var prototype = { + //TODO: worldMatrix and localMatrix look like property accessors from the outside but are actually methods. This should be changed, either so that they are accessed like properties or look like methods worldMatrix: computeWorldMatrix, localMatrix: computeLocalMatrix, - directionToLocal: directionToLocal, - directionToWorld: directionToWorld, + pointToLocal: pointToLocal, + pointToWorld: pointToWorld, + directionToWorld: undefined, + //Same thing goes for this one. worldRotation: computeWorldRotation, - toWorldPoint: undefined, - toLocalPoint: undefined, + relativeTo: relativeTo, + toWorldPoint: toWorldPoint, lookAt: undefined, target: undefined, // Direction constants