From ebd62ece4cbe4700b45d0d4a311a69f42e45c399 Mon Sep 17 00:00:00 2001 From: David Perit Date: Wed, 4 Jul 2012 17:13:15 -0400 Subject: [PATCH 01/19] Added a rotating turret Added a second tank which is coloured red Added 4 walls around the arena --- examples/assets/images/red-tank-diffuse.jpg | Bin 0 -> 32917 bytes examples/tank/tank-controls.json | 4 +- examples/tank/tank.js | 196 ++++++++++++++------ 3 files changed, 144 insertions(+), 56 deletions(-) create mode 100644 examples/assets/images/red-tank-diffuse.jpg diff --git a/examples/assets/images/red-tank-diffuse.jpg b/examples/assets/images/red-tank-diffuse.jpg new file mode 100644 index 0000000000000000000000000000000000000000..685cc4120cf97be9a565182d83c6e9576e2fafa5 GIT binary patch literal 32917 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 z Date: Wed, 8 Aug 2012 11:51:51 -0400 Subject: [PATCH 02/19] Removed a pair of unnecessary lines from tank.js --- examples/tank/tank.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/examples/tank/tank.js b/examples/tank/tank.js index be926ea..1cf42dc 100644 --- a/examples/tank/tank.js +++ b/examples/tank/tank.js @@ -146,7 +146,6 @@ document.addEventListener( "DOMContentLoaded", function( e ) { transform.position.add( transform.directionToLocal( [0, space.clock.delta * -0.001, 0] )); } else { console.log( this.owner.id, "Turn left!" ); - var rotation = transform.rotation; transform.rotation.add([0, 0, space.clock.delta * -0.001] ); } } @@ -156,7 +155,6 @@ document.addEventListener( "DOMContentLoaded", function( e ) { transform.position.add( transform.directionToLocal( [0, space.clock.delta * 0.001, 0] )); } else { console.log( this.owner.id, "Turn right!" ); - var rotation = transform.rotation; transform.rotation.add([0, 0, space.clock.delta * 0.001] ); } } From e45d1264b7c6bad7797696c9c0315cd977d88508 Mon Sep 17 00:00:00 2001 From: David Perit Date: Wed, 8 Aug 2012 17:51:34 -0400 Subject: [PATCH 03/19] Added physics, bullets to tank.js, fixed an input bug in it Updated options for box2d in cube-collision and tank to take advantage of dimension mapping Added newer versions of libraries --- examples/cube-collision/cube-collision.js | 4 +- examples/tank/tank.js | 109 ++++++++++++++-------- gladius-box2d.js | 31 +++++- gladius-core.js | 7 +- 4 files changed, 105 insertions(+), 46 deletions(-) diff --git a/examples/cube-collision/cube-collision.js b/examples/cube-collision/cube-collision.js index db393e7..19bb100 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 = {}; diff --git a/examples/tank/tank.js b/examples/tank/tank.js index de9faab..fbe32ba 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(); @@ -36,11 +37,18 @@ document.addEventListener( "DOMContentLoaded", function( e ) { } } engine.registerExtension( inputExtension, inputOptions ); + //Need to find a way to make this property access longer :) + engine.registerExtension( box2dExtension, {resolver: {dimensionMap: box2dExtension.services.resolver.service.prototype.DimensionMaps.XZ}}); 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'; @@ -105,6 +113,16 @@ document.addEventListener( "DOMContentLoaded", function( e ) { onfailure: function( error ) { } }, + { + type: cubicvr.Mesh, + url: "../assets/procedural-prism.js?length=0.5&width=0.5&depth=0.5", + load: engine.loaders.procedural, + onsuccess: function( mesh ) { + resources.bullet = mesh; + }, + onfailure: function( error ) { + } + }, { type: cubicvr.MaterialDefinition, url: "../assets/procedural-material.js" + materialArgs, @@ -135,6 +153,16 @@ document.addEventListener( "DOMContentLoaded", function( e ) { 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", @@ -157,6 +185,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { 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 tankMovementSpeed = 0.003; @@ -178,44 +207,50 @@ document.addEventListener( "DOMContentLoaded", function( e ) { var turretTransform = space.findNamed ("tank-turret").findComponent( "Transform" ); if( controller.states["MoveForward"] ) { console.log( this.owner.id, "Move forward!" ); - transform.position.add( transform.directionToLocal( [space.clock.delta * 0.001, 0, 0] ) ); + transform.position.add( transform.directionToLocal( [space.clock.delta * tankMovementSpeed, 0, 0] ) ); } if( controller.states["MoveBackward"] ) { console.log( this.owner.id, "Move backward!" ); - transform.position.add( transform.directionToLocal( [space.clock.delta * -0.001, 0, 0] )); + transform.position.add( transform.directionToLocal( [space.clock.delta * -tankMovementSpeed, 0, 0] )); } 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] )); + transform.position.add( transform.directionToLocal( [0, space.clock.delta * -tankMovementSpeed, 0] )); } else { console.log( this.owner.id, "Turn left!" ); - transform.rotation.add([0, 0, space.clock.delta * -0.001] ); + transform.rotation.add([0, 0, space.clock.delta * -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] )); + transform.position.add( transform.directionToLocal( [0, space.clock.delta * tankMovementSpeed, 0] )); } else { console.log( this.owner.id, "Turn right!" ); - transform.rotation.add([0, 0, space.clock.delta * 0.001] ); + transform.rotation.add([0, 0, space.clock.delta * tankRotationSpeed] ); } } if (controller.states["TurnTurretLeft"] ) { console.log( this.owner.id, "Turret turn left!" ); - var rotation = turretTransform.rotation; - turretTransform.setRotation( math.vector3.add( rotation, [0, 0, space.clock.delta * -turretRotationSpeed] ) ); + turretTransform.rotation.add([0, 0, space.clock.delta * -turretRotationSpeed]); } if (controller.states["TurnTurretRight"] ) { console.log( this.owner.id, "Turret turn right!" ); - var rotation = turretTransform.rotation; - turretTransform.setRotation( math.vector3.add( rotation, [0, 0, space.clock.delta * turretRotationSpeed] ) ); + turretTransform.rotation.add([0, 0, space.clock.delta * turretRotationSpeed]); } } }, "Fire": function( event ) { console.log( this.owner.id, "Fire!" ); + space.add(new Entity("bullet", + [ + new engine.core.Transform(space.findNamed ("tank-barrel").findComponent( "Transform").toWorldPoint()), + new cubicvr.Model(resources.bullet, resources.bulletMaterial), + new box2d.Body({bodyDefinition: new box2d.BodyDefinition(), + fixtureDefinition: new box2d.FixtureDefinition({shape:new box2d.BoxShape(0.5, 0.5)})}) + ] + )); } }; @@ -225,7 +260,6 @@ document.addEventListener( "DOMContentLoaded", function( e ) { space.add(new Entity(name, [ new engine.core.Transform(position, [math.TAU / 4, 0, 0], [0.5, 0.5, 0.5]), - new input.Controller(resources.tankControls), new engine.logic.Actor(tankLogic) ], [name] @@ -277,48 +311,48 @@ document.addEventListener( "DOMContentLoaded", function( e ) { createTank("tank", [-4,0,-4], resources.material, true); createTank("red-tank", [4,0,4], resources.redMaterial, false); - //TODO: Make these walls have tiling textures. - // TODO: Add in physics bounding boxes for them + //TODO: Make these walls have tiling textures + //TODO: Add in physics bounding boxes for them + var bodyDefinition = new box2d.BodyDefinition({type:box2d.BodyDefinition.BodyTypes.STATIC}); + var fixtureDefinition = new box2d.FixtureDefinition({shape:new box2d.BoxShape(10,1)}); + + var body = new box2d.Body({bodyDefinition: bodyDefinition, fixtureDefinition: fixtureDefinition}); + + body.onContactBegin = function(event){ + console.log("First cube number " + cubeIndex + " contact begin"); + }; + body.onContactEnd = function(event){ + console.log("First cube number " + cubeIndex + " contact end"); + }; + space.add( new Entity( "wallLeft", [ new engine.core.Transform([-5,0,0], [0,math.TAU/4,0]), - new cubicvr.Model(resources.wall, resources.wallMaterial) + new cubicvr.Model(resources.wall, resources.wallMaterial), + new box2d.Body({bodyDefinition: bodyDefinition, fixtureDefinition: fixtureDefinition}) ] )); space.add( new Entity( "wallRight", [ new engine.core.Transform([5,0,0], [0,math.TAU/4,0]), - new cubicvr.Model(resources.wall, resources.wallMaterial) + new cubicvr.Model(resources.wall, resources.wallMaterial), + new box2d.Body({bodyDefinition: bodyDefinition, fixtureDefinition: fixtureDefinition}) ] )); space.add( new Entity( "wallTop", [ new engine.core.Transform([0,0,-5], [0,0,0]), - new cubicvr.Model(resources.wall, resources.wallMaterial) + new cubicvr.Model(resources.wall, resources.wallMaterial), + new box2d.Body({bodyDefinition: bodyDefinition, fixtureDefinition: fixtureDefinition}) ] )); space.add( new Entity( "wallBottom", [ new engine.core.Transform([0,0,5], [0,0,0]), - new cubicvr.Model(resources.wall, resources.wallMaterial) + new cubicvr.Model(resources.wall, resources.wallMaterial), + new box2d.Body({bodyDefinition: bodyDefinition, fixtureDefinition: fixtureDefinition}) ] )); - space.add( new Entity( "tank-turret", - [ - new engine.core.Transform( [-0.2, 0, -0.6] ), - new cubicvr.Model( resources.tankTurret, resources.material ) - ], - ["tank"], - space.findNamed( "tank-body" ) - )); - space.add( new Entity( "tank-barrel", - [ - new engine.core.Transform( [0.8, 0, 0] ), - new cubicvr.Model( resources.tankBarrel, resources.material ) - ], - ["tank"], - space.findNamed( "tank-turret" ) - )); space.add( new Entity( "camera", [ @@ -329,11 +363,6 @@ document.addEventListener( "DOMContentLoaded", function( e ) { )); // space.findNamed( "camera" ).findComponent( "Camera" ).setTarget( 0, 0, 0 ); - var task = new engine.FunctionTask( function() { - }, { - tags: ["@update"] - }).start(); - engine.resume(); } diff --git a/gladius-box2d.js b/gladius-box2d.js index cfa9b43..9394a18 100644 --- a/gladius-box2d.js +++ b/gladius-box2d.js @@ -99616,6 +99616,7 @@ define('src/services/resolver',['require','base/service','core/event','_math','b options.gravity = options.gravity || [0, 0]; this.gravity = new Box2D.b2Vec2(); this.world = new Box2D.b2World( this.gravity ); + this.dimensionMap = options.dimensionMap || 0; this._timeStep = 30; // time step, in milliseconds this._timeRemaining = 0; // time remaining from last frame, in milliseconds @@ -99672,6 +99673,12 @@ define('src/services/resolver',['require','base/service','core/event','_math','b var totalForce = new math.Vector2(); + var DimensionMaps = { + XY: 0, + XZ: 1, + YZ: 2 + }; + function resolve() { var component; @@ -99717,6 +99724,7 @@ define('src/services/resolver',['require','base/service','core/event','_math','b Resolver.prototype = new Service(); Resolver.prototype.constructor = Resolver; Resolver.prototype.resolve = resolve; + Resolver.prototype.DimensionMaps = DimensionMaps; return Resolver; @@ -99830,6 +99838,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 { @@ -99856,6 +99866,7 @@ define('src/components/body',['require','box2d','common/extend','base/component' Body.prototype.constructor = Body; var linearImpulse = new Box2D.b2Vec2( 0, 0 ); + function onLinearImpulse( event ) { var impulse = event.data.impulse; linearImpulse.Set( impulse[0], impulse[1] ); @@ -99874,8 +99885,16 @@ define('src/components/body',['require','box2d','common/extend','base/component' // 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] ]; - transform.rotation.z = angle2; + if (this.service.dimensionMap === this.service.DimensionMaps.XY){ + transform.position = [ position2.get_x(), position2.get_y(), transform.position.buffer[2] ]; + transform.rotation.z = angle2; + }else if (this.service.dimensionMap === this.service.DimensionMaps.XZ){ + transform.position = [ position2.get_x(), transform.position.buffer[1], position2.get_y()]; + transform.rotation.y = angle2; + }else{ + transform.position = [transform.position.buffer[0], position2.get_y(), position2.get_x()]; + transform.rotation.x = angle2; + } } function onEntitySpaceChanged( event ) { @@ -99904,7 +99923,13 @@ define('src/components/body',['require','box2d','common/extend','base/component' if( this.owner ) { var transform = this.owner.findComponent( 'Transform' ); //Note: It is currently okay to read from buffers, but writing to them will result in things breaking - this.box2dBody.SetTransform( new Box2D.b2Vec2( transform.position.buffer[0], transform.position.buffer[1] ), transform.rotation.buffer[2] ); + if (this.service.dimensionMap === this.service.DimensionMaps.XY){ + this.box2dBody.SetTransform( new Box2D.b2Vec2( transform.position.buffer[0], transform.position.buffer[1] ), transform.rotation.buffer[2] ); + }else if (this.service.dimensionMap === this.service.DimensionMaps.XZ){ + this.box2dBody.SetTransform( new Box2D.b2Vec2( transform.position.buffer[0], transform.position.buffer[2] ), transform.rotation.buffer[1] ); + }else{ + this.box2dBody.SetTransform( new Box2D.b2Vec2( transform.position.buffer[2], transform.position.buffer[1] ), transform.rotation.buffer[0] ); + } } if( this.owner === null && data.previous !== null ) { diff --git a/gladius-core.js b/gladius-core.js index 1754244..f89528b 100644 --- a/gladius-core.js +++ b/gladius-core.js @@ -14043,13 +14043,18 @@ define('core/components/transform',['require','_math','common/extend','base/comp return result; } + function toWorldPoint() { + var worldMatrix = computeWorldMatrix.call(this); + return [worldMatrix[3], worldMatrix[7], worldMatrix[11]]; + } + var prototype = { worldMatrix: computeWorldMatrix, localMatrix: computeLocalMatrix, directionToLocal: directionToLocal, directionToWorld: directionToWorld, worldRotation: computeWorldRotation, - toWorldPoint: undefined, + toWorldPoint: toWorldPoint, toLocalPoint: undefined, lookAt: undefined, target: undefined, From 77c90fb5a6f3f29816e68f6073d241486fa6a7ca Mon Sep 17 00:00:00 2001 From: David Perit Date: Thu, 9 Aug 2012 16:52:33 -0400 Subject: [PATCH 04/19] Made space actually fire bullets with velocity Added new version of libraries --- examples/tank/tank.js | 9 +++++++-- gladius-box2d.js | 6 ++---- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/examples/tank/tank.js b/examples/tank/tank.js index fbe32ba..cf91967 100644 --- a/examples/tank/tank.js +++ b/examples/tank/tank.js @@ -243,14 +243,19 @@ document.addEventListener( "DOMContentLoaded", function( e ) { }, "Fire": function( event ) { console.log( this.owner.id, "Fire!" ); - space.add(new Entity("bullet", + var newBullet = new Entity("bullet", [ new engine.core.Transform(space.findNamed ("tank-barrel").findComponent( "Transform").toWorldPoint()), new cubicvr.Model(resources.bullet, resources.bulletMaterial), new box2d.Body({bodyDefinition: new box2d.BodyDefinition(), fixtureDefinition: new box2d.FixtureDefinition({shape:new box2d.BoxShape(0.5, 0.5)})}) ] - )); + ); + space.add(newBullet); + var bulletVelocity = [3,0,0]; + space.findNamed("tank-barrel").findComponent( "Transform").directionToWorld(bulletVelocity, bulletVelocity); + var impEvent = new engine.Event('LinearImpulse',{impulse: [bulletVelocity[0], bulletVelocity[2]]}); + impEvent.dispatch(newBullet); } }; diff --git a/gladius-box2d.js b/gladius-box2d.js index 9394a18..3fe418a 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.dimensionMap = options.dimensionMap || 0; @@ -99866,7 +99865,6 @@ define('src/components/body',['require','box2d','common/extend','base/component' Body.prototype.constructor = Body; var linearImpulse = new Box2D.b2Vec2( 0, 0 ); - function onLinearImpulse( event ) { var impulse = event.data.impulse; linearImpulse.Set( impulse[0], impulse[1] ); @@ -100098,8 +100096,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 ); From ebe4d800cb72cfffff54dcd9bd3e87da592b4ccd Mon Sep 17 00:00:00 2001 From: David Perit Date: Fri, 10 Aug 2012 15:52:50 -0400 Subject: [PATCH 05/19] Caused bullets to be removed after 5 collisions Limited tank firing speed Remove console.log commands --- examples/tank/tank.js | 57 +++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/examples/tank/tank.js b/examples/tank/tank.js index cf91967..5b9dd92 100644 --- a/examples/tank/tank.js +++ b/examples/tank/tank.js @@ -188,6 +188,8 @@ document.addEventListener( "DOMContentLoaded", function( e ) { var box2d = engine.findExtension( "gladius-box2d" ); var Entity = engine.Entity; + var lastBulletTime = 0; + var tankFiringInterval = 500; var tankMovementSpeed = 0.003; var tankRotationSpeed = 0.002; var turretRotationSpeed = 0.002; @@ -206,56 +208,60 @@ document.addEventListener( "DOMContentLoaded", function( e ) { var transform = space.findNamed( "tank-body" ).findComponent( "Transform" ); var turretTransform = space.findNamed ("tank-turret").findComponent( "Transform" ); if( controller.states["MoveForward"] ) { - console.log( this.owner.id, "Move forward!" ); transform.position.add( transform.directionToLocal( [space.clock.delta * tankMovementSpeed, 0, 0] ) ); } if( controller.states["MoveBackward"] ) { - console.log( this.owner.id, "Move backward!" ); transform.position.add( transform.directionToLocal( [space.clock.delta * -tankMovementSpeed, 0, 0] )); } if( controller.states["TurnLeft"] ) { if( controller.states["StrafeModifier"] ) { - console.log( this.owner.id, "Strafe left!" ); transform.position.add( transform.directionToLocal( [0, space.clock.delta * -tankMovementSpeed, 0] )); } else { - console.log( this.owner.id, "Turn left!" ); transform.rotation.add([0, 0, space.clock.delta * -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 * tankMovementSpeed, 0] )); } else { - console.log( this.owner.id, "Turn right!" ); transform.rotation.add([0, 0, space.clock.delta * tankRotationSpeed] ); } } if (controller.states["TurnTurretLeft"] ) { - console.log( this.owner.id, "Turret turn left!" ); turretTransform.rotation.add([0, 0, space.clock.delta * -turretRotationSpeed]); } if (controller.states["TurnTurretRight"] ) { - console.log( this.owner.id, "Turret turn right!" ); turretTransform.rotation.add([0, 0, space.clock.delta * turretRotationSpeed]); } } }, "Fire": function( event ) { - console.log( this.owner.id, "Fire!" ); - var newBullet = new Entity("bullet", - [ - new engine.core.Transform(space.findNamed ("tank-barrel").findComponent( "Transform").toWorldPoint()), - new cubicvr.Model(resources.bullet, resources.bulletMaterial), - new box2d.Body({bodyDefinition: new box2d.BodyDefinition(), - fixtureDefinition: new box2d.FixtureDefinition({shape:new box2d.BoxShape(0.5, 0.5)})}) - ] - ); - space.add(newBullet); - var bulletVelocity = [3,0,0]; - space.findNamed("tank-barrel").findComponent( "Transform").directionToWorld(bulletVelocity, bulletVelocity); - var impEvent = new engine.Event('LinearImpulse',{impulse: [bulletVelocity[0], bulletVelocity[2]]}); - impEvent.dispatch(newBullet); + if (space.clock.time - tankFiringInterval > lastBulletTime){ + lastBulletTime = space.clock.time; + var physicsBody = new box2d.Body({bodyDefinition: new box2d.BodyDefinition(), + fixtureDefinition: new box2d.FixtureDefinition({shape:new box2d.BoxShape(0.5, 0.5)})}); + physicsBody.tankBulletCollisions = 0; + var newBullet = new Entity("bullet", + [ + new engine.core.Transform(space.findNamed ("tank-barrel").findComponent( "Transform").toWorldPoint()), + new cubicvr.Model(resources.bullet, resources.bulletMaterial), + physicsBody + ] + ); + physicsBody.onContactBegin = function(event){ + this.tankBulletCollisions++; + if (this.tankBulletCollisions === 5){ + //This is how you remove something from the space properly + this.owner.setActive(false); + space.remove(this.owner); + } + }; + space.add(newBullet); + var bulletVelocity = [3,0,0]; + space.findNamed("tank-barrel").findComponent( "Transform").directionToWorld(bulletVelocity, bulletVelocity); + var impEvent = new engine.Event('LinearImpulse',{impulse: [bulletVelocity[0], bulletVelocity[2]]}); + impEvent.dispatch(newBullet); + } } }; @@ -323,13 +329,6 @@ document.addEventListener( "DOMContentLoaded", function( e ) { var body = new box2d.Body({bodyDefinition: bodyDefinition, fixtureDefinition: fixtureDefinition}); - body.onContactBegin = function(event){ - console.log("First cube number " + cubeIndex + " contact begin"); - }; - body.onContactEnd = function(event){ - console.log("First cube number " + cubeIndex + " contact end"); - }; - space.add( new Entity( "wallLeft", [ new engine.core.Transform([-5,0,0], [0,math.TAU/4,0]), From e6cdf43d45c450c564846370636cc2eb9fc7eac1 Mon Sep 17 00:00:00 2001 From: David Perit Date: Fri, 10 Aug 2012 17:10:55 -0400 Subject: [PATCH 06/19] Turned bullets into spheres Added a procedural sphere creator Added new version of physics library --- examples/assets/procedural-sphere.js | 26 ++++++++++++++++++++++++++ examples/tank/tank.js | 4 ++-- gladius-box2d.js | 20 ++++++++++++++++++-- 3 files changed, 46 insertions(+), 4 deletions(-) create mode 100644 examples/assets/procedural-sphere.js 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/tank/tank.js b/examples/tank/tank.js index 5b9dd92..2221d96 100644 --- a/examples/tank/tank.js +++ b/examples/tank/tank.js @@ -115,7 +115,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { }, { type: cubicvr.Mesh, - url: "../assets/procedural-prism.js?length=0.5&width=0.5&depth=0.5", + url: "../assets/procedural-sphere.js?type=sphere&radius=0.25", load: engine.loaders.procedural, onsuccess: function( mesh ) { resources.bullet = mesh; @@ -239,7 +239,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { if (space.clock.time - tankFiringInterval > lastBulletTime){ lastBulletTime = space.clock.time; var physicsBody = new box2d.Body({bodyDefinition: new box2d.BodyDefinition(), - fixtureDefinition: new box2d.FixtureDefinition({shape:new box2d.BoxShape(0.5, 0.5)})}); + fixtureDefinition: new box2d.FixtureDefinition({shape:new box2d.CircleShape(0.25)})}); physicsBody.tankBulletCollisions = 0; var newBullet = new Entity("bullet", [ diff --git a/gladius-box2d.js b/gladius-box2d.js index 3fe418a..f96cfa9 100644 --- a/gladius-box2d.js +++ b/gladius-box2d.js @@ -100105,11 +100105,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" ); @@ -100133,7 +100148,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" ) } }); From 00bf718d996bb7df3f144ee3bfe94e1a0b7edd7e Mon Sep 17 00:00:00 2001 From: David Perit Date: Mon, 13 Aug 2012 15:49:07 -0400 Subject: [PATCH 07/19] Re-did tank movement so that it is done through the physics object using setLinearVelocity and setAngularVelocity Made tanks have physics objects attached Removed scaling from tanks Added new version of box2d library --- examples/tank/tank.js | 56 +++++++++++++++++++++++++++---------------- gladius-box2d.js | 28 ++++++++++++++++++---- 2 files changed, 59 insertions(+), 25 deletions(-) diff --git a/examples/tank/tank.js b/examples/tank/tank.js index 2221d96..c7f9390 100644 --- a/examples/tank/tank.js +++ b/examples/tank/tank.js @@ -65,7 +65,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { [ { 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; @@ -75,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; @@ -85,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; @@ -95,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; @@ -190,10 +190,13 @@ document.addEventListener( "DOMContentLoaded", function( e ) { var lastBulletTime = 0; var tankFiringInterval = 500; - var tankMovementSpeed = 0.003; - var tankRotationSpeed = 0.002; + var tankMovementSpeed = 3; + var tankRotationSpeed = 2; var turretRotationSpeed = 0.002; + var tankVelocity = [0,0,0]; + var rotation = 0; + var lightDefinition = new cubicvr.LightDefinition({ intensity: 1.5, distance: 30, @@ -205,28 +208,40 @@ document.addEventListener( "DOMContentLoaded", function( e ) { "Update": function( event ) { if( this.owner.hasComponent( "Controller" ) ) { var controller = this.owner.findComponent( "Controller" ); + var physBody = this.owner.findComponent( "Body" ); var transform = space.findNamed( "tank-body" ).findComponent( "Transform" ); var turretTransform = space.findNamed ("tank-turret").findComponent( "Transform" ); + tankVelocity[0] = 0; + tankVelocity[1] = 0; + tankVelocity[2] = 0; + rotation = 0; + if( controller.states["MoveForward"] ) { - transform.position.add( transform.directionToLocal( [space.clock.delta * tankMovementSpeed, 0, 0] ) ); +// transform.position.add( transform.directionToLocal( +// [space.clock.delta * tankMovementSpeed, 0, 0] ) ); + tankVelocity[0]+=tankMovementSpeed; } if( controller.states["MoveBackward"] ) { - transform.position.add( transform.directionToLocal( [space.clock.delta * -tankMovementSpeed, 0, 0] )); + tankVelocity[0]-=tankMovementSpeed; } + if( controller.states["TurnLeft"] ) { if( controller.states["StrafeModifier"] ) { - transform.position.add( transform.directionToLocal( [0, space.clock.delta * -tankMovementSpeed, 0] )); + tankVelocity[2]-=tankMovementSpeed; } else { - transform.rotation.add([0, 0, space.clock.delta * -tankRotationSpeed] ); + rotation+=tankRotationSpeed; } } if( controller.states["TurnRight"] ) { if( controller.states["StrafeModifier"] ) { - transform.position.add( transform.directionToLocal( [0, space.clock.delta * tankMovementSpeed, 0] )); + tankVelocity[2]+=tankMovementSpeed; } else { - transform.rotation.add([0, 0, space.clock.delta * tankRotationSpeed] ); + rotation-=tankRotationSpeed; } } + transform.directionToWorld(tankVelocity, tankVelocity); + physBody.setLinearVelocity(tankVelocity[0],tankVelocity[2]); + physBody.setAngularVelocity(rotation); if (controller.states["TurnTurretLeft"] ) { turretTransform.rotation.add([0, 0, space.clock.delta * -turretRotationSpeed]); } @@ -257,7 +272,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { } }; space.add(newBullet); - var bulletVelocity = [3,0,0]; + var bulletVelocity = [1,0,0]; space.findNamed("tank-barrel").findComponent( "Transform").directionToWorld(bulletVelocity, bulletVelocity); var impEvent = new engine.Event('LinearImpulse',{impulse: [bulletVelocity[0], bulletVelocity[2]]}); impEvent.dispatch(newBullet); @@ -270,8 +285,10 @@ document.addEventListener( "DOMContentLoaded", function( e ) { // tank, and handle game logic events space.add(new Entity(name, [ - new engine.core.Transform(position, [math.TAU / 4, 0, 0], [0.5, 0.5, 0.5]), - new engine.logic.Actor(tankLogic) + new engine.core.Transform(position, [math.TAU / 4, 0, 0]), + new engine.logic.Actor(tankLogic), + new box2d.Body({bodyDefinition: new box2d.BodyDefinition(), + fixtureDefinition: new box2d.FixtureDefinition({shape:new box2d.BoxShape(1,1)})}) ], [name] )); @@ -288,7 +305,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { )); space.add(new Entity(name + "-tread", [ - new engine.core.Transform([0, 0.8, 0]), + new engine.core.Transform([0, 0.4, 0]), new cubicvr.Model(resources.tankTread, material) ], [name], @@ -296,7 +313,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { )); space.add(new Entity(name + "-tread", [ - new engine.core.Transform([0, -0.8, 0]), + new engine.core.Transform([0, -0.4, 0]), new cubicvr.Model(resources.tankTread, material) ], [name], @@ -304,7 +321,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { )); space.add(new Entity(name+"-turret", [ - new engine.core.Transform([-0.2, 0, -0.6]), + new engine.core.Transform([-0.1, 0, -0.3]), new cubicvr.Model(resources.tankTurret, material) ], [name], @@ -312,7 +329,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { )); space.add(new Entity(name + "-barrel", [ - new engine.core.Transform([0.8, 0, 0]), + new engine.core.Transform([0.4, 0, 0]), new cubicvr.Model(resources.tankBarrel, material) ], [name], @@ -323,7 +340,6 @@ document.addEventListener( "DOMContentLoaded", function( e ) { createTank("red-tank", [4,0,4], resources.redMaterial, false); //TODO: Make these walls have tiling textures - //TODO: Add in physics bounding boxes for them var bodyDefinition = new box2d.BodyDefinition({type:box2d.BodyDefinition.BodyTypes.STATIC}); var fixtureDefinition = new box2d.FixtureDefinition({shape:new box2d.BoxShape(10,1)}); diff --git a/gladius-box2d.js b/gladius-box2d.js index f96cfa9..d39dad1 100644 --- a/gladius-box2d.js +++ b/gladius-box2d.js @@ -99864,12 +99864,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 linearVector = new Box2D.b2Vec2( 0, 0 ); + + function setAngularVelocity(rotation){ + this.box2dBody.SetAngularVelocity(rotation); + } + + function setLinearVelocity(arg1, arg2) { + var argc = arguments.length; + if( 1 === argc ) { + linearVector.Set( arg1[0], arg1[1] ); + }else{ + linearVector.Set( arg1, arg2); + } + this.box2dBody.SetLinearVelocity( linearVector ); + linearVector.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 ); + linearVector.Set( impulse[0], impulse[1] ); + this.box2dBody.ApplyLinearImpulse( linearVector, this.box2dBody.GetPosition() ); + linearVector.Set( 0, 0 ); } function onAngularImpulse( event ) { @@ -99880,7 +99896,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 if (this.service.dimensionMap === this.service.DimensionMaps.XY){ @@ -99951,6 +99967,8 @@ define('src/components/body',['require','box2d','common/extend','base/component' } var prototype = { + setAngularVelocity: setAngularVelocity, + setLinearVelocity: setLinearVelocity, onLinearImpulse: onLinearImpulse, onAngularImpulse: onAngularImpulse, onUpdate: onUpdate, From 5553a4b1dd74899f4022ee6391115b72d7969b22 Mon Sep 17 00:00:00 2001 From: David Perit Date: Mon, 13 Aug 2012 16:55:33 -0400 Subject: [PATCH 08/19] Set tank projectiles to have the bullet option in their bodyDefinition set to true. This causes them to do better collision detection against other dynamic objects. Moved the bullet velocity property out to be grouped with the other properties --- examples/tank/tank.js | 10 +++++++--- gladius-box2d.js | 3 +++ 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/examples/tank/tank.js b/examples/tank/tank.js index c7f9390..ce02f81 100644 --- a/examples/tank/tank.js +++ b/examples/tank/tank.js @@ -193,6 +193,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { var tankMovementSpeed = 3; var tankRotationSpeed = 2; var turretRotationSpeed = 0.002; + var bulletVelocity = [3,0,0]; var tankVelocity = [0,0,0]; var rotation = 0; @@ -253,8 +254,12 @@ document.addEventListener( "DOMContentLoaded", function( e ) { "Fire": function( event ) { if (space.clock.time - tankFiringInterval > lastBulletTime){ lastBulletTime = space.clock.time; - var physicsBody = new box2d.Body({bodyDefinition: new box2d.BodyDefinition(), - fixtureDefinition: new box2d.FixtureDefinition({shape:new box2d.CircleShape(0.25)})}); + var physicsBody = new box2d.Body({bodyDefinition: new box2d.BodyDefinition({bullet:true}), + fixtureDefinition: new box2d.FixtureDefinition( + { + shape:new box2d.CircleShape(0.25), + friction:0.3 + })}); physicsBody.tankBulletCollisions = 0; var newBullet = new Entity("bullet", [ @@ -272,7 +277,6 @@ document.addEventListener( "DOMContentLoaded", function( e ) { } }; space.add(newBullet); - var bulletVelocity = [1,0,0]; space.findNamed("tank-barrel").findComponent( "Transform").directionToWorld(bulletVelocity, bulletVelocity); var impEvent = new engine.Event('LinearImpulse',{impulse: [bulletVelocity[0], bulletVelocity[2]]}); impEvent.dispatch(newBullet); diff --git a/gladius-box2d.js b/gladius-box2d.js index d39dad1..44f6dce 100644 --- a/gladius-box2d.js +++ b/gladius-box2d.js @@ -100062,6 +100062,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' ) ? @@ -100099,6 +100101,7 @@ 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_shape( options.shape ); return box2dFixtureDef; }; From 5f74c7fa07b10bd7e0103577ce28068252201f75 Mon Sep 17 00:00:00 2001 From: David Perit Date: Tue, 14 Aug 2012 16:27:56 -0400 Subject: [PATCH 09/19] Made tank projectiles spawn at the end of the barrel, outside of the tank's collision boundaries. Fixed bug related to weird bullet directions --- examples/tank/tank.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/examples/tank/tank.js b/examples/tank/tank.js index ce02f81..15ba126 100644 --- a/examples/tank/tank.js +++ b/examples/tank/tank.js @@ -37,6 +37,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { } } engine.registerExtension( inputExtension, inputOptions ); + //Need to find a way to make this property access longer :) engine.registerExtension( box2dExtension, {resolver: {dimensionMap: box2dExtension.services.resolver.service.prototype.DimensionMaps.XZ}}); @@ -218,8 +219,6 @@ document.addEventListener( "DOMContentLoaded", function( e ) { rotation = 0; if( controller.states["MoveForward"] ) { -// transform.position.add( transform.directionToLocal( -// [space.clock.delta * tankMovementSpeed, 0, 0] ) ); tankVelocity[0]+=tankMovementSpeed; } if( controller.states["MoveBackward"] ) { @@ -261,22 +260,25 @@ document.addEventListener( "DOMContentLoaded", function( e ) { friction:0.3 })}); physicsBody.tankBulletCollisions = 0; + var barrelTransform = space.findNamed("tank-barrel").findComponent( "Transform"); + var bulletFiringPoint = math.vector3.add(barrelTransform.toWorldPoint(), barrelTransform.directionToWorld([0.7,0,0])); var newBullet = new Entity("bullet", [ - new engine.core.Transform(space.findNamed ("tank-barrel").findComponent( "Transform").toWorldPoint()), + new engine.core.Transform(bulletFiringPoint), new cubicvr.Model(resources.bullet, resources.bulletMaterial), physicsBody ] ); physicsBody.onContactBegin = function(event){ this.tankBulletCollisions++; - if (this.tankBulletCollisions === 5){ + 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 = [3,0,0]; space.findNamed("tank-barrel").findComponent( "Transform").directionToWorld(bulletVelocity, bulletVelocity); var impEvent = new engine.Event('LinearImpulse',{impulse: [bulletVelocity[0], bulletVelocity[2]]}); impEvent.dispatch(newBullet); From 649f69a2c11e34221974339da5faa6dbdf8bf4e4 Mon Sep 17 00:00:00 2001 From: David Perit Date: Wed, 15 Aug 2012 14:23:51 -0400 Subject: [PATCH 10/19] Added restitution (bounciness) to bullets and tanks Added collision filters to bullets and tanks so that bullets no longer can collide with the tank that fired them. Added new version of box2d extension that allows the two above improvements to work --- examples/tank/tank.js | 34 ++++++++++++++++++++++++++-------- gladius-box2d.js | 13 +++++++++++++ 2 files changed, 39 insertions(+), 8 deletions(-) diff --git a/examples/tank/tank.js b/examples/tank/tank.js index 15ba126..30a77ad 100644 --- a/examples/tank/tank.js +++ b/examples/tank/tank.js @@ -257,11 +257,22 @@ document.addEventListener( "DOMContentLoaded", function( e ) { fixtureDefinition: new box2d.FixtureDefinition( { shape:new box2d.CircleShape(0.25), - friction:0.3 + 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.directionToWorld([0.7,0,0])); + var bulletFiringPoint = math.vector3.add(barrelTransform.toWorldPoint(), barrelTransform.directionToWorld([0.3,0,0])); var newBullet = new Entity("bullet", [ new engine.core.Transform(bulletFiringPoint), @@ -271,7 +282,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { ); physicsBody.onContactBegin = function(event){ this.tankBulletCollisions++; - if (this.tankBulletCollisions === 2){ + if (this.tankBulletCollisions === 3){ //This is how you remove something from the space properly this.owner.setActive(false); space.remove(this.owner); @@ -286,7 +297,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { } }; - function createTank(name, position, material, hasControls) { + 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, @@ -294,7 +305,10 @@ document.addEventListener( "DOMContentLoaded", function( e ) { new engine.core.Transform(position, [math.TAU / 4, 0, 0]), new engine.logic.Actor(tankLogic), new box2d.Body({bodyDefinition: new box2d.BodyDefinition(), - fixtureDefinition: new box2d.FixtureDefinition({shape:new box2d.BoxShape(1,1)})}) + fixtureDefinition: new box2d.FixtureDefinition( + {shape:new box2d.BoxShape(1,1), + filter:{categoryBits:collisionCategory} + })}) ], [name] )); @@ -342,12 +356,16 @@ document.addEventListener( "DOMContentLoaded", function( e ) { space.findNamed(name + "-turret") )); } - createTank("tank", [-4,0,-4], resources.material, true); - createTank("red-tank", [4,0,4], resources.redMaterial, false); + createTank("tank", [-4,0,-4], resources.material, true, 8); + createTank("red-tank", [4,0,4], resources.redMaterial, false, 16); //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)}); + 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}); diff --git a/gladius-box2d.js b/gladius-box2d.js index 44f6dce..084ceb5 100644 --- a/gladius-box2d.js +++ b/gladius-box2d.js @@ -100102,6 +100102,19 @@ define('src/resources/fixture-definition',['require','box2d'],function ( require 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; }; From 35e01df5bd5b74779aade19c86924c943ee9d97d Mon Sep 17 00:00:00 2001 From: David Perit Date: Fri, 17 Aug 2012 15:16:35 -0400 Subject: [PATCH 11/19] Made the red tank move to random positions in the arena Made the red tank get stunned for a period of time after being collided with so that it moves only according to physics impulses Added new version of the core library that includes a new version of the math library --- examples/tank/tank.js | 94 ++++++++++++++++++++-- gladius-core.js | 177 ++++++++++++++++++++++++++++++++++++++---- 2 files changed, 252 insertions(+), 19 deletions(-) diff --git a/examples/tank/tank.js b/examples/tank/tank.js index 30a77ad..e2c2bad 100644 --- a/examples/tank/tank.js +++ b/examples/tank/tank.js @@ -39,7 +39,8 @@ document.addEventListener( "DOMContentLoaded", function( e ) { engine.registerExtension( inputExtension, inputOptions ); //Need to find a way to make this property access longer :) - engine.registerExtension( box2dExtension, {resolver: {dimensionMap: box2dExtension.services.resolver.service.prototype.DimensionMaps.XZ}}); + engine.registerExtension( box2dExtension, + {resolver: {dimensionMap: box2dExtension.services.resolver.service.prototype.DimensionMaps.XZ}}); var cubicvr = engine.findExtension( "gladius-cubicvr" ); var input = engine.findExtension( "gladius-input" ); @@ -182,6 +183,11 @@ 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" ); @@ -194,6 +200,8 @@ document.addEventListener( "DOMContentLoaded", function( e ) { var tankMovementSpeed = 3; var tankRotationSpeed = 2; var turretRotationSpeed = 0.002; + var minStunTime = 2; + var maxStunTime = 4; var bulletVelocity = [3,0,0]; var tankVelocity = [0,0,0]; @@ -298,7 +306,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { }; function createTank(name, position, material, hasControls, collisionCategory) { -// This parent entity will let us adjust the position and orientation of the + // This parent entity will let us adjust the position and orientation of the // tank, and handle game logic events space.add(new Entity(name, [ @@ -356,8 +364,18 @@ document.addEventListener( "DOMContentLoaded", function( e ) { space.findNamed(name + "-turret") )); } - createTank("tank", [-4,0,-4], resources.material, true, 8); - createTank("red-tank", [4,0,4], resources.redMaterial, false, 16); + createTank("tank", [-3,0,-3], resources.material, true, 8); + createTank("red-tank", [3,0,3], resources.redMaterial, false, 16); + var redTank = space.findNamed( "red-tank" ); + redTank.doneRotation = true; + redTank.doneMovement = true; + redTank.stunned = false; + redTank.findComponent("Body").onContactBegin = function(event){ + if (!this.owner.stunned){ + this.owner.stunnedTime = getRandom(minStunTime, maxStunTime); + this.owner.stunned = true; + } + }; //TODO: Make these walls have tiling textures var bodyDefinition = new box2d.BodyDefinition({type:box2d.BodyDefinition.BodyTypes.STATIC}); @@ -405,7 +423,73 @@ document.addEventListener( "DOMContentLoaded", function( e ) { new cubicvr.Light(lightDefinition) ] )); - // space.findNamed( "camera" ).findComponent( "Camera" ).setTarget( 0, 0, 0 ); + + var task = new engine.FunctionTask( function() { + var elapsedTime = space.clock.delta/1000; + var redTank = space.findNamed( "red-tank" ); + var transform = redTank.findComponent("Transform"); + var position = transform.position; + var physicsBody = redTank.findComponent("Body"); + var greenTank = space.findNamed( "tank" ); + var greenTransform = greenTank.findComponent("Transform"); + var turretTransform = space.findNamed("red-tank-turret").findComponent("Transform"); + if (redTank.stunned){ + redTank.stunnedTime -= elapsedTime; + if (redTank.stunnedTime < 0){ + redTank.stunned = false; + redTank.doneMovement = true; + } + } + if (!redTank.stunned){ + if (redTank.doneMovement){ + //Done moving, make up a new destination + var newPosition = []; + newPosition[0] = getRandom(-3, 3); + newPosition[1] = position.y; + newPosition[2] = getRandom(-3, 3); + var currentRotation = transform.rotation.y * -1; + var directionToNewPosition = Math.atan2(newPosition[2] - position.z, newPosition[0] - position.x); + + var changeInDirection = directionToNewPosition - (currentRotation - (Math.floor(currentRotation / math.TAU) * math.TAU)); + if (changeInDirection > math.PI){ + changeInDirection = (math.TAU - changeInDirection) * -1; + } + if (changeInDirection < -math.PI){ + changeInDirection = (-math.TAU - changeInDirection) * -1; + } + 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]; + transform.directionToWorld(redTank.tankVelocity, redTank.tankVelocity); + physicsBody.setAngularVelocity(0); + physicsBody.setLinearVelocity(redTank.tankVelocity[0], redTank.tankVelocity[2]); + } + } + //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"] + }); + task.start(); engine.resume(); } diff --git a/gladius-core.js b/gladius-core.js index f89528b..2a47f30 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, From 8545fb795b6ba5816999dbe5642457972da9ebbb Mon Sep 17 00:00:00 2001 From: David Perit Date: Tue, 21 Aug 2012 15:46:14 -0400 Subject: [PATCH 12/19] Made the red tank's turret automatically rotate to point at the green tank Made the red tank fire shots at the green tank Changed the way tanks are created so that they don't have to have an x rotation applied after creation Caused the player's tank to get stunned by impacts, but for a shorter period of time than the AI tank Caused both tanks to do a full turret rotation over the course of the stun, to visually show that they are stunned Added a removeExcessRotation function, which simplifies a rotation angle to be still correct but within the range of -PI to PI radians Simplified some math in the red tank's movement code Added a new version of the core library --- examples/tank/tank.js | 222 +++++++++++++++++++++++++++++++----------- gladius-core.js | 74 +++++++++++--- 2 files changed, 225 insertions(+), 71 deletions(-) diff --git a/examples/tank/tank.js b/examples/tank/tank.js index e2c2bad..e58e5e7 100644 --- a/examples/tank/tank.js +++ b/examples/tank/tank.js @@ -67,7 +67,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { [ { type: cubicvr.Mesh, - url: "../assets/procedural-prism.js?length=1.0&width=0.5&depth=0.25", + url: "../assets/procedural-prism.js?length=1.0&width=0.25&depth=0.5", load: engine.loaders.procedural, onsuccess: function( mesh ) { resources.tankBody = mesh; @@ -77,7 +77,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { }, { type: cubicvr.Mesh, - url: "../assets/procedural-prism.js?length=0.85&width=0.2&depth=0.35", + url: "../assets/procedural-prism.js?length=0.85&width=0.35&depth=0.2", load: engine.loaders.procedural, onsuccess: function( mesh ) { resources.tankTread = mesh; @@ -87,7 +87,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { }, { type: cubicvr.Mesh, - url: "../assets/procedural-prism.js?length=0.5&width=0.35&depth=0.15", + url: "../assets/procedural-prism.js?length=0.5&width=0.15&depth=0.35", load: engine.loaders.procedural, onsuccess: function( mesh ) { resources.tankTurret = mesh; @@ -97,7 +97,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { }, { type: cubicvr.Mesh, - url: "../assets/procedural-prism.js?length=0.4&width=0.1&depth=0.05", + url: "../assets/procedural-prism.js?length=0.4&width=0.05&depth=0.1", load: engine.loaders.procedural, onsuccess: function( mesh ) { resources.tankBarrel = mesh; @@ -196,12 +196,17 @@ document.addEventListener( "DOMContentLoaded", function( e ) { var Entity = engine.Entity; var lastBulletTime = 0; + var lastRedBulletTime = 0; var tankFiringInterval = 500; + var redTankFiringInterval = 1000; var tankMovementSpeed = 3; var tankRotationSpeed = 2; - var turretRotationSpeed = 0.002; - var minStunTime = 2; - var maxStunTime = 4; + 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]; @@ -219,47 +224,58 @@ document.addEventListener( "DOMContentLoaded", function( e ) { if( this.owner.hasComponent( "Controller" ) ) { var controller = this.owner.findComponent( "Controller" ); var physBody = this.owner.findComponent( "Body" ); - var transform = space.findNamed( "tank-body" ).findComponent( "Transform" ); + var greenTank = space.findNamed( "tank" ); + var transform = greenTank.findComponent( "Transform" ); var turretTransform = space.findNamed ("tank-turret").findComponent( "Transform" ); + var elapsedTime = space.clock.delta/1000; tankVelocity[0] = 0; tankVelocity[1] = 0; tankVelocity[2] = 0; rotation = 0; - if( controller.states["MoveForward"] ) { - tankVelocity[0]+=tankMovementSpeed; - } - if( controller.states["MoveBackward"] ) { - tankVelocity[0]-=tankMovementSpeed; - } + if (greenTank.stunned){ + greenTank.stunnedTime -= elapsedTime; + if (greenTank.stunnedTime < 0){ + greenTank.stunned = false; + }else{ + turretTransform.rotation.y += greenTank.stunnedTurretRotationSpeed * elapsedTime * greenTank.stunnedTurretRotationDirection; + } + }else{ - if( controller.states["TurnLeft"] ) { - if( controller.states["StrafeModifier"] ) { - tankVelocity[2]-=tankMovementSpeed; - } else { - rotation+=tankRotationSpeed; + if( controller.states["MoveForward"] ) { + tankVelocity[0]+=tankMovementSpeed; } - } - if( controller.states["TurnRight"] ) { - if( controller.states["StrafeModifier"] ) { - tankVelocity[2]+=tankMovementSpeed; - } else { - rotation-=tankRotationSpeed; + if( controller.states["MoveBackward"] ) { + tankVelocity[0]-=tankMovementSpeed; + } + if( controller.states["TurnLeft"] ) { + if( controller.states["StrafeModifier"] ) { + tankVelocity[2]-=tankMovementSpeed; + } else { + rotation+=tankRotationSpeed; + } + } + if( controller.states["TurnRight"] ) { + if( controller.states["StrafeModifier"] ) { + tankVelocity[2]+=tankMovementSpeed; + } else { + rotation-=tankRotationSpeed; + } + } + transform.directionToWorld(tankVelocity, tankVelocity); + physBody.setLinearVelocity(tankVelocity[0],tankVelocity[2]); + physBody.setAngularVelocity(rotation); + if (controller.states["TurnTurretLeft"] ) { + turretTransform.rotation.add([0, (space.clock.delta/1000) * greenTankTurretRotationSpeed, 0]); + } + if (controller.states["TurnTurretRight"] ) { + turretTransform.rotation.add([0, (space.clock.delta/1000) * -greenTankTurretRotationSpeed, 0]); } - } - transform.directionToWorld(tankVelocity, tankVelocity); - physBody.setLinearVelocity(tankVelocity[0],tankVelocity[2]); - physBody.setAngularVelocity(rotation); - if (controller.states["TurnTurretLeft"] ) { - turretTransform.rotation.add([0, 0, space.clock.delta * -turretRotationSpeed]); - } - if (controller.states["TurnTurretRight"] ) { - turretTransform.rotation.add([0, 0, space.clock.delta * turretRotationSpeed]); } } }, "Fire": function( event ) { - if (space.clock.time - tankFiringInterval > lastBulletTime){ + if (space.clock.time > lastBulletTime + tankFiringInterval){ lastBulletTime = space.clock.time; var physicsBody = new box2d.Body({bodyDefinition: new box2d.BodyDefinition({bullet:true}), fixtureDefinition: new box2d.FixtureDefinition( @@ -310,7 +326,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { // tank, and handle game logic events space.add(new Entity(name, [ - new engine.core.Transform(position, [math.TAU / 4, 0, 0]), + new engine.core.Transform(position), new engine.logic.Actor(tankLogic), new box2d.Body({bodyDefinition: new box2d.BodyDefinition(), fixtureDefinition: new box2d.FixtureDefinition( @@ -333,7 +349,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { )); space.add(new Entity(name + "-tread", [ - new engine.core.Transform([0, 0.4, 0]), + new engine.core.Transform([0, 0, 0.4]), new cubicvr.Model(resources.tankTread, material) ], [name], @@ -341,7 +357,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { )); space.add(new Entity(name + "-tread", [ - new engine.core.Transform([0, -0.4, 0]), + new engine.core.Transform([0, 0, -0.4]), new cubicvr.Model(resources.tankTread, material) ], [name], @@ -349,7 +365,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { )); space.add(new Entity(name+"-turret", [ - new engine.core.Transform([-0.1, 0, -0.3]), + new engine.core.Transform([-0.1, 0.3, 0]), new cubicvr.Model(resources.tankTurret, material) ], [name], @@ -365,14 +381,29 @@ document.addEventListener( "DOMContentLoaded", function( e ) { )); } createTank("tank", [-3,0,-3], resources.material, true, 8); - createTank("red-tank", [3,0,3], resources.redMaterial, false, 16); + createTank("red-tank", [1,0,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(minStunTime, maxStunTime); + 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; } }; @@ -424,39 +455,112 @@ document.addEventListener( "DOMContentLoaded", function( e ) { ] )); + 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() { - var elapsedTime = space.clock.delta/1000; - var redTank = space.findNamed( "red-tank" ); - var transform = redTank.findComponent("Transform"); - var position = transform.position; - var physicsBody = redTank.findComponent("Body"); - var greenTank = space.findNamed( "tank" ); - var greenTransform = greenTank.findComponent("Transform"); - var turretTransform = space.findNamed("red-tank-turret").findComponent("Transform"); + elapsedTime = space.clock.delta/1000; + if (redTank.stunned){ redTank.stunnedTime -= elapsedTime; if (redTank.stunnedTime < 0){ redTank.stunned = false; redTank.doneMovement = true; + }else{ + redTankTurretTransform.rotation.y += redTank.stunnedTurretRotationSpeed * elapsedTime * redTank.stunnedTurretRotationDirection; } } if (!redTank.stunned){ + //Rotate the red turret to point at the green tank + var greenTankInRedTankTurretLocalSpace = redTankTurretTransform.transformToLocal(greenTankTransform); + //We are multiplying the z coordinate by -1 because Math.atan2 expects (y,x), and up on the screen is negative for z but positive for y + var directionOfGreenTank = Math.atan2(greenTankInRedTankTurretLocalSpace[2] * -1, greenTankInRedTankTurretLocalSpace[0]); + var currentDirection = redTankTurretTransform.rotation.y; + 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.y = 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.directionToWorld([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.directionToWorld(bulletVelocity, bulletVelocity); + var impEvent = new engine.Event('LinearImpulse',{impulse: [bulletVelocity[0], bulletVelocity[2]]}); + impEvent.dispatch(newBullet); + } + if (redTank.doneMovement){ //Done moving, make up a new destination - var newPosition = []; newPosition[0] = getRandom(-3, 3); newPosition[1] = position.y; newPosition[2] = getRandom(-3, 3); - var currentRotation = transform.rotation.y * -1; + //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) +// ] +// )); + + var currentRotation = redTankTransform.rotation.y; var directionToNewPosition = Math.atan2(newPosition[2] - position.z, newPosition[0] - position.x); - var changeInDirection = directionToNewPosition - (currentRotation - (Math.floor(currentRotation / math.TAU) * math.TAU)); - if (changeInDirection > math.PI){ - changeInDirection = (math.TAU - changeInDirection) * -1; - } - if (changeInDirection < -math.PI){ - changeInDirection = (-math.TAU - changeInDirection) * -1; - } + 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; @@ -471,7 +575,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { if (redTank.timeToRotate < 0){ redTank.doneRotation = true; redTank.tankVelocity = [tankMovementSpeed, 0, 0]; - transform.directionToWorld(redTank.tankVelocity, redTank.tankVelocity); + redTankTransform.directionToWorld(redTank.tankVelocity, redTank.tankVelocity); physicsBody.setAngularVelocity(0); physicsBody.setLinearVelocity(redTank.tankVelocity[0], redTank.tankVelocity[2]); } diff --git a/gladius-core.js b/gladius-core.js index 2a47f30..b6c09ad 100644 --- a/gladius-core.js +++ b/gladius-core.js @@ -14102,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 @@ -14113,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; @@ -14126,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; @@ -14164,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(), @@ -14174,21 +14178,44 @@ define('core/components/transform',['require','_math','common/extend','base/comp } } + //This calculates the rotation of world space relative to the object + //It is wrong! + function computeLocalRotation(){ + //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(math.transform.rotate(this._rotation.buffer), + this.owner.parent.findComponent( "Transform").localRotation()); + }else{ + return math.transform.rotate(this._rotation.buffer); + } + } + function directionToWorld(direction, result) { result = result || new math.V3(); - var transformedDirection = math.matrix4.multiply( + 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) { 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 thisWorldPositionMatrix + //Solution grabbed from http://www.macaronikazoo.com/?p=419 + math.matrix4.multiply(math.matrix4.inverse(thisParentWorldMatrix,this._tempMatrix), math.matrix4.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; } @@ -14197,14 +14224,37 @@ define('core/components/transform',['require','_math','common/extend','base/comp return [worldMatrix[3], worldMatrix[7], worldMatrix[11]]; } + function transformToLocal(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 thisWorldPositionMatrix + // 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, + //Same thing goes for this one. worldRotation: computeWorldRotation, + localRotation: computeLocalRotation, toWorldPoint: toWorldPoint, - toLocalPoint: undefined, + transformToLocal: transformToLocal, lookAt: undefined, target: undefined, // Direction constants From 3a7ddb918fd32a222a39a8bdf1b46c282a822d5a Mon Sep 17 00:00:00 2001 From: David Perit Date: Tue, 21 Aug 2012 17:02:38 -0400 Subject: [PATCH 13/19] Updated instructions in index.html for tank game --- examples/tank/index.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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

