ATTACHING IMAGES

22
Oct
2012

This demo here shows how to attach images/css to bodies in Box2dWeb world. I have used jCanvas for working with canvas element. It is easier to understand the code if jCanvas is used.

Using CSS to display bodies:

First delete the line
world.DrawDebugData();
from the update() & add the following lines in update().
$("canvas").clearCanvas();	// Clears the previous frame before drawing a new frame
for (b = world.GetBodyList() ; b; b = b.GetNext())	// Iterating over all the bodies in the world
{
	var angle = b.GetAngle()*(180/Math.PI);	// Get current angle
	for(f = b.GetFixtureList(); f; f = f.GetNext()) {
		if (b.GetUserData() == 'circle')	// If body is circle
		{
			var radius = f.GetShape().GetRadius();
			var pos = b.GetPosition();
			$("canvas")
			.rotateCanvas({		// Rotating the canvas by the current angle of the body
				x: pos.x * 30, y: pos.y * 30,
				rotate: angle
			})
			.drawArc({		// Drawing the body
				fillStyle: "#0099FF",						  
				x: pos.x * 30, y: pos.y * 30,
				radius: radius * 30
			})
			.restoreCanvas();
		}
		else if (b.GetUserData() == 'rectangle')	// If body is Rectangle
		{	
			var X = f.GetShape().GetVertices()[1].x - f.GetShape().GetVertices()[0].x;	// Width of the body
			var Y = f.GetShape().GetVertices()[2].y - f.GetShape().GetVertices()[1].y;	// Height of the body
			var pos = b.GetPosition();
			$("canvas")
			.rotateCanvas({ 	// Rotating the canvas by the current angle of the body
				x: pos.x * 30, y: pos.y * 30,
				rotate: angle
			})
			.drawRect({		// Drawing the body
				fillStyle: "#8cc924",
				x: pos.x * 30, y: pos.y * 30,
				width: X * 30,
				height: Y * 30,
				cornerRadius: 0
			})
			.restoreCanvas();
		}
	}
}

Here 30 is the scale. 1 unit = 30 pixels. pos.x & pos.y are in Box2dWeb unit (meters) but we need to feed the x and y position, while drawing the circle or rectangle, in pixels so we multiply it by 30.

To identify whether a body is rectangle or a circle, I've set the body's User Data to circle and rectangle as applicable.
bodyDef.userData = 'rectangle';

Here is a demo of CSS as Bodies in Box2dweb.



Using IMAGES to display bodies:

As in the previous method, first delete the line
world.DrawDebugData();
from the update() & add the following lines in update().
			$("canvas").clearCanvas();
			for (b = world.GetBodyList() ; b; b = b.GetNext())
			{
				  var angle = b.GetAngle()*(180/Math.PI);
				  var pos = b.GetPosition();
                  
                  // Using Images to display bodies
				  if (b.GetUserData() != 'ground'){	
					  $("canvas")
					  .rotateCanvas({
						  x: pos.x * 30, y: pos.y * 30,
						  rotate: angle
					  })
					  .drawImage({
						  source: b.GetUserData(),
						  x: pos.x * 30, y: pos.y * 30,
						  fromCenter: true
					  })
					  .restoreCanvas();
				   }
                   
                   // Using CSS to draw ground
				   else if(b.GetUserData() == 'ground')	{
					   $("canvas").drawRect({
						  fillStyle: "#8cc924",
						  x: pos.x * 30, y: pos.y * 30,
						  width: 20 * 30,	// 600px
						  height: 1 * 30,	// 30px
						  cornerRadius: 0
					  })
				   }				
			}
            

