package com.deftwun.zombiecopter.box2dJson;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.Joint;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Logger;
import com.badlogic.gdx.utils.ObjectMap;
/*
Manages multiple bodies, joints (..planned), and fixtures. Also able to be
serialized and rebuilt from json data (..using PhysicsModel,BodyModel,FixtureModel,etc..)
*/
public class PhysicsScene{
private Logger logger = new Logger("PhysicsScene",Logger.INFO);
private static long uniqueId = 0;
private Body primaryBody = null;
private World world = null;
private ObjectMap<String, Joint> joints = new ObjectMap<String,Joint>();
private ObjectMap<String, Body> bodies = new ObjectMap<String,Body>();
private ObjectMap<String, Fixture> fixtures = new ObjectMap<String,Fixture>();
private PhysicsSceneListener listener = null;
public interface PhysicsSceneListener{
public void fixtureAdded(Fixture f);
public void bodyAdded(Body b);
public void jointAdded(Joint j);
public void fixtureRemoved(Fixture f);
public void bodyRemoved(Body b);
public void jointRemoved(Joint j);
}
public PhysicsScene(World w){
logger.debug("Creating scene using world");
world = w;
}
public PhysicsScene(){
logger.debug("Creating scene using new default world");
world = new World(new Vector2(),true);
}
public void setPhysicsSceneListener(PhysicsSceneListener l){
listener = l;
}
//Create everything from a PhysicsSceneModel
public void createFromModel(PhysicsSceneModel model){
logger.debug("create from model");
this.destroy();
for (BodyModel bm : model.bodyModels){
createBody(bm);
}
for (JointModel jm : model.jointModels){
createJoint(jm);
}
primaryBody = bodies.get(model.primaryBody,null);
if (primaryBody == null && bodies.size > 0)
primaryBody = bodies.values().toArray().get(0);
}
public void setPrimaryBody(String name){
logger.debug("Set primary body: " + name);
primaryBody = bodies.get(name,null);
}
public Body getPrimaryBody(){
return primaryBody;
}
//Create Body
public Body createBody(BodyModel bm){
logger.debug("create Body from model: " + bm.name);
String name = uniqueBodyName(bm.name);
Body body = bm.toBody(world);
if (primaryBody == null){
primaryBody = body;
}
bodies.put(name,body);
if (listener != null) listener.bodyAdded(body);
for (FixtureModel fm : bm.fixtures){
Fixture f = fm.toFixture(body);
fm.name = uniqueFixtureName(fm.name);
fixtures.put(fm.name,f);
if (listener != null) listener.fixtureAdded(f);
}
return body;
}
//Add Body
public String addBody(Body b){
String name = uniqueBodyName("body");
this.addBody(name, b);
return name;
}
//Add body
public String addBody(String name,Body b){
logger.debug("Add body: " + name);
if (primaryBody == null){
primaryBody = b;
}
bodies.put(name,b);
if (listener != null) listener.bodyAdded(b);
for (Fixture f : b.getFixtureList()){
String fixName = uniqueFixtureName("fixture");
logger.debug("add fixture: " + fixName);
fixtures.put(fixName,f);
if (listener != null) listener.fixtureAdded(f);
}
return name;
}
//Create Joint
public Joint createJoint(JointModel jm){
String name = uniqueJointName(jm.name);
logger.debug("Creating Joint from model: " + name + " = " + jm.bodyA + "+" + jm.bodyB);
Body bodyA = bodies.get(jm.bodyA),
bodyB = bodies.get(jm.bodyB);
if (bodyA == null) logger.error("Can't create Joint. Body: " + jm.bodyA + " not found in scene.");
if (bodyB == null) logger.error("Can't create Joint. Body: " + jm.bodyB + " nof found in scene.");
Joint joint = jm.toJoint(world,bodyA,bodyB);
joints.put(name,joint);
logger.debug("Joint count = " + joints.size);
if (listener != null) listener.jointAdded(joint);
return joint;
}
//Add joint
public String addJoint(Joint j){
String name = uniqueJointName("joint");
return this.addJoint(name,j);
}
//Add joint
public String addJoint(String name, Joint j){
logger.debug("Joint added: " + name);
joints.put(name,j);
if (listener != null) listener.jointAdded(j);
return name;
}
//Check if body exists in the scene
public boolean hasBody(String name){
return bodies.containsKey(name);
}
public boolean hasBody(Body b){
return bodies.containsValue(b,true);
}
//Check if fixture exists in the scene
public boolean hasFixture(String name){
return fixtures.containsKey(name);
}
public boolean hasFixture(Fixture f){
return fixtures.containsValue(f,true);
}
//Check if joint exists in the scene
public boolean hasJoint(String name){
return joints.containsKey(name);
}
public boolean hasJoint(Joint j){
return joints.containsValue(j,true);
}
//Get name of body
public String getName(Body b){
for (ObjectMap.Entry<String,Body> entry : bodies){
if (entry.value == b) return entry.key;
}
return "";
}
//Get name of fixture
public String getName(Fixture f){
for (ObjectMap.Entry<String,Fixture> entry : fixtures){
if (entry.value == f) return entry.key;
}
return "";
}
//Get name of joint
public String getName(Joint j){
for (ObjectMap.Entry<String,Joint> entry : joints){
if (entry.value == j) return entry.key;
}
return "";
}
//Get body
public Body getBody(String name){
return bodies.get(name);
}
//Get fixture
public Fixture getFixture(String name){
return fixtures.get(name);
}
//Get joint
public Joint getJoint(String name){
return joints.get(name);
}
//Get all fixtures
public Array<Fixture> getFixtures(){
return fixtures.values().toArray();
}
//Get all bodies
public Array<Body> getBodies(){
return bodies.values().toArray();
}
//Get all joints
public Array<Joint> getJoints(){
return joints.values().toArray();
}
//Destroy everything
public void destroy(){
logger.debug(String.format("Destroying: %d fixtures, %d bodies, & %d joints...",
fixtures.size,bodies.size,joints.size));
for (Joint j : joints.values()){
world.destroyJoint(j);
if (listener != null) listener.jointRemoved(j);
logger.debug("Joint Destroyed");
}
for (Body b : bodies.values()){
for (Fixture f : b.getFixtureList()){
b.destroyFixture(f);
if (listener != null) listener.fixtureRemoved(f);
logger.debug("Fixture Destroyed");
}
world.destroyBody(b);
if (listener != null) listener.bodyRemoved(b);
logger.debug("Body Destroyed");
}
fixtures.clear();
bodies.clear();
joints.clear();
uniqueId = 0;
primaryBody = null;
logger.debug("---Destroyed");
}
//Destroy body
public void destroyBody(String name){
logger.debug("Destroy body: " + name);
Body b = bodies.get(name,null);
if (b != null){
//Check if its the primary body. If so, then automatically set a new primary
if (b == primaryBody){
if (bodies.size > 0)
primaryBody = (Body) bodies.values().toArray().get(0);
else primaryBody = null;
}
world.destroyBody(b);
bodies.remove(name);
if (listener != null) listener.bodyRemoved(b);
}
else logger.debug("Could not destroy body: " + name + " not found");
}
//Destroy Fixture
public void destroyFixture(String name){
logger.debug("Destroy fixture: " + name);
Fixture f = fixtures.get(name);
if (f != null){
f.getBody().destroyFixture(f);
fixtures.remove(name);
if (listener != null) listener.fixtureRemoved(f);
}
else logger.debug("Could not destroy fixture: " + name + " not found");
}
//Destroy joint
public void destroyJoint(String name){
logger.debug("Destroy Joint: " + name);
Joint j = joints.get(name);
if (j != null){
world.destroyJoint(j);
joints.remove(name);
if (listener != null) listener.jointRemoved(j);
}
else logger.debug("Could not destroy joint: " + name + " not found");
}
//Create Scene model
public PhysicsSceneModel toSceneModel(){
logger.debug("Creating Scene Model");
PhysicsSceneModel physicsModel = new PhysicsSceneModel();
//Bodies
for (ObjectMap.Entry<String,Body> bodyEntry : bodies.entries()){
BodyModel bodyModel = new BodyModel(bodyEntry.key,bodyEntry.value);
//clear un-named fixtures. We'll manually add them with names included
bodyModel.fixtures.clear();
//Fixtures
for (ObjectMap.Entry<String,Fixture> fixtureEntry : fixtures.entries()){
if (fixtureEntry.value.getBody() == bodyEntry.value){
FixtureModel fixModel = new FixtureModel(fixtureEntry.key,fixtureEntry.value);
bodyModel.fixtures.add(fixModel);
}
}
physicsModel.bodyModels.add(bodyModel);
}
//Joints
for (ObjectMap.Entry<String,Joint> jointEntry : joints.entries()){
Joint j = jointEntry.value;
JointModel jointModel = new JointModel(jointEntry.key,jointEntry.value,getName(j.getBodyA()), getName(j.getBodyB()));
physicsModel.jointModels.add(jointModel);
}
return physicsModel;
}
//generates a unique body name using the given prefix
private String uniqueBodyName(String prefix){
String s = prefix;
while (bodies.containsKey(prefix))
s = prefix + uniqueId++;
return s;
}
//generates a unique fixture name using the given prefix
private String uniqueFixtureName(String prefix){
String s = prefix;
while (fixtures.containsKey(s)) s = prefix + uniqueId++;
return s;
}
//generates a unique joint name using the given prefix
private String uniqueJointName(String prefix){
String s = prefix;
while (fixtures.containsKey(s)) s = prefix + uniqueId++;
return s;
}
}