Note: The parser in this tutorial has been updated by the curve parser here. This tutorial still explains InkScape and the “floors/ceilings” idea.

->

This tutorial is geared for creating levels for the Flash version of Box2D. With a little work, you can also use these on other versions of Box2D.

Things you will need

Creating Edges in Box2D

The easiest way of creating levels in Box2D uses edge chains, which can be be declared like so…

var bodyDef: b2BodyDef = new b2BodyDef();
var chainDef: b2EdgeChainDef = new b2EdgeChainDef();
chainDef.friction = 0.5;
chainDef.restitution = 0.0;
chainDef.vertices.push(new b2Vec2(x1, y1)); //Must pass b2Vec2 for line coordinates
chainDef.vertices.push(new b2Vec2(x2, y2));
chainDef.vertexCount = chainDef.vertices.length; //# of points = however many in definition
world.GetGroundBody().CreateShape(chainDef); //Create the edgeShape

However, coding these levels by hand will take you much too long, especially if your level uses curves. An easy alternative to manually coding these levels is to use InkScape, a program that allows you to create vector art and saves it in svg format.

Creating Levels in InkScape

Open up an InkScape document and go to File -> Document Properties. From here you may set the canvas size and enable a grid to help you draw.

Edges and Collision Checking

You may notice  that the Y values in on the ruler in your InkScape document start at the bottom and increase as you go up. When we convert the InkScape SVG file into Box2D coordinates, the parser (converting part of the code) will determine the side of the line that checks for collision based on how your Y coordinates are set up.

Box2D will only check collision on one side of your lines. Which side of the line is checked for collision is determined by the way you draw it in InkScape.
When your Y coordinates start at the bottom and increase as you go up, lines that go from left to right are floors, while lines that go right to left are ceilings.

Notice how the ball jumps through the line in the middle of the world. This happens when it approaches from the top because that line was drawn from right-to-left, making it a ceiling.

Importing the SVG and Parsing it

When you are done drawing your level, save it as an SVG file and open it back up in notepad. We’re going to copy everything from the the beginning of the tag to the end of the tag into a Flash AS3 variable.

var svg =
 
//All content inside SVG tags goes here
 
;

Now that we have imported the SVG, we’re going to parse it. Make a function that looks like the one below in your class.

import Box2D.Dynamics.b2World;
import Box2D.Common.Math.b2Vec2;
import Box2D.Collision.Shapes.b2EdgeChainDef;
import Box2D.Collision.Shapes.b2ShapeDef;
import Box2D.Dynamics.b2BodyDef;
import Box2D.Collision.Shapes.b2Shape;
 
//RATIO is your physics scale of pixels to meters
public static function parseThisSVG(svg: XML, world: b2World, RATIO:Number): void {
var ns: Namespace = svg.namespace("");
var bodyDef: b2BodyDef = new b2BodyDef();
var chainDef: b2EdgeChainDef = new b2EdgeChainDef();
chainDef.friction = 0.5;
chainDef.restitution = 0.0;
for each (var path: XML in svg..ns::path) {
	var d: String = path.@d;
	// split string at spaces or commas:
	var regExp: RegExp = / |,/;
	var args: Array = d.split(regExp);
	if (args[args.length-1] == "") {
		args.pop(); // removes last element;
	}
	var i: int = 1; // skip first element, which is always "M".
	chainDef.isALoop = false;
	chainDef.vertices.length = 0;
	while (true) {
		if (i == args.length - 2) {
			chainDef.vertices.push(new b2Vec2(args[i] / RATIO, args[i+1] / RATIO ));
			break;
		} else if (args[i+2] == "z" || args[i+2] == "Z" ) {
			chainDef.isALoop = true;
			break;
			} else if (args[i+2] != "L") {
				throw new Error("Unsupported: The SVG Path contains an arc command or move-to command or a relative coordinate.");
			}
			chainDef.vertices.push(new b2Vec2(args[i] / RATIO , args[i+1] / RATIO ));
			i += 3;
		}
		chainDef.vertexCount = chainDef.vertices.length;
		world.GetGroundBody().CreateShape(chainDef);
	}
}

When you call this function pass the SVG variable and your Box2D world variable to it and it will create all of the defined lines from your SVG.

Source here

That concludes the tutorial. If you need help, e-mail me or leave a comment here and I’ll see what I can do. Seeing as this is my first tutorial, constructive criticism is highly encouraged.

->

Credit for the parsing function goes to Shaktool off the Box2D forums. Another thanks to him for helping update the parser in this tutorial to the curve parser.

Related posts:

  1. Box2D SVG Parser with Curve Support