/*
* AQP Project
* http://http://code.google.com/p/aqp-project/
* Alexandre Gomez - Clément Troesch - Fabrice Latterner
*/
package com.aqpproject.physics.gdx;
import com.aqpproject.game.Singleton;
import com.aqpproject.physics.Physics;
import com.aqpproject.tools.Segment2D;
import com.aqpproject.tools.Vector2D;
import com.aqpproject.visualisation.Visualisation;
import com.aqpproject.worldmodel.WorldModel;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Shape.Type;
import com.badlogic.gdx.physics.box2d.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* GDX Physics component
*
* @author Alexandre, Clement, Fabrice
*/
public class PhysicsGDX implements Physics {
@Override
public void initialize() {
m_world = new World(new Vector2(0, 0), true);
m_bodies = new HashMap<>();
m_mapBodies = new ArrayList<>();
m_segments = new HashMap<>();
m_debugSegments = new ArrayList<>();
m_bodiesSizes = new HashMap<>();
m_active = false;
m_positionsToModify = new HashMap<>();
m_velocitiesToModify = new HashMap<>();
m_rotationToModify = new HashMap<>();
m_isPaused = false;
m_world.setContactListener(new ContactListener() {
@Override
public void beginContact(Contact cntct) {
WorldManifold wm = cntct.getWorldManifold();
Singleton.getWorldModel().startContact(cntct.getFixtureA().getBody().getUserData().toString(), cntct.getFixtureB().getBody().getUserData().toString(), toVector2D(wm.getNormal()), toVector2D(wm.getPoints()[0]).scale(PIXELS_PER_METERS));
}
@Override
public void endContact(Contact cntct) {
WorldManifold wm = cntct.getWorldManifold();
Singleton.getWorldModel().stopContact(cntct.getFixtureA().getBody().getUserData().toString(), cntct.getFixtureB().getBody().getUserData().toString(), toVector2D(wm.getNormal()), toVector2D(wm.getPoints()[0]).scale(PIXELS_PER_METERS));
}
@Override
public void preSolve(Contact cntct, Manifold mnfld) {
}
@Override
public void postSolve(Contact cntct, ContactImpulse ci) {
}
});
}
@Override
public void destroy() {
}
@Override
public void createBody(String name, Vector2D position, float rotation, Vector2D size, float density, float linearDamping, float angularDamping) {
/*
* BodyDef Creation
*/
BodyDef bodydef = new BodyDef();
bodydef.type = BodyDef.BodyType.DynamicBody;
bodydef.position.set(position.x / PIXELS_PER_METERS, position.y / PIXELS_PER_METERS);
bodydef.awake = false;
Body body = m_world.createBody(bodydef);
body.setUserData(name);
/*
* Shape creation
*/
PolygonShape shape = new PolygonShape();
Vector2 pos = new Vector2(size.x / (2.f * PIXELS_PER_METERS), size.y / (2.f * PIXELS_PER_METERS));
shape.setAsBox(size.x / (2.f * PIXELS_PER_METERS), size.y / (2.f * PIXELS_PER_METERS), pos, 0);
m_bodiesSizes.put(name, new Vector2D(size));
/*
* Body Creation
*/
body.createFixture(shape, density);
shape.dispose();
body.setLinearVelocity(0, 0);
body.setLinearDamping(linearDamping);
body.setAngularDamping(angularDamping);
body.setTransform(position.x / PIXELS_PER_METERS, position.y / PIXELS_PER_METERS, (float) (rotation * Math.PI / 180f));
m_bodies.put(name, body);
}
@Override
public void createMapBodies() {
for (int x = 0; x < Singleton.getVisualisation().getMapWidth(); x++) {
for (int y = 0; y < Singleton.getVisualisation().getMapHeight(); y++) {
int id = Singleton.getVisualisation().getTile(Visualisation.MAP_LAYER.STATIC_OBJECTS, new Vector2D(x * 64, y * 64));
String code = "" + id;
if (m_segments.containsKey(code)) {
ArrayList<Segment2D> segments = m_segments.get(code);
for (Segment2D seg : segments) {
/*
* BodyDef Creation
*/
BodyDef bodydef = new BodyDef();
bodydef.type = BodyDef.BodyType.StaticBody;
Body body = m_world.createBody(bodydef);
body.setUserData("StaticBody");
/*
* Shape creation
*/
EdgeShape shape = new EdgeShape();
Vector2 first = toVector2(new Vector2D(seg.getFirst()).translate((x) * 64, (y) * 64).scale(1.f / PIXELS_PER_METERS));
Vector2 second = toVector2(new Vector2D(seg.getSecond()).translate((x) * 64, (y) * 64).scale(1.f / PIXELS_PER_METERS));
shape.set(first, second);
/*
* Body Creation
*/
body.createFixture(shape, 0);
shape.dispose();
m_debugSegments.add(new Segment2D(new Vector2D(seg.getFirst()).translate((x) * 64, (y) * 64), new Vector2D(seg.getSecond()).translate((x) * 64, (y) * 64)));
m_mapBodies.add(body);
}
}
}
}
}
@Override
public void deleteBody(String name) {
m_world.destroyBody(m_bodies.get(name));
m_bodies.remove(name);
}
@Override
public void deleteMapBodies() {
while (!m_mapBodies.isEmpty()) {
m_world.destroyBody(m_mapBodies.get(0));
m_mapBodies.remove(0);
}
}
@Override
public void applyLinearForce(String name, Vector2D vel) {
m_bodies.get(name).applyForceToCenter(toVector2(new Vector2D(vel).scale(1.f / PIXELS_PER_METERS)));
}
@Override
public void applyAngularForce(String name, float vel) {
m_bodies.get(name).applyTorque(vel);
}
@Override
public Vector2D getBodyPosition(String name) {
return toVector2D(m_bodies.get(name).getPosition()).scale(PIXELS_PER_METERS);
}
@Override
public void setBodyPosition(String name, Vector2D position) {
Vector2 pos = toVector2(new Vector2D(position).scale(1.f / PIXELS_PER_METERS));
float rotation = m_bodies.get(name).getAngle();
m_bodies.get(name).setTransform(pos, rotation);
}
@Override
public void resetBody(String name, Vector2D position, Vector2D velocity, float rotation) {
m_positionsToModify.put(name, position);
m_velocitiesToModify.put(name, velocity);
m_rotationToModify.put(name, rotation);
}
private void updateBodyPosition() {
while (!m_positionsToModify.isEmpty()) {
String name = m_positionsToModify.keySet().iterator().next();
Vector2D position = m_positionsToModify.remove(name);
Vector2D velocity = m_velocitiesToModify.remove(name);
float rotation = m_rotationToModify.remove(name);
if (m_bodies.containsKey(name)) {
Vector2 pos = toVector2(new Vector2D(position).scale(1.f / PIXELS_PER_METERS));
// float rotation = m_bodies.get(name).getAngle();
m_bodies.get(name).setTransform(pos, rotation);
m_bodies.get(name).setLinearVelocity(toVector2(new Vector2D(velocity).scale(1.f / PIXELS_PER_METERS)));
}
}
}
@Override
public Vector2D getBodyCenter(String name) {
Body body = m_bodies.get(name);
Vector2D size = m_bodiesSizes.get(name);
return toVector2D(body.getTransform().mul(new Vector2(size.x / (PIXELS_PER_METERS * 2.f), size.y / (PIXELS_PER_METERS * 2.f)))).scale(PIXELS_PER_METERS);
}
@Override
public float getBodyRotation(String name) {
return (float) (m_bodies.get(name).getAngle() * 180.f / Math.PI);
}
@Override
public Vector2D getLinearVelocity(String name) {
return toVector2D(m_bodies.get(name).getLinearVelocity()).scale(PIXELS_PER_METERS);
}
@Override
public void setLinearVelocity(String name, Vector2D velocity) {
m_bodies.get(name).setLinearVelocity(toVector2(new Vector2D(velocity).scale(1.f / PIXELS_PER_METERS)));
}
@Override
public void setDampling(String name, float linearDamping, float angularDamping) {
m_bodies.get(name).setLinearDamping(linearDamping);
m_bodies.get(name).setAngularDamping(angularDamping);
}
@Override
public void update() {
if (m_active && !m_isPaused) {
updateBodyPosition();
m_world.step(1.f / WorldModel.UPDATE_RATE, 8, 8);
}
}
@Override
public void loadPhysicsTiles(String path) throws ParserConfigurationException, IOException, SAXException {
File file = new File(path);
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
Document doc = builder.parse(file);
doc.getDocumentElement().normalize();
Element root = doc.getDocumentElement();
NodeList children = root.getChildNodes();
for (int i = 0; i < children.getLength(); i++) {
Node n = children.item(i);
if (n.getNodeType() == Node.ELEMENT_NODE) {
Element e = (Element) n;
String id = e.getAttribute("id");
m_segments.put(id, new ArrayList<Segment2D>());
for (int j = 0; j < e.getChildNodes().getLength(); j++) {
if (e.getChildNodes().item(j).getNodeType() == Node.ELEMENT_NODE) {
Element seg = (Element) e.getChildNodes().item(j);
int x1 = Integer.parseInt(seg.getAttribute("x1"));
int y1 = 64 - Integer.parseInt(seg.getAttribute("y1"));
int x2 = Integer.parseInt(seg.getAttribute("x2"));
int y2 = 64 - Integer.parseInt(seg.getAttribute("y2"));
m_segments.get(id).add(new Segment2D(x1, y1, x2, y2));
}
}
}
}
}
@Override
public ArrayList<Segment2D> getDebugSegments() {
ArrayList<Segment2D> result = new ArrayList<>();
result.addAll(m_debugSegments);
if (m_bodies != null) {
for (String s : m_bodies.keySet()) {
ArrayList<Vector2> vertices = new ArrayList<>();
Body body = m_bodies.get(s);
for (Fixture fixture : body.getFixtureList()) {
if (fixture != null && fixture.getType() == Type.Polygon) {
PolygonShape shape = (PolygonShape) fixture.getShape();
for (int i = 0; i < shape.getVertexCount(); i++) {
Vector2 vec = new Vector2();
shape.getVertex(i, vec);
vertices.add(body.getTransform().mul(vec));
}
for (int i = 0; i < vertices.size(); i++) {
Vector2D a;
Vector2D b;
if (i == vertices.size() - 1) {
a = toVector2D(vertices.get(i)).scale(PIXELS_PER_METERS);
b = toVector2D(vertices.get(0)).scale(PIXELS_PER_METERS);;
} else {
a = toVector2D(vertices.get(i)).scale(PIXELS_PER_METERS);;
b = toVector2D(vertices.get(i + 1)).scale(PIXELS_PER_METERS);;
}
result.add(new Segment2D(a, b));
}
}
}
}
}
return result;
}
@Override
public void setActive(boolean value) {
m_active = value;
}
@Override
public boolean isWorldLocked() {
return m_world.isLocked();
}
@Override
public void setPause(boolean pause) {
m_isPaused = pause;
}
@Override
public boolean isPaused() {
return m_isPaused;
}
/////////////////////////////////////////
// Statics
/////////////////////////////////////////
private static Vector2D toVector2D(Vector2 v) {
return new Vector2D(v.x, v.y);
}
private static Vector2 toVector2(Vector2D v) {
return new Vector2(v.x, v.y);
}
public void setRotation(String s, float r) {
m_bodies.get(s).setTransform(m_bodies.get(s).getPosition().x, m_bodies.get(s).getPosition().y, (float) (r * Math.PI) / 180.0f);
}
public void setBodyActive(String s, boolean b) {
if (m_bodies.containsKey(s)) {
m_bodies.get(s).setActive(b);
}
}
/////////////////////////////////////////
// Attributes
/////////////////////////////////////////
private World m_world;
private HashMap<String, Body> m_bodies;
private HashMap<String, Vector2D> m_bodiesSizes;
private ArrayList<Body> m_mapBodies;
private HashMap<String, ArrayList<Segment2D>> m_segments;
private static int PIXELS_PER_METERS = 100;
private ArrayList<Segment2D> m_debugSegments;
private boolean m_active;
private HashMap<String, Vector2D> m_positionsToModify;
private HashMap<String, Vector2D> m_velocitiesToModify;
private HashMap<String, Float> m_rotationToModify;
private boolean m_isPaused;
}