javaandroidlibgdxbox2djbox2d

Adding a dynamic physic body to a drawn line


I'm developing a game with a similar mechanical to "Crayon Physics Deluxe" on libGDX (https://www.youtube.com/watch?v=avkacGQKWec). I'm stuck on the algorithm implementation of the drawn. The problem is that dynamics bodies doesn't work with EdgeShapes and ChainShapes. I've attempted using a polygonization algorithm, but it doesn't work exactly like "Crayon Physics" and creates a lot of bugs.

Is there any way to adding a dynamic body to the drawn?


Solution

  • Finally, I've solved the problem concatenating rectangles. The method is detailed below. The process has 3 parts:

    1.- Reduction of user input

    For improve the performance, I've defined a tolerance distance: Every point has to be separated from previous by the tolerance distance defined.

    2.- Smoothing input

    For avoiding peaks and jagged corners I've used one iteration of Chaikin's smoothing algorithm.(http://www.idav.ucdavis.edu/education/CAGDNotes/Chaikins-Algorithm/Chaikins-Algorithm.html)

    3.- Build a line of rectangles

    Once we have the input processed and smoothed, the last step is build de physic body. That body will have a multiple rectangle fixtures. Concretly, NUMBER_OF_POINTS/2 fixtures, since we'll construct a rectangle every two points. The next draw illustrate the process:

    Drawing of the process

    And that's the code to achive it:

    private static Body createPhysicBodies(Array<Vector2> input, World world) {
        BodyDef bodyDef = new BodyDef();
        bodyDef.type = BodyType.DynamicBody;
        Body body = world.createBody(bodyDef);
        for (int i = 0; i < input.size - 1; i++) {
            Vector2 point = input.get(i);
            Vector2 dir = input.get(i + 1).cpy().sub(point);
            float distance = dir.len();
            float angle = dir.angle() * MathUtils.degreesToRadians;
            PolygonShape shape = new PolygonShape();    
            shape.setAsBox(distance / 2, Constants.THICKNESS / 2, dir.cpy()
                    .scl(0.5f).add(point), angle);
            body.createFixture(shape, 1.0f);
        }
        return body;
    }