Impact

This forum is read only and just serves as an archive. If you have any questions, please post them on github.com/phoboslab/impact

1 decade ago by Chema

Howdy,

I'm trying to implement the amusing Box2DWeb demo (https://code.google.com/p/box2dweb/ -- you'll have to download it if you have a paranoid browser) in Impact, but I've been stuck in a loop for a while... perhaps someone could break me out. So, I grabbed the physics demo and adapted the Box2DWeb's one to it. It works like this: when you click anywhere, it triggers an ig.input.state in update, which calls getBodyAtMouse, which in turn creates a small collision box around the cursor and does an ig.world.QueryAABB to check if there are any bodies beneath it. So far so good, but the query never calls getBodyCB, the callback, and being new to Box2D I'm completely stumped. I suspect the problem resides in the click coordinates I'm feeding Box2D, but after many hours I've not made any progress. Any takers?

You need only replace the main.js from the latest physics demo with this one:

DBG_ALL			= 0xFFFFF;
DBG_ERROR		= 0x1;
DBG_WARN		= 0x2;
DBG_NOTICE		= 0x4;
DBG_DEBUG		= 0x8;
DBG_DEBUG_SPAM	= 0x10;
DBG_IMPACT_DBG	= 0x20
DBG_BOX2D		= 0x30;
DBG_NOSPAM		= DBG_ALL ^ DBG_DEBUG_SPAM;

debug = DBG_NOSPAM;
//debug = false;

ig.module( 
	'game.main' 
)

.requires(
	'impact.game',
	'impact.font',

	'game.entities.player',
	'game.entities.crate',
	'game.levels.test',

	'plugins.box2d.game',
	'plugins.box2d.debug'
)

