Advertisement
dermetfan

BodyEditorLoader

Feb 28th, 2014
133
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Java 8.21 KB | None | 0 0
  1. package aurelienribon.bodyeditor;
  2.  
  3. import java.util.ArrayList;
  4. import java.util.HashMap;
  5. import java.util.List;
  6. import java.util.Map;
  7.  
  8. import com.badlogic.gdx.files.FileHandle;
  9. import com.badlogic.gdx.math.Vector2;
  10. import com.badlogic.gdx.physics.box2d.Body;
  11. import com.badlogic.gdx.physics.box2d.CircleShape;
  12. import com.badlogic.gdx.physics.box2d.FixtureDef;
  13. import com.badlogic.gdx.physics.box2d.PolygonShape;
  14. import com.badlogic.gdx.utils.JsonReader;
  15. import com.badlogic.gdx.utils.JsonValue;
  16.  
  17. /** Loads the collision fixtures defined with the Physics Body Editor application. You only need to give it a body and the
  18.  * corresponding fixture name, and it will attach these fixtures to your body.
  19.  *
  20.  * @author Aurelien Ribon | http://www.aurelienribon.com */
  21. public class BodyEditorLoader {
  22.  
  23.     // Model
  24.     private final Model model;
  25.  
  26.     // Reusable stuff
  27.     private final List<Vector2> vectorPool = new ArrayList<Vector2>();
  28.     private final PolygonShape polygonShape = new PolygonShape();
  29.     private final CircleShape circleShape = new CircleShape();
  30.     private final Vector2 vec = new Vector2();
  31.  
  32.     // -------------------------------------------------------------------------
  33.     // Ctors
  34.     // -------------------------------------------------------------------------
  35.  
  36.     public BodyEditorLoader(FileHandle file) {
  37.         if(file == null) {
  38.             throw new NullPointerException("file is null");
  39.         }
  40.         model = readJson(file.readString());
  41.     }
  42.  
  43.     public BodyEditorLoader(String str) {
  44.         if(str == null) {
  45.             throw new NullPointerException("str is null");
  46.         }
  47.         model = readJson(str);
  48.     }
  49.  
  50.     // -------------------------------------------------------------------------
  51.     // Public API
  52.     // -------------------------------------------------------------------------
  53.  
  54.     /** Creates and applies the fixtures defined in the editor. The name parameter is used to retrieve the right fixture from the
  55.      * loaded file. <br/>
  56.      * <br/>
  57.      *
  58.      * The body reference point (the red cross in the tool) is by default located at the bottom left corner of the image. This
  59.      * reference point will be put right over the BodyDef position point. Therefore, you should place this reference point
  60.      * carefully to let you place your body in your world easily with its BodyDef.position point. Note that to draw an image at the
  61.      * position of your body, you will need to know this reference point (see {@link #getOrigin(java.lang.String, float)}. <br/>
  62.      * <br/>
  63.      *
  64.      * Also, saved shapes are normalized. As shown in the tool, the width of the image is considered to be always 1 meter. Thus,
  65.      * you need to provide a scale factor so the polygons get resized according to your needs (not every body is 1 meter large in
  66.      * your game, I guess).
  67.      *
  68.      * @param body The Box2d body you want to attach the fixture to.
  69.      * @param name The name of the fixture you want to load.
  70.      * @param fd The fixture parameters to apply to the created body fixture.
  71.      * @param scale The desired scale of the body. The default width is 1. */
  72.     public void attachFixture(Body body, String name, FixtureDef fd, float scale, float scaleX, float scaleY) {
  73.         RigidBodyModel rbModel = model.rigidBodies.get(name);
  74.         if(rbModel == null) {
  75.             throw new RuntimeException("Name '" + name + "' was not found.");
  76.         }
  77.  
  78.         Vector2 origin = vec.set(rbModel.origin).scl(scale);
  79.  
  80.         for(int i = 0, n = rbModel.polygons.size(); i < n; i++) {
  81.             PolygonModel polygon = rbModel.polygons.get(i);
  82.             Vector2[] vertices = polygon.buffer;
  83.  
  84.             for(int ii = 0, nn = vertices.length; ii < nn; ii++) {
  85.                 vertices[ii] = newVec().set(polygon.vertices.get(ii)).scl(scale);
  86.                 vertices[ii].sub(origin);
  87.                 vertices[ii].x *= scaleX;
  88.                 vertices[ii].y *= scaleY;
  89.             }
  90.  
  91.             polygonShape.set(vertices);
  92.             fd.shape = polygonShape;
  93.             body.createFixture(fd);
  94.  
  95.             for(int ii = 0, nn = vertices.length; ii < nn; ii++) {
  96.                 free(vertices[ii]);
  97.             }
  98.         }
  99.  
  100.         for(int i = 0, n = rbModel.circles.size(); i < n; i++) {
  101.             CircleModel circle = rbModel.circles.get(i);
  102.             Vector2 center = newVec().set(circle.center).scl(scale);
  103.             float radius = circle.radius * scale;
  104.  
  105.             circleShape.setPosition(center);
  106.             circleShape.setRadius(radius);
  107.             fd.shape = circleShape;
  108.             body.createFixture(fd);
  109.  
  110.             free(center);
  111.         }
  112.     }
  113.  
  114.     /** Gets the image path attached to the given name. */
  115.     public String getImagePath(String name) {
  116.         RigidBodyModel rbModel = model.rigidBodies.get(name);
  117.         if(rbModel == null) {
  118.             throw new RuntimeException("Name '" + name + "' was not found.");
  119.         }
  120.  
  121.         return rbModel.imagePath;
  122.     }
  123.  
  124.     /** Gets the origin point attached to the given name. Since the point is normalized in [0,1] coordinates, it needs to be scaled
  125.      * to your body size. Warning: this method returns the same Vector2 object each time, so copy it if you need it for later use. */
  126.     public Vector2 getOrigin(String name, float scale) {
  127.         RigidBodyModel rbModel = model.rigidBodies.get(name);
  128.         if(rbModel == null)
  129.             throw new RuntimeException("Name '" + name + "' was not found.");
  130.  
  131.         return vec.set(rbModel.origin).scl(scale);
  132.     }
  133.  
  134.     /** <b>For advanced users only.</b> Lets you access the internal model of this loader and modify it. Be aware that any
  135.      * modification is permanent and that you should really know what you are doing. */
  136.     public Model getInternalModel() {
  137.         return model;
  138.     }
  139.  
  140.     // -------------------------------------------------------------------------
  141.     // Json Models
  142.     // -------------------------------------------------------------------------
  143.  
  144.     public static class Model {
  145.  
  146.         public final Map<String, RigidBodyModel> rigidBodies = new HashMap<String, RigidBodyModel>();
  147.     }
  148.  
  149.     public static class RigidBodyModel {
  150.  
  151.         public String name;
  152.         public String imagePath;
  153.         public final Vector2 origin = new Vector2();
  154.         public final List<PolygonModel> polygons = new ArrayList<PolygonModel>();
  155.         public final List<CircleModel> circles = new ArrayList<CircleModel>();
  156.     }
  157.  
  158.     public static class PolygonModel {
  159.  
  160.         public final List<Vector2> vertices = new ArrayList<Vector2>();
  161.         private Vector2[] buffer; // used to avoid allocation in attachFixture()
  162.     }
  163.  
  164.     public static class CircleModel {
  165.  
  166.         public final Vector2 center = new Vector2();
  167.         public float radius;
  168.     }
  169.  
  170.     // -------------------------------------------------------------------------
  171.     // Json reading process
  172.     // -------------------------------------------------------------------------
  173.  
  174.     private Model readJson(String str) {
  175.         Model m = new Model();
  176.         JsonValue root = new JsonReader().parse(str);
  177.         JsonValue bodies = root.get("rigidBodies");
  178.  
  179.         for(JsonValue body = bodies.child(); body != null; body = body.next()) {
  180.             RigidBodyModel rbModel = readRigidBody(body);
  181.             m.rigidBodies.put(rbModel.name, rbModel);
  182.         }
  183.  
  184.         return m;
  185.     }
  186.  
  187.     private RigidBodyModel readRigidBody(JsonValue bodyElem) {
  188.         RigidBodyModel rbModel = new RigidBodyModel();
  189.         rbModel.name = bodyElem.getString("name");
  190.         rbModel.imagePath = bodyElem.getString("imagePath");
  191.  
  192.         JsonValue origin = bodyElem.get("origin");
  193.  
  194.         rbModel.origin.x = origin.getFloat("x");
  195.         rbModel.origin.y = origin.getFloat("y");
  196.  
  197.         // polygons
  198.         JsonValue polygons = bodyElem.get("polygons");
  199.  
  200.         for(JsonValue vertices = polygons.child(); vertices != null; vertices = vertices.next()) {
  201.             PolygonModel polygon = new PolygonModel();
  202.             rbModel.polygons.add(polygon);
  203.  
  204.             for(JsonValue vertex = vertices.child(); vertex != null; vertex = vertex.next()) {
  205.                 polygon.vertices.add(new Vector2(vertex.getFloat("x"), vertex.getFloat("y")));
  206.             }
  207.  
  208.             polygon.buffer = new Vector2[polygon.vertices.size()];
  209.         }
  210.  
  211.         // circles
  212.         JsonValue circles = bodyElem.get("circles");
  213.  
  214.         for(JsonValue circle = circles.child(); circle != null; circle = circle.next()) {
  215.             CircleModel c = new CircleModel();
  216.             rbModel.circles.add(c);
  217.  
  218.             c.center.x = circle.getFloat("cx");
  219.             c.center.y = circle.getFloat("cy");
  220.             c.radius = circle.getFloat("r");
  221.         }
  222.  
  223.         return rbModel;
  224.     }
  225.  
  226.     // -------------------------------------------------------------------------
  227.     // Helpers
  228.     // -------------------------------------------------------------------------
  229.  
  230.     private Vector2 newVec() {
  231.         return vectorPool.isEmpty() ? new Vector2() : vectorPool.remove(0);
  232.     }
  233.  
  234.     private void free(Vector2 v) {
  235.         vectorPool.add(v);
  236.     }
  237. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement