function addBody(bodyDef, fixDef, bodyMesh) {
	var geometry;
	var body = physicsWorld.CreateBody(bodyDef);
	body.CreateFixture(fixDef);
	body.SetAwake(1);
	body.SetActive(1);
	if(!bodyMesh) {
		if(fixDef.width && fixDef.height) {
			geometry = new THREE.PlaneGeometry(fixDef.width, fixDef.height, 1, 1);
		} else if(fixDef.radius) {
			geometry = new THREE.SphereGeometry(fixDef.radius, 8, 4);
		} else {
			throw new Error('Cannot deduce desired shape.');
		}
		bodyMesh = new THREE.Mesh(geometry);
	}
	bodyMesh.body = body;
	body.bodyMesh = bodyMesh;
	scene.add(bodyMesh);
	bodyMeshes.push(bodyMesh);
	if(bodyMesh.updateRotation) {
		bodyMeshesWithManualRotationUpdate.push(bodyMesh);
	}
	return body;
}
function despawnBody(body) {
	physicsWorld.DestroyBody(body);
	var mesh = body.bodyMesh;
	var index = bodyMeshes.indexOf(mesh);
	bodyMeshes.splice(index, 1);
	index = bodyMeshesWithManualRotationUpdate.indexOf(mesh);
	if(index !== -1) {
		bodyMeshesWithManualRotationUpdate.splice(index, 1);
	}
	mesh.body = null;
	body.mesh = null;
}
function update() {

	var i;
	for (i = 0; i < prePhysicsCallbacks.length; i++) {
		prePhysicsCallbacks[i]();
	}
	
	pos = avatar.body.GetPosition();
	var posX = pos.x;
	var absPosX = Math.abs(posX);
	var posXDirection = posX < 0 ? 1 : -1;
	if(absPosX > jumpDistanceHalf) {
		//avatar crossed a barrier, teleport everything
		var bodyList = physicsWorld.GetBodyList();
		var total = physicsWorld.GetBodyCount();
		var jumpX = posXDirection * jumpDistance;
		avatar.desiredLocation.x += jumpX;
		scenery.teleport(jumpX * SCALE_INV);
		for (i = total; i >= 0; i--) {
			pos = bodyList.GetPosition();
			if(bodyList !== floorBody && bodyList !== ceilingBody) {
				var x = pos.x + jumpX;
				pos.x = x;
				bodyList.SetPosition(pos);
				if(Math.abs(x) > despawnDistance) {
					bodiesToDespawn.push(bodyList);
				}
				bodyList = bodyList.GetNext();
			}
		}
		// });
		// avatar.SetTransform(new Box2D.b2Vec2(100 * SCALE, 100 * SCALE), 0);
	}
	
	physicsWorld.Step(
		1 / 60,   //frame-rate
		2,       //velocity iterations
		2       //position iterations
	);

	bodyMeshes.forEach(function(bodyMesh){
		pos = bodyMesh.body.GetPosition();
		bodyMesh.position.x = pos.x * SCALE_INV;
		bodyMesh.position.y = pos.y * SCALE_INV;
		bodyMesh.rotation.z = bodyMesh.body.GetAngle();
		if(bodyMesh.postPhysicsUpdate) {
			bodyMesh.postPhysicsUpdate();
		}
	});

	bodyMeshesWithManualRotationUpdate.forEach(function(bodyMesh) {
		bodyMesh.updateRotation();
	});

	bodiesToDespawn.forEach(function(body) {
		despawnBody(body);
	});
	bodiesToDespawn.length = 0;

	meshesToDespawn.forEach(function(mesh) {
		despawnMesh(mesh);
	});
	meshesToDespawn.length = 0;

	physicsWorld.ClearForces();
	people.forEach(function(person){
		person.updateWalk();
	});
}
var FIST_IMPULSE_TOLERANCE = 0.002;
var MAX_ENEMIES = 10;

var bodyMeshes = [];
var bodyMeshesWithManualRotationUpdate = [];
var scene;
var avatar;
var people = [];
var floorBody;
var ceilingBody;

var tempVec2 = new Box2D.b2Vec2(0, 0);

var gravity = new Box2D.b2Vec2(0, 0);
var physicsWorld = new Box2D.b2World(gravity);

var b2Listener = Box2D.Dynamics.b2ContactListener;

//Add listeners for contact
var listener = new b2Listener();

var impulseVec = new Box2D.b2Vec2();
listener.BeginContact = function(contact) {
	var bodyFist = contact.GetFixtureA().GetBody();
	var bodyPerson = contact.GetFixtureB().GetBody();
	var fist = bodyFist.GetUserData();
	var person = bodyPerson.GetUserData();
	if(!fist || !person) return;
	if(person.isWeapon && fist.isPerson) {
		var temp = fist;