From fcdb4a5b18c482ecfd18ddaf0bee5711b80a546c Mon Sep 17 00:00:00 2001 From: David Perit Date: Wed, 22 Aug 2012 14:12:15 -0400 Subject: [PATCH 14/19] Fixed units in cube-collision so that it works properly again Re-ordered some code in tank.js --- examples/cube-collision/cube-collision.js | 13 ++-- examples/tank/tank.js | 82 +++++++++++------------ 2 files changed, 47 insertions(+), 48 deletions(-) diff --git a/examples/cube-collision/cube-collision.js b/examples/cube-collision/cube-collision.js index 19bb100..d22e711 100644 --- a/examples/cube-collision/cube-collision.js +++ b/examples/cube-collision/cube-collision.js @@ -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/tank.js b/examples/tank/tank.js index e58e5e7..fda977c 100644 --- a/examples/tank/tank.js +++ b/examples/tank/tank.js @@ -197,7 +197,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { var lastBulletTime = 0; var lastRedBulletTime = 0; - var tankFiringInterval = 500; + var greenTankFiringInterval = 500; var redTankFiringInterval = 1000; var tankMovementSpeed = 3; var tankRotationSpeed = 2; @@ -221,61 +221,59 @@ document.addEventListener( "DOMContentLoaded", function( e ) { 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.y += greenTank.stunnedTurretRotationSpeed * elapsedTime * greenTank.stunnedTurretRotationDirection; + } + }else if( this.owner.hasComponent( "Controller" ) ) { var controller = this.owner.findComponent( "Controller" ); var physBody = this.owner.findComponent( "Body" ); - var greenTank = space.findNamed( "tank" ); var transform = greenTank.findComponent( "Transform" ); - var turretTransform = space.findNamed ("tank-turret").findComponent( "Transform" ); - var elapsedTime = space.clock.delta/1000; tankVelocity[0] = 0; tankVelocity[1] = 0; tankVelocity[2] = 0; rotation = 0; - if (greenTank.stunned){ - greenTank.stunnedTime -= elapsedTime; - if (greenTank.stunnedTime < 0){ - greenTank.stunned = false; - }else{ - turretTransform.rotation.y += greenTank.stunnedTurretRotationSpeed * elapsedTime * greenTank.stunnedTurretRotationDirection; - } - }else{ - - if( controller.states["MoveForward"] ) { - tankVelocity[0]+=tankMovementSpeed; - } - if( controller.states["MoveBackward"] ) { - tankVelocity[0]-=tankMovementSpeed; - } - if( controller.states["TurnLeft"] ) { - if( controller.states["StrafeModifier"] ) { - tankVelocity[2]-=tankMovementSpeed; - } else { - rotation+=tankRotationSpeed; - } - } - if( controller.states["TurnRight"] ) { - if( controller.states["StrafeModifier"] ) { - tankVelocity[2]+=tankMovementSpeed; - } else { - rotation-=tankRotationSpeed; - } - } - transform.directionToWorld(tankVelocity, tankVelocity); - physBody.setLinearVelocity(tankVelocity[0],tankVelocity[2]); - physBody.setAngularVelocity(rotation); - if (controller.states["TurnTurretLeft"] ) { - turretTransform.rotation.add([0, (space.clock.delta/1000) * greenTankTurretRotationSpeed, 0]); + if( controller.states["MoveForward"] ) { + tankVelocity[0]+=tankMovementSpeed; + } + if( controller.states["MoveBackward"] ) { + tankVelocity[0]-=tankMovementSpeed; + } + if( controller.states["TurnLeft"] ) { + if( controller.states["StrafeModifier"] ) { + tankVelocity[2]-=tankMovementSpeed; + } else { + rotation+=tankRotationSpeed; } - if (controller.states["TurnTurretRight"] ) { - turretTransform.rotation.add([0, (space.clock.delta/1000) * -greenTankTurretRotationSpeed, 0]); + } + if( controller.states["TurnRight"] ) { + if( controller.states["StrafeModifier"] ) { + tankVelocity[2]+=tankMovementSpeed; + } else { + rotation-=tankRotationSpeed; } } + transform.directionToWorld(tankVelocity, tankVelocity); + physBody.setLinearVelocity(tankVelocity[0],tankVelocity[2]); + physBody.setAngularVelocity(rotation); + if (controller.states["TurnTurretLeft"] ) { + turretTransform.rotation.add([0, (space.clock.delta/1000) * greenTankTurretRotationSpeed, 0]); + } + if (controller.states["TurnTurretRight"] ) { + turretTransform.rotation.add([0, (space.clock.delta/1000) * -greenTankTurretRotationSpeed, 0]); + } + } }, "Fire": function( event ) { - if (space.clock.time > lastBulletTime + tankFiringInterval){ + 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( From b26a357ca848282750088d5266e006dc0ee65b1d Mon Sep 17 00:00:00 2001 From: David Perit Date: Fri, 24 Aug 2012 15:03:36 -0400 Subject: [PATCH 15/19] Updated code to account for some renamed methods Added new version of core library --- examples/tank/tank.js | 14 +++++++------- gladius-core.js | 33 ++++++++++----------------------- 2 files changed, 17 insertions(+), 30 deletions(-) diff --git a/examples/tank/tank.js b/examples/tank/tank.js index fda977c..40839ca 100644 --- a/examples/tank/tank.js +++ b/examples/tank/tank.js @@ -260,7 +260,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { rotation-=tankRotationSpeed; } } - transform.directionToWorld(tankVelocity, tankVelocity); + transform.pointToWorld(tankVelocity, tankVelocity); physBody.setLinearVelocity(tankVelocity[0],tankVelocity[2]); physBody.setAngularVelocity(rotation); if (controller.states["TurnTurretLeft"] ) { @@ -294,7 +294,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { })}); physicsBody.tankBulletCollisions = 0; var barrelTransform = space.findNamed("tank-barrel").findComponent( "Transform"); - var bulletFiringPoint = math.vector3.add(barrelTransform.toWorldPoint(), barrelTransform.directionToWorld([0.3,0,0])); + var bulletFiringPoint = math.vector3.add(barrelTransform.toWorldPoint(), barrelTransform.pointToWorld([0.3,0,0])); var newBullet = new Entity("bullet", [ new engine.core.Transform(bulletFiringPoint), @@ -312,7 +312,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { }; space.add(newBullet); bulletVelocity = [3,0,0]; - space.findNamed("tank-barrel").findComponent( "Transform").directionToWorld(bulletVelocity, bulletVelocity); + space.findNamed("tank-barrel").findComponent( "Transform").pointToWorld(bulletVelocity, bulletVelocity); var impEvent = new engine.Event('LinearImpulse',{impulse: [bulletVelocity[0], bulletVelocity[2]]}); impEvent.dispatch(newBullet); } @@ -491,7 +491,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { } if (!redTank.stunned){ //Rotate the red turret to point at the green tank - var greenTankInRedTankTurretLocalSpace = redTankTurretTransform.transformToLocal(greenTankTransform); + var greenTankInRedTankTurretLocalSpace = redTankTurretTransform.relativeTo(greenTankTransform); //We are multiplying the z coordinate by -1 because Math.atan2 expects (y,x), and up on the screen is negative for z but positive for y var directionOfGreenTank = Math.atan2(greenTankInRedTankTurretLocalSpace[2] * -1, greenTankInRedTankTurretLocalSpace[0]); var currentDirection = redTankTurretTransform.rotation.y; @@ -517,7 +517,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { filter:{categoryBits:2, maskBits:15} })}); bulletBody.tankBulletCollisions = 0; - var bulletFiringPoint = math.vector3.add(redTankBarrelTransform.toWorldPoint(), redTankBarrelTransform.directionToWorld([0.3,0,0])); + var bulletFiringPoint = math.vector3.add(redTankBarrelTransform.toWorldPoint(), redTankBarrelTransform.pointToWorld([0.3,0,0])); var newBullet = new Entity("bullet", [ new engine.core.Transform(bulletFiringPoint), @@ -535,7 +535,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { }; space.add(newBullet); bulletVelocity = [2,0,0]; - redTankBarrelTransform.directionToWorld(bulletVelocity, bulletVelocity); + redTankBarrelTransform.pointToWorld(bulletVelocity, bulletVelocity); var impEvent = new engine.Event('LinearImpulse',{impulse: [bulletVelocity[0], bulletVelocity[2]]}); impEvent.dispatch(newBullet); } @@ -573,7 +573,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { if (redTank.timeToRotate < 0){ redTank.doneRotation = true; redTank.tankVelocity = [tankMovementSpeed, 0, 0]; - redTankTransform.directionToWorld(redTank.tankVelocity, redTank.tankVelocity); + redTankTransform.pointToWorld(redTank.tankVelocity, redTank.tankVelocity); physicsBody.setAngularVelocity(0); physicsBody.setLinearVelocity(redTank.tankVelocity[0], redTank.tankVelocity[2]); } diff --git a/gladius-core.js b/gladius-core.js index b6c09ad..0b5918d 100644 --- a/gladius-core.js +++ b/gladius-core.js @@ -14178,21 +14178,9 @@ define('core/components/transform',['require','_math','common/extend','base/comp } } - //This calculates the rotation of world space relative to the object - //It is wrong! - function computeLocalRotation(){ - //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(math.transform.rotate(this._rotation.buffer), - this.owner.parent.findComponent( "Transform").localRotation()); - }else{ - return math.transform.rotate(this._rotation.buffer); - } - } - - function directionToWorld(direction, result) { + function pointToWorld(direction, result) { result = result || new math.V3(); + direction = direction || new math.V3(); math.matrix4.multiply( computeWorldRotation.call(this), math.transform.translate( direction ), @@ -14201,15 +14189,15 @@ define('core/components/transform',['require','_math','common/extend','base/comp return result; } - function directionToLocal(direction, result) { + function pointToLocal(direction, result) { result = result || new math.V3(); 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 thisWorldPositionMatrix + // 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.matrix4.translate(direction), this._tempMatrix); + 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]); } @@ -14224,7 +14212,7 @@ define('core/components/transform',['require','_math','common/extend','base/comp return [worldMatrix[3], worldMatrix[7], worldMatrix[11]]; } - function transformToLocal(otherTransform, result) + function relativeTo(otherTransform, result) { result = result || new math.V3(); var otherWorldMatrix = otherTransform.worldMatrix(); @@ -14232,7 +14220,7 @@ define('core/components/transform',['require','_math','common/extend','base/comp 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 thisWorldPositionMatrix + // 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 @@ -14248,13 +14236,12 @@ define('core/components/transform',['require','_math','common/extend','base/comp //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, //Same thing goes for this one. worldRotation: computeWorldRotation, - localRotation: computeLocalRotation, + relativeTo: relativeTo, toWorldPoint: toWorldPoint, - transformToLocal: transformToLocal, lookAt: undefined, target: undefined, // Direction constants From a80416e36e84d7fc26bb000e370384d7dcfd72c7 Mon Sep 17 00:00:00 2001 From: David Perit Date: Fri, 24 Aug 2012 15:14:24 -0400 Subject: [PATCH 16/19] Added new versions of core and box2d libraries --- gladius-box2d.js | 16 ++++++++-------- gladius-core.js | 6 ++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/gladius-box2d.js b/gladius-box2d.js index 084ceb5..e0c3698 100644 --- a/gladius-box2d.js +++ b/gladius-box2d.js @@ -99864,7 +99864,7 @@ define('src/components/body',['require','box2d','common/extend','base/component' Body.prototype = new Component(); Body.prototype.constructor = Body; - var linearVector = new Box2D.b2Vec2( 0, 0 ); + var b2Vector = new Box2D.b2Vec2( 0, 0 ); function setAngularVelocity(rotation){ this.box2dBody.SetAngularVelocity(rotation); @@ -99873,19 +99873,19 @@ define('src/components/body',['require','box2d','common/extend','base/component' function setLinearVelocity(arg1, arg2) { var argc = arguments.length; if( 1 === argc ) { - linearVector.Set( arg1[0], arg1[1] ); + b2Vector.Set( arg1[0], arg1[1] ); }else{ - linearVector.Set( arg1, arg2); + b2Vector.Set( arg1, arg2); } - this.box2dBody.SetLinearVelocity( linearVector ); - linearVector.Set( 0, 0 ); + this.box2dBody.SetLinearVelocity( b2Vector ); + b2Vector.Set( 0, 0 ); } function onLinearImpulse( event ) { var impulse = event.data.impulse; - linearVector.Set( impulse[0], impulse[1] ); - this.box2dBody.ApplyLinearImpulse( linearVector, this.box2dBody.GetPosition() ); - linearVector.Set( 0, 0 ); + b2Vector.Set( impulse[0], impulse[1] ); + this.box2dBody.ApplyLinearImpulse( b2Vector, this.box2dBody.GetPosition() ); + b2Vector.Set( 0, 0 ); } function onAngularImpulse( event ) { diff --git a/gladius-core.js b/gladius-core.js index 0b5918d..d5be028 100644 --- a/gladius-core.js +++ b/gladius-core.js @@ -14178,6 +14178,11 @@ define('core/components/transform',['require','_math','common/extend','base/comp } } + //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(); direction = direction || new math.V3(); @@ -14238,6 +14243,7 @@ define('core/components/transform',['require','_math','common/extend','base/comp localMatrix: computeLocalMatrix, pointToLocal: pointToLocal, pointToWorld: pointToWorld, + directionToWorld: undefined, //Same thing goes for this one. worldRotation: computeWorldRotation, relativeTo: relativeTo, From 484da0c2bb43b82eb4e93765a4de69d278cbe101 Mon Sep 17 00:00:00 2001 From: David Perit Date: Wed, 19 Sep 2012 14:49:28 -0400 Subject: [PATCH 17/19] Updated coordinates/removed dimension mapping in tank game. They still aren't right, but it's an improvement. Added newer version of box2d without direction mapping --- examples/tank/tank.js | 62 +++++++++++++++++++++---------------------- gladius-box2d.js | 28 +++---------------- 2 files changed, 33 insertions(+), 57 deletions(-) diff --git a/examples/tank/tank.js b/examples/tank/tank.js index 40839ca..ecf3060 100644 --- a/examples/tank/tank.js +++ b/examples/tank/tank.js @@ -38,9 +38,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { } engine.registerExtension( inputExtension, inputOptions ); - //Need to find a way to make this property access longer :) - engine.registerExtension( box2dExtension, - {resolver: {dimensionMap: box2dExtension.services.resolver.service.prototype.DimensionMaps.XZ}}); + engine.registerExtension( box2dExtension ); var cubicvr = engine.findExtension( "gladius-cubicvr" ); var input = engine.findExtension( "gladius-input" ); @@ -67,7 +65,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { [ { type: cubicvr.Mesh, - url: "../assets/procedural-prism.js?length=1.0&width=0.25&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; @@ -77,7 +75,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { }, { type: cubicvr.Mesh, - url: "../assets/procedural-prism.js?length=0.85&width=0.35&depth=0.2", + url: "../assets/procedural-prism.js?length=0.85&width=0.2&depth=0.35", load: engine.loaders.procedural, onsuccess: function( mesh ) { resources.tankTread = mesh; @@ -87,7 +85,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { }, { type: cubicvr.Mesh, - url: "../assets/procedural-prism.js?length=0.5&width=0.15&depth=0.35", + url: "../assets/procedural-prism.js?length=0.5&width=0.35&depth=0.15", load: engine.loaders.procedural, onsuccess: function( mesh ) { resources.tankTurret = mesh; @@ -97,7 +95,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { }, { type: cubicvr.Mesh, - url: "../assets/procedural-prism.js?length=0.4&width=0.05&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; @@ -229,7 +227,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { if (greenTank.stunnedTime < 0){ greenTank.stunned = false; }else{ - turretTransform.rotation.y += greenTank.stunnedTurretRotationSpeed * elapsedTime * greenTank.stunnedTurretRotationDirection; + turretTransform.rotation.z += greenTank.stunnedTurretRotationSpeed * elapsedTime * greenTank.stunnedTurretRotationDirection; } }else if( this.owner.hasComponent( "Controller" ) ) { var controller = this.owner.findComponent( "Controller" ); @@ -248,20 +246,20 @@ document.addEventListener( "DOMContentLoaded", function( e ) { } if( controller.states["TurnLeft"] ) { if( controller.states["StrafeModifier"] ) { - tankVelocity[2]-=tankMovementSpeed; + tankVelocity[1]-=tankMovementSpeed; } else { rotation+=tankRotationSpeed; } } if( controller.states["TurnRight"] ) { if( controller.states["StrafeModifier"] ) { - tankVelocity[2]+=tankMovementSpeed; + tankVelocity[1]+=tankMovementSpeed; } else { rotation-=tankRotationSpeed; } } transform.pointToWorld(tankVelocity, tankVelocity); - physBody.setLinearVelocity(tankVelocity[0],tankVelocity[2]); + physBody.setLinearVelocity(tankVelocity[0],tankVelocity[1]); physBody.setAngularVelocity(rotation); if (controller.states["TurnTurretLeft"] ) { turretTransform.rotation.add([0, (space.clock.delta/1000) * greenTankTurretRotationSpeed, 0]); @@ -313,7 +311,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { 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[2]]}); + var impEvent = new engine.Event('LinearImpulse',{impulse: [bulletVelocity[0], bulletVelocity[1]]}); impEvent.dispatch(newBullet); } } @@ -347,7 +345,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { )); space.add(new Entity(name + "-tread", [ - new engine.core.Transform([0, 0, 0.4]), + new engine.core.Transform([0, 0.4, 0]), new cubicvr.Model(resources.tankTread, material) ], [name], @@ -355,7 +353,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { )); space.add(new Entity(name + "-tread", [ - new engine.core.Transform([0, 0, -0.4]), + new engine.core.Transform([0, -0.4, 0]), new cubicvr.Model(resources.tankTread, material) ], [name], @@ -363,7 +361,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { )); space.add(new Entity(name+"-turret", [ - new engine.core.Transform([-0.1, 0.3, 0]), + new engine.core.Transform([-0.1, 0, 0.3]), new cubicvr.Model(resources.tankTurret, material) ], [name], @@ -378,8 +376,8 @@ document.addEventListener( "DOMContentLoaded", function( e ) { space.findNamed(name + "-turret") )); } - createTank("tank", [-3,0,-3], resources.material, true, 8); - createTank("red-tank", [1,0,0], resources.redMaterial, false, 16); + 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; @@ -418,28 +416,28 @@ document.addEventListener( "DOMContentLoaded", function( e ) { space.add( new Entity( "wallLeft", [ - new engine.core.Transform([-5,0,0], [0,math.TAU/4,0]), + 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( "wallRight", [ - new engine.core.Transform([5,0,0], [0,math.TAU/4,0]), + 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( "wallTop", [ - new engine.core.Transform([0,0,-5], [0,0,0]), + 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( "wallBottom", [ - new engine.core.Transform([0,0,5], [0,0,0]), + 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}) ] @@ -447,7 +445,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { space.add( new Entity( "camera", [ - new engine.core.Transform( [0, 10, 0], [-math.TAU/4, 0, 0] ), + new engine.core.Transform( [0, 0, 10], [0, 0, 0] ), new cubicvr.Camera(), new cubicvr.Light(lightDefinition) ] @@ -486,15 +484,15 @@ document.addEventListener( "DOMContentLoaded", function( e ) { redTank.stunned = false; redTank.doneMovement = true; }else{ - redTankTurretTransform.rotation.y += redTank.stunnedTurretRotationSpeed * elapsedTime * redTank.stunnedTurretRotationDirection; + 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); //We are multiplying the z coordinate by -1 because Math.atan2 expects (y,x), and up on the screen is negative for z but positive for y - var directionOfGreenTank = Math.atan2(greenTankInRedTankTurretLocalSpace[2] * -1, greenTankInRedTankTurretLocalSpace[0]); - var currentDirection = redTankTurretTransform.rotation.y; + var directionOfGreenTank = Math.atan2(greenTankInRedTankTurretLocalSpace[1] * -1, greenTankInRedTankTurretLocalSpace[0]); + var currentDirection = redTankTurretTransform.rotation.z; var differenceBetweenDirections = removeExcessRotation(currentDirection - directionOfGreenTank); var newRotation; if (differenceBetweenDirections > 0 && differenceBetweenDirections > (redTankTurretRotationSpeed * elapsedTime)){ @@ -504,7 +502,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { }else{ newRotation = directionOfGreenTank; } - redTankTurretTransform.rotation.y = newRotation; + redTankTurretTransform.rotation.z = newRotation; if (space.clock.time > lastRedBulletTime + redTankFiringInterval){ lastRedBulletTime = space.clock.time; @@ -536,15 +534,15 @@ document.addEventListener( "DOMContentLoaded", function( e ) { space.add(newBullet); bulletVelocity = [2,0,0]; redTankBarrelTransform.pointToWorld(bulletVelocity, bulletVelocity); - var impEvent = new engine.Event('LinearImpulse',{impulse: [bulletVelocity[0], bulletVelocity[2]]}); + 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] = position.y; - newPosition[2] = 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", // [ @@ -553,8 +551,8 @@ document.addEventListener( "DOMContentLoaded", function( e ) { // ] // )); - var currentRotation = redTankTransform.rotation.y; - var directionToNewPosition = Math.atan2(newPosition[2] - position.z, newPosition[0] - position.x); + var currentRotation = redTankTransform.rotation.z; + 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 @@ -575,7 +573,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { redTank.tankVelocity = [tankMovementSpeed, 0, 0]; redTankTransform.pointToWorld(redTank.tankVelocity, redTank.tankVelocity); physicsBody.setAngularVelocity(0); - physicsBody.setLinearVelocity(redTank.tankVelocity[0], redTank.tankVelocity[2]); + physicsBody.setLinearVelocity(redTank.tankVelocity[0], redTank.tankVelocity[1]); } } //Move until we reach the desired destination diff --git a/gladius-box2d.js b/gladius-box2d.js index e0c3698..7d06dff 100644 --- a/gladius-box2d.js +++ b/gladius-box2d.js @@ -99615,7 +99615,6 @@ define('src/services/resolver',['require','base/service','core/event','_math','b this.gravity = new Box2D.b2Vec2(); this.world = new Box2D.b2World( this.gravity ); - this.dimensionMap = options.dimensionMap || 0; this._timeStep = 30; // time step, in milliseconds this._timeRemaining = 0; // time remaining from last frame, in milliseconds @@ -99672,12 +99671,6 @@ define('src/services/resolver',['require','base/service','core/event','_math','b var totalForce = new math.Vector2(); - var DimensionMaps = { - XY: 0, - XZ: 1, - YZ: 2 - }; - function resolve() { var component; @@ -99723,7 +99716,6 @@ define('src/services/resolver',['require','base/service','core/event','_math','b Resolver.prototype = new Service(); Resolver.prototype.constructor = Resolver; Resolver.prototype.resolve = resolve; - Resolver.prototype.DimensionMaps = DimensionMaps; return Resolver; @@ -99899,16 +99891,8 @@ define('src/components/body',['require','box2d','common/extend','base/component' var transform = this.owner.findComponent( "Transform" ); //Note: It is currently okay to read from buffers, but writing to them will result in things breaking - if (this.service.dimensionMap === this.service.DimensionMaps.XY){ - transform.position = [ position2.get_x(), position2.get_y(), transform.position.buffer[2] ]; - transform.rotation.z = angle2; - }else if (this.service.dimensionMap === this.service.DimensionMaps.XZ){ - transform.position = [ position2.get_x(), transform.position.buffer[1], position2.get_y()]; - transform.rotation.y = angle2; - }else{ - transform.position = [transform.position.buffer[0], position2.get_y(), position2.get_x()]; - transform.rotation.x = angle2; - } + transform.position = [ position2.get_x(), position2.get_y(), transform.position.buffer[2] ]; + transform.rotation.z = angle2; } function onEntitySpaceChanged( event ) { @@ -99937,13 +99921,7 @@ define('src/components/body',['require','box2d','common/extend','base/component' if( this.owner ) { var transform = this.owner.findComponent( 'Transform' ); //Note: It is currently okay to read from buffers, but writing to them will result in things breaking - if (this.service.dimensionMap === this.service.DimensionMaps.XY){ - this.box2dBody.SetTransform( new Box2D.b2Vec2( transform.position.buffer[0], transform.position.buffer[1] ), transform.rotation.buffer[2] ); - }else if (this.service.dimensionMap === this.service.DimensionMaps.XZ){ - this.box2dBody.SetTransform( new Box2D.b2Vec2( transform.position.buffer[0], transform.position.buffer[2] ), transform.rotation.buffer[1] ); - }else{ - this.box2dBody.SetTransform( new Box2D.b2Vec2( transform.position.buffer[2], transform.position.buffer[1] ), transform.rotation.buffer[0] ); - } + this.box2dBody.SetTransform( new Box2D.b2Vec2( transform.position.buffer[0], transform.position.buffer[1] ), transform.rotation.buffer[2] ); } if( this.owner === null && data.previous !== null ) { From 7142545d5ef0509fe46406fa1b56fe65044ee4cc Mon Sep 17 00:00:00 2001 From: David Perit Date: Fri, 21 Sep 2012 15:26:23 -0400 Subject: [PATCH 18/19] Made the red tank move properly in the new orientation --- examples/tank/tank.js | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/examples/tank/tank.js b/examples/tank/tank.js index ecf3060..a803859 100644 --- a/examples/tank/tank.js +++ b/examples/tank/tank.js @@ -490,8 +490,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { if (!redTank.stunned){ //Rotate the red turret to point at the green tank var greenTankInRedTankTurretLocalSpace = redTankTurretTransform.relativeTo(greenTankTransform); - //We are multiplying the z coordinate by -1 because Math.atan2 expects (y,x), and up on the screen is negative for z but positive for y - var directionOfGreenTank = Math.atan2(greenTankInRedTankTurretLocalSpace[1] * -1, greenTankInRedTankTurretLocalSpace[0]); + var directionOfGreenTank = Math.atan2(greenTankInRedTankTurretLocalSpace[1], greenTankInRedTankTurretLocalSpace[0]); var currentDirection = redTankTurretTransform.rotation.z; var differenceBetweenDirections = removeExcessRotation(currentDirection - directionOfGreenTank); var newRotation; @@ -544,14 +543,15 @@ document.addEventListener( "DOMContentLoaded", function( e ) { 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) -// ] -// )); - - var currentRotation = redTankTransform.rotation.z; + 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); @@ -559,7 +559,7 @@ document.addEventListener( "DOMContentLoaded", function( e ) { //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.rotationDirection = changeInDirection > 0 ? 1 : -1; redTank.doneRotation = false; redTank.doneMovement = false; physicsBody.setAngularVelocity(tankRotationSpeed * redTank.rotationDirection); From 6752c0503ee66e606188a2625863e8fb4e6a207e Mon Sep 17 00:00:00 2001 From: David Perit Date: Fri, 21 Sep 2012 15:57:13 -0400 Subject: [PATCH 19/19] Fixed green tank turret rotation --- examples/tank/tank.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/tank/tank.js b/examples/tank/tank.js index a803859..3e70b85 100644 --- a/examples/tank/tank.js +++ b/examples/tank/tank.js @@ -262,10 +262,10 @@ document.addEventListener( "DOMContentLoaded", function( e ) { physBody.setLinearVelocity(tankVelocity[0],tankVelocity[1]); physBody.setAngularVelocity(rotation); if (controller.states["TurnTurretLeft"] ) { - turretTransform.rotation.add([0, (space.clock.delta/1000) * greenTankTurretRotationSpeed, 0]); + turretTransform.rotation.add([0, 0, (space.clock.delta/1000) * greenTankTurretRotationSpeed]); } if (controller.states["TurnTurretRight"] ) { - turretTransform.rotation.add([0, (space.clock.delta/1000) * -greenTankTurretRotationSpeed, 0]); + turretTransform.rotation.add([0, 0, (space.clock.delta/1000) * -greenTankTurretRotationSpeed]); } } @@ -543,12 +543,12 @@ document.addEventListener( "DOMContentLoaded", function( e ) { 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) - ] - )); +// 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;