.defines(function(){

	MyGame = ig.Box2DGame.extend({

		gravity: 0, // All entities are affected by this

		// Load a font
		font: new ig.Font( 'media/04b03.font.png' ),
		clearColor: '#1b2026',

		mouseJoint: false,


		init: function() {
			// Bind keys
			ig.input.bind( ig.KEY.LEFT_ARROW, 'left' );
			ig.input.bind( ig.KEY.RIGHT_ARROW, 'right' );
			ig.input.bind( ig.KEY.UP_ARROW, 'jump' );
			ig.input.bind( ig.KEY.DOWN_ARROW, 'down' );
			ig.input.bind( ig.KEY.SPACE, 'shoot' );

			// Bind mouse clicks and touch
			ig.input.bind( ig.KEY.MOUSE1, 'MouseDown' );

			if( ig.ua.mobile ) {
				ig.input.bindTouch( '#buttonLeft', 'left' );
				ig.input.bindTouch( '#buttonRight', 'right' );
				ig.input.bindTouch( '#buttonShoot', 'shoot' );
				ig.input.bindTouch( '#buttonJump', 'jump' );
			}

			// Load the LevelTest as required above ('game.level.test')
			this.loadLevel( LevelTest);
			if ( debug & DBG_BOX2D )
				this.debugDrawer = new ig.Box2DDebug( ig.world );
			if ( debug & DBG_DEBUG )
				document.addEventListener("mousedown", function(e) {
					console.log("Event mousedown at: "+ e.clientX +", "+
								e.clientY); }, true);
		},

		loadLevel: function( data ) {
			this.parent( data );
			for( var i = 0; i < this.backgroundMaps.length; i++ ) {
				this.backgroundMaps[i].preRender = true;
			}
		},

		update: function() {
			var click = this.ClickCoordinates(ig.input.mouse.x,
												 ig.input.mouse.y);

			// .state and .pressed both activate on click
			if( ig.input.pressed("MouseDown") ) {
				if (debug & DBG_DEBUG)
					console.log("ig.input.pressed MouseDown at: "+
								JSON.stringify(click) +
								" (ig.input.mouse: "+
								ig.input.mouse.x +", "+ ig.input.mouse.y +").");
			}

			if( ig.input.state("MouseDown") ) {
				if (debug & DBG_DEBUG_SPAM) 
					console.log("ig.input.state MouseDown at: "+
								JSON.stringify(click) +
								" (ig.input.mouse: "+
								ig.input.mouse.x +", "+ ig.input.mouse.y +").");

				if(!this.mouseJoint) {
					var body = this.getBodyAtMouse();
					if(body) {
						var md = new Box2D.Dynamics.Joints.b2MouseJointDef();
						md.bodyA = ig.world.GetGroundBody();
						md.bodyB = body;
						md.target.Set(click.x, click.y);
						md.collideConnected = true;
						md.maxForce = 300.0 * body.GetMass();
						this.mouseJoint = ig.world.CreateJoint(md);
						body.SetAwake(true);
					}
				}
			}

			if(this.mouseJoint) {
				if(ig.input.state("MouseDown")) {
					this.mouseJoint.SetTarget(
						new Box2D.Common.Math.b2Vec2(click.x, click.y));
				} else {
					ig.world.DestroyJoint(this.mouseJoint);
					this.mouseJoint = null;
				}
			}
			// .state and .released both activate on release
			if( ig.input.released("MouseDown") ) {
				if (debug & DBG_DEBUG_SPAM)
					console.log("ig.input.released MouseDown at: "+
								JSON.stringify(click) +
								" (ig.input.mouse: "+
								ig.input.mouse.x +", "+ ig.input.mouse.y +").");
			}

			// Update all entities and BackgroundMaps, call Step and ClearForces
			this.parent();

			// screen follows the player
			var player = this.getEntitiesByType( EntityPlayer )[0];
			if( player ) {
				this.screen.x = player.pos.x - ig.system.width/2;
				this.screen.y = player.pos.y - ig.system.height/2;
			}
		},

		draw: function() {
			// Draw all entities and BackgroundMaps
			this.parent();

			if ( debug & DBG_BOX2D ) this.debugDrawer.draw();

			if( !ig.ua.mobile ) {
				this.font.draw( 'Arrow Keys + Space', 2, 2 );
			}
		},

		getBodyAtMouse: function() {
			// Box2D requires window coordinates
			var click = this.ClickCoordinates(ig.input.mouse.x,
												 ig.input.mouse.y);

			var aabb = new Box2D.Collision.b2AABB();
			aabb.lowerBound.Set(click.x - 0.001, click.y - 0.001);
			aabb.upperBound.Set(click.x + 0.001, click.y + 0.001);

			// Query the world for overlapping shapes.
			this.selectedBody = null;
			ig.world.QueryAABB(this.getBodyCB, aabb);
			return this.selectedBody;
		},

		getBodyCB: function(fixture) {
			var click = this.ClickCoordinates(ig.input.mouse.x,
												 ig.input.mouse.y);
			this.mousePVec = new b2Vec2(click.x, click.y);

			if (debug & DBG_DEBUG)
				console.log("getBodyCB: Called with fixture "+ fixture);

			if(fixture.GetBody().GetType() !=
			   Box2D.Dynamics.b2Body.b2_staticBody) {

				if(fixture.GetShape().TestPoint(fixture.GetBody().GetTransform(),
												mousePVec)) {
					this.selectedBody = fixture.GetBody();
					return false;
				}
			}
			return true;
		},

		ClickCoordinates: function(localX, localY) {
			return { x: localX,
					 y: localY };
		},

		// http://js-tut.aardon.de/js-tut/tutorial/position.html
		getElementPosition: function(element) {
			var elem=element, tagname="", x=0, y=0;

			while((typeof(elem) == "object") &&
				  (typeof(elem.tagName) != "undefined")) {

				y += elem.offsetTop;
				x += elem.offsetLeft;
				tagname = elem.tagName.toUpperCase();

				if(tagname == "BODY")
					elem=0;

				if(typeof(elem) == "object") {
					if(typeof(elem.offsetParent) == "object")
						elem = elem.offsetParent;
				}
			}

			return {x: x, y: y};
		}


	});


	if( ig.ua.iPad ) {
		ig.Sound.enabled = false;
		ig.main('#canvas', MyGame, 60, 240, 160, 2);
	}
	else if( ig.ua.mobile ) {	
		ig.Sound.enabled = false;
		ig.main('#canvas', MyGame, 60, 160, 160, 2);
	}
	else {
		ig.main('#canvas', MyGame, 60, 320, 240, 2);
	}

});

