[LibGDX] Softbody or Jelly effect?

I just to manage to make the softbody or jelly effect on box2d but the problem is how can I map into texture. Can anyone point me into right direction or tutorial if how can I map the bodies/joints into texture?

Something like similar to this game

M4eA2YPXODs

thanks

Maybe someone can answer the question without this information, but could you describe what data you have available from Box2D? Is it something like points roughly in a circle with springs between them? (You mentioned bodies and joints, so I’m assuming that’s the case, but some information about how many bodies and how they’re joined together might be useful.)

Basically, this is my box2d code. Everything is working fine. My problem is I don’t know if how can I map this to texture.


import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.physics.box2d.joints.DistanceJointDef;
import com.badlogic.gdx.utils.Array;

public class Box2d extends ApplicationAdapter {

    public static final float PTM_RATIO = 32;
    public static final int NUM_SEGMENTS = 12;
    public static final float TIME_STEP = 1 / 300f;

    private float accumulator = 0;

    private Box2DDebugRenderer debugRenderer;
    private World world;
    private Array<Body> bodies = new Array<Body>();


    private static final int VIEWPORT_WIDTH = 20;
    private static final int VIEWPORT_HEIGHT = 13;
    private OrthographicCamera camera;


    @Override
    public void create() {

        debugRenderer = new Box2DDebugRenderer();

        camera = new OrthographicCamera(VIEWPORT_WIDTH, VIEWPORT_HEIGHT);
        camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0f);
        camera.update();


        world = new World(new Vector2(0, -10), false);

        createGround(world);

        Vector2 center = new Vector2(640 / 2 / PTM_RATIO, 480 / 2 / PTM_RATIO);

        CircleShape circleShape = new CircleShape();
        circleShape.setRadius(0.25f);

        FixtureDef fixtureDef = new FixtureDef();
        fixtureDef.shape = circleShape;
        fixtureDef.density = 0.1f;
        fixtureDef.restitution = 0.05f;
        fixtureDef.friction = 1.0f;

        float springiness = 4.0f;
        float deltaAngle = (2.f * MathUtils.PI) / NUM_SEGMENTS;
        float radius = 50;


        // For each segment...
        for (int i = 0; i < NUM_SEGMENTS; i++) {
            // Current angle
            float theta = deltaAngle * i;

            // Calcualte the x and y based on theta
            float x = radius * MathUtils.cos(theta);
            float y = radius * MathUtils.sin(theta);

            // Remember to divide by PTM_RATIO to convert to Box2d coordinates
            Vector2 circlePosition = new Vector2(x / PTM_RATIO, y / PTM_RATIO);

            BodyDef bodyDef = new BodyDef();
            bodyDef.type = BodyDef.BodyType.DynamicBody;
            // Position should be relative to the center
            Vector2 v2 = center.cpy().add(circlePosition);
            bodyDef.position.set(v2);

            // Create the body and fixture
            Body body = world.createBody(bodyDef);
            body.createFixture(fixtureDef);

            // Add the body to the array to connect joints to it
            // later. b2Body is a C++ object, so must wrap it
            // in NSValue when inserting into it NSMutableArray
            bodies.add(body);
        }

        // Circle at the center (inner circle)
        BodyDef innerCircleBodyDef = new BodyDef();
        innerCircleBodyDef.type = BodyDef.BodyType.DynamicBody;
        // Position is at the center
        innerCircleBodyDef.position.set(center);
        Body innerCircleBody = world.createBody(innerCircleBodyDef);
        innerCircleBody.createFixture(fixtureDef);

        // Connect the joints
        DistanceJointDef jointDef = new DistanceJointDef();
        for (int i = 0; i < NUM_SEGMENTS; i++) {
            // The neighbor.
            int neighborIndex = (i + 1) % NUM_SEGMENTS;

            // Get the current body and the neighbor
            Body currentBody = bodies.get(i);
            Body neighborBody = bodies.get(neighborIndex);


            // Connect the outer circles to each other
            jointDef.initialize(currentBody, neighborBody,
                    currentBody.getWorldCenter(),
                    neighborBody.getWorldCenter());
            jointDef.collideConnected = true;
            jointDef.frequencyHz = springiness;
            jointDef.dampingRatio = 0.5f;

            world.createJoint(jointDef);

            // Connect the center circle with other circles
            jointDef.initialize(currentBody, innerCircleBody, currentBody.getWorldCenter(), center);
            jointDef.collideConnected = true;
            jointDef.frequencyHz = springiness;
            jointDef.dampingRatio = 0.5f;

            world.createJoint(jointDef);
        }


    }

    @Override
    public void render() {

        camera.update();

        float delta = Gdx.graphics.getDeltaTime();

        accumulator += delta;

        while (accumulator >= delta) {
            world.step(TIME_STEP, 6, 2);
            accumulator -= TIME_STEP;
        }

        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        debugRenderer.render(world, camera.combined);


    }


    public static Body createGround(World world) {
        BodyDef bodyDef = new BodyDef();
        bodyDef.position.set(new Vector2(0, 0));
        Body body = world.createBody(bodyDef);
        PolygonShape shape = new PolygonShape();
        shape.setAsBox(50, 2);
        body.createFixture(shape, 0);
        shape.dispose();
        return body;
    }
}

Are the bodies arranged as one body in the center with a ring of NUM_SEGMENTS bodies around it? Something like this?

  O---O
 / \ / \
O---O---O
 \ / \ /
  O---O

Yes! something like that. Here’s the screenies

Ok, I see. It seems like that should be pretty straightforward; if there’s anything difficult about it, it’ll probably just be figuring out the appropriate LibGDX features or implementing some low-level OpenGL stuff.

First, I should say that I don’t know how other similar games have done it, although I’m guessing it’s similar to what I’m describing here.

What you posted actually has the form of a triangle mesh already, so it seems all that’s needed is to figure out how to implement dynamic meshes in LibGDX and translate what you have there to mesh form. The texture coordinates would be static, so all you’d have to change per-update would be the mesh vertex positions (which would simply be the positions of the corresponding bodies). The only pitfall I can think of is the shape getting deformed enough that triangle windings are reversed, but if your springs are stiff enough I doubt that’ll happen.

Is that enough info to go on?