Also I've created bodies in such a way that every body's User Data contains the location of the images. Ground Body has it's User Data set to ground.
		// Boxes
		for(i=0; i < 8; i++)	{			
			var colour = ['gold','green','lime','orange','pink','purple','red','turquoise'];
			var src = 'images/'+colour[i]+'.png'; // For Example one of src will look like --- 'images/red.png'
			
			var X = Math.round(Math.random()*20);	// Random X Position within the Canvas
			var Y = Math.round(Math.random()*14);	// Random Y Position within the Canvas
			var bodyDef = new b2BodyDef;
			bodyDef.type = b2Body.b2_dynamicBody;
			bodyDef.position.Set(X,Y);
			bodyDef.userData = src;		// Location of Image set as User Data
			
			var fixDef = new b2FixtureDef;
			fixDef.density = 10.0;
			fixDef.friction = .9;
			fixDef.restitution = .2; 
			fixDef.shape = new b2PolygonShape;
			fixDef.shape.SetAsBox((40/60),(40/60)); // 40 pixels x 40 pixels = Size of the Images = Size of the Body
			
			world.CreateBody(bodyDef).CreateFixture(fixDef);
		}
        
        // Ground
        var bodyDef = new b2BodyDef;
		bodyDef.type = b2Body.b2_staticBody;
		bodyDef.position.Set(10,13);
		bodyDef.userData = 'ground';
		
		var fd = new b2FixtureDef;
		fd.shape = new b2PolygonShape;
		fd.shape.SetAsBox(10,0.5);	// 20 units x 1 unit = 600px x 30px with 30 being the scale factor
		  
        var ground = world.CreateBody(bodyDef);
        ground.CreateFixture(fd);
Here is a demo of IMAGES as Bodies in Box2dweb.



In the demo for the above example (images) the image is first loaded and then drawn on the canvas (the code for that has not been shown. check the source code if you want more information) unlike the code which I've shown you in the tutorial where it just draw the images (it doesn't matter whether the image has been loaded or not). The code which have been shown here works just fine when running the example locally or on a very fast internet connection. Click here to see what happens if you don't load the images and then draw.

The above two examples' code just gives you the basic idea about using Images/CSS as replacement for boring & dull bodies rendered by Box2dWeb.

As always use your IMAGINATION and CREATIVITY to use images/css in a very different way!! :)

By administrator at 12:27:20 AM 7 Comment(s)

Comments

There is an error while loading multiple images into canvas 4Uncaught TypeError: Cannot read property 'getContext' of null
By Rahul on 23 Oct, 2012 at 05:01:51 PM
Yeah. I've seen the error but I can't figure out what is causing the error. But I do know this error is popping up after I added the code to load the images before drawing on the canvas. Even with this error I've not seen any side effects.
By administrator on 23 Oct, 2012 at 09:56:43 PM

Do you have any ideas of how to apply sprites/images to joints.

By dlubean on 13 Jan, 2013 at 01:11:15 PM

hello, i just need a clarification.
the reason that we delete world.DrawDebugData(); from update() is because
world.DrawDebugData() basically automatically renders the bodies which we do not
need because here is shown how to do it manualy.
Did i get it right?

By haris on 28 Aug, 2014 at 08:42:20 AM

@haris first of all apologies for the late reply. The reason we delete world.DrawDebugData() is that we do not want Box2dWeb to render anything. We want to render every body by images and that's why we deleted that line.e deleted that line.

By administrator on 7 Sep, 2014 at 10:21:15 PM

Need some more clarifications… sorry.
First of all i tried to find all the code that you used for the "Using images to display bodies", is it the bodies_images.html? Anyhow I'm basing the questions on that file also.
I) Does the attachment of images have to be in update()? Is it, like a reconfirmation of image attachment in every single step?
II)Does 'var sources'(or var colour & var src, in this webpage) actually links to a file in a folder like the tag?
III).clearRect instead of .clearCanvas is ok?(i don't use jcanvas)
IV)why function box2bweb(images){} is empty?

Thank you in advance!

By haris on 22 Sep, 2014 at 03:05:59 PM

@haris YES!
I) Yes. Because the images has to be drawn in each frame as the position of body changes (it has to be drawn even if it remains static).
II) Yes. They do.
III) I don't know. I think it should work. Try it.
IV) What function?!?!

By administrator on 22 Sep, 2014 at 05:27:48 PM

Add a Comment

Please enter the email address.Invalid format. (Won't be Displayed)
Notify me of followup comments
Enter the displayed Code: captcha