1 decade ago by Chema

Typical. All the inspiration comes after asking for help. ;)


All done! Throw in a bunch of entities and go wild!

DBG_ALL			= 0xFFFFF;
DBG_ERROR		= 0x1;
DBG_WARN		= 0x2;
DBG_NOTICE		= 0x4;
DBG_DEBUG		= 0x8;
DBG_DEBUG_SPAM	= 0x10;
DBG_IMPACT_DBG	= 0x20
DBG_BOX2D		= 0x30;
DBG_NOSPAM		= DBG_ALL ^ DBG_DEBUG_SPAM;

debug = DBG_NOSPAM;
//debug = false;

ig.module( 
	'game.main' 
)

.requires(
	'impact.game',
	'impact.font',

	'game.entities.player',
	'game.entities.crate',
//	'game.entities.circle',
	'game.levels.test',

	'plugins.box2d.game',
	'plugins.box2d.debug'
)

.defines(function(){

	MyGame = ig.Box2DGame.extend({

		gravity: 0, // All entities are affected by this

		// Load a font
		font: new ig.Font( 'media/04b03.font.png' ),
		clearColor: '#1b2026',

		mouseJoint: false,


		init: function() {
			// Bind keys
			ig.input.bind( ig.KEY.LEFT_ARROW, 'left' );
			ig.input.bind( ig.KEY.RIGHT_ARROW, 'right' );
			ig.input.bind( ig.KEY.UP_ARROW, 'jump' );
			ig.input.bind( ig.KEY.DOWN_ARROW, 'down' );
			ig.input.bind( ig.KEY.SPACE, 'shoot' );

			// Bind mouse clicks and touch
			ig.input.bind( ig.KEY.MOUSE1, 'MouseDown' );

			if( ig.ua.mobile ) {
				ig.input.bindTouch( '#buttonLeft', 'left' );
				ig.input.bindTouch( '#buttonRight', 'right' );
				ig.input.bindTouch( '#buttonShoot', 'shoot' );
				ig.input.bindTouch( '#buttonJump', 'jump' );
			}

			// Load the LevelTest as required above ('game.level.test')
			this.loadLevel( LevelTest );
			if ( debug & DBG_BOX2D )
				this.debugDrawer = new ig.Box2DDebug( ig.world );
			if ( debug & DBG_DEBUG )
				document.addEventListener("mousedown", function(e) {
					console.log("Event mousedown at: "+ e.clientX +", "+
								e.clientY); }, true);
		},

		loadLevel: function( data ) {
			this.parent( data );
			for( var i = 0; i < this.backgroundMaps.length; i++ ) {
				this.backgroundMaps[i].preRender = true;
			}
		},

		update: function() {
			var click = this.ClickCoordinates(ig.input.mouse.x,
												 ig.input.mouse.y);

			// .state and .pressed both activate on click
			if( ig.input.pressed("MouseDown") ) {
				if (debug & DBG_DEBUG)
					console.log("ig.input.pressed MouseDown at: "+
								JSON.stringify(click) +
								" (ig.input.mouse: "+
								ig.input.mouse.x +", "+ ig.input.mouse.y +").");
			}

			if( ig.input.state("MouseDown") ) {
				if (debug & DBG_DEBUG_SPAM) 
					console.log("ig.input.state MouseDown at: "+
								JSON.stringify(click) +
								" (ig.input.mouse: "+
								ig.input.mouse.x +", "+ ig.input.mouse.y +").");

				if(!this.mouseJoint) {
					var body = this.getBodyAtMouse();
					if(body) {
						var md = new Box2D.Dynamics.Joints.b2MouseJointDef();
						md.bodyA = ig.world.GetGroundBody();
						md.bodyB = body;
						md.target.Set(click.x, click.y);
						md.collideConnected = true;
						md.maxForce = 300.0 * body.GetMass();
						this.mouseJoint = ig.world.CreateJoint(md);
						body.SetAwake(true);
					}
				}
			}

			if(this.mouseJoint) {
				if(ig.input.state("MouseDown")) {
					this.mouseJoint.SetTarget(
						new Box2D.Common.Math.b2Vec2(click.x, click.y));
				} else {
					ig.world.DestroyJoint(this.mouseJoint);
					this.mouseJoint = null;
				}
			}
			// .state and .released both activate on release
			if( ig.input.released("MouseDown") ) {
				if (debug & DBG_DEBUG_SPAM)
					console.log("ig.input.released MouseDown at: "+
								JSON.stringify(click) +
								" (ig.input.mouse: "+
								ig.input.mouse.x +", "+ ig.input.mouse.y +").");
			}

			// Update all entities and BackgroundMaps, call Step and ClearForces
			this.parent();

			// screen follows the player
			var player = this.getEntitiesByType( EntityPlayer )[0];
			if( player ) {
				this.screen.x = player.pos.x - ig.system.width/2;
				this.screen.y = player.pos.y - ig.system.height/2;
			}
		},

		draw: function() {
			// Draw all entities and BackgroundMaps
			this.parent();

			if ( debug & DBG_BOX2D ) this.debugDrawer.draw();

			if( !ig.ua.mobile ) {
				this.font.draw( 'Arrow Keys + Space', 2, 2 );
			}
		},

		getBodyAtMouse: function() {
			// Box2D requires window coordinates
			var click = this.ClickCoordinates(ig.input.mouse.x,
												 ig.input.mouse.y);

			var aabb = new Box2D.Collision.b2AABB();
			aabb.lowerBound.Set(click.x - 0.001, click.y - 0.001);
			aabb.upperBound.Set(click.x + 0.001, click.y + 0.001);

			// Query the world for overlapping shapes.
			this.selectedBody = null;
			ig.world.QueryAABB(this.getBodyCB, aabb);
			return this.selectedBody;
		},

		getBodyCB: function(fixture) {
			var click = ig.game.ClickCoordinates(ig.input.mouse.x,
												 ig.input.mouse.y);
			this.mousePVec = new Box2D.Common.Math.b2Vec2(click.x, click.y);

			if (debug & DBG_DEBUG_SPAM)
				console.log("getBodyCB: fixture type = "+ fixture.GetBody().GetType());

			if(fixture.GetBody().GetType() !=
			   Box2D.Dynamics.b2Body.b2_staticBody) {

				if(fixture.GetShape().TestPoint(fixture.GetBody().GetTransform(),
												mousePVec)) {
					ig.game.selectedBody = fixture.GetBody();
					return false;
				}
			}
			return true;
		},

		ClickCoordinates: function(localX, localY) {
			return { x: (localX + ig.game.screen.x) * Box2D.SCALE,
					 y: (localY + ig.game.screen.y) * Box2D.SCALE };
		}
	});


	if( ig.ua.iPad ) {
		ig.Sound.enabled = false;
		ig.main('#canvas', MyGame, 60, 240, 160, 2);
	}
	else if( ig.ua.mobile ) {	
		ig.Sound.enabled = false;
		ig.main('#canvas', MyGame, 60, 160, 160, 2);
	}
	else {
		ig.main('#canvas', MyGame, 60, 320, 240, 2);
	}

});
Page 1 of 1
« first « previous next › last »