I'm working on a game using LiquidFun with libgdx. The problem is when I try to have an object sink into the particles the particles get sucked into the top side of the object, whichever direction its facing, and shot out the bottom side of the object, whichever direction its facing. So it's acting very much like a turbine, sucking them in one side and shooting them out of the other, and propeling the object in the direction the top is facing. If the top side is against a wall or the ground it will suck particles in from one of the corners connected to the top side. Here's a gif demonstrating
Here's the code to demonstrate, it's pretty much just a stripped down version of the LiquidFun demo file:
import com.badlogic.gdx.*;
import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Matrix4;
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.BodyDef.BodyType;
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 finnstr.libgdx.liquidfun.ParticleDebugRenderer;
import finnstr.libgdx.liquidfun.ParticleDef.ParticleType;
import finnstr.libgdx.liquidfun.ParticleGroupDef;
import finnstr.libgdx.liquidfun.ParticleSystem;
import finnstr.libgdx.liquidfun.ParticleSystemDef;
import com.badlogic.gdx.physics.box2d.*;
public class Demo extends ApplicationAdapter implements InputProcessor {
private final static float BOX_TO_WORLD = 120.0f;
private final static float WORLD_TO_BOX = 1f / BOX_TO_WORLD;
private OrthographicCamera camera;
private World mWorld;
private ParticleSystem mParticleSystem;
private ParticleDebugRenderer mParticleDebugRenderer;
private Box2DDebugRenderer mDebugRenderer;
private ParticleGroupDef mParticleGroupDef1;
Body boxBody;
@Override
public void create() {
float width = Gdx.graphics.getWidth();
float height = Gdx.graphics.getHeight();
camera = new OrthographicCamera(width, height);
camera.position.set(width / 2, height / 2, 0);
camera.update();
Gdx.input.setInputProcessor(this);
createBox2DWorld(width, height);
createParticleStuff(width, height);
mDebugRenderer = new Box2DDebugRenderer();
mParticleDebugRenderer = new ParticleDebugRenderer(new Color(0, 1, 0, 1), mParticleSystem.getParticleCount());
}
private void createBox2DWorld(float width, float height) {
mWorld = new World(new Vector2(0, -9.8f), false);
/* Bottom */
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyType.StaticBody;
bodyDef.position.set(width * WORLD_TO_BOX / 2f, height * (2f / 100f) * WORLD_TO_BOX / 2f);
Body ground = mWorld.createBody(bodyDef);
PolygonShape shape = new PolygonShape();
shape.setAsBox(width * WORLD_TO_BOX / 2, height * (2f / 100f) * WORLD_TO_BOX / 2f);
FixtureDef fixDef = new FixtureDef();
fixDef.friction = 0.2f;
fixDef.shape = shape;
ground.createFixture(fixDef);
shape.dispose();
/* Walls */
BodyDef bodyDef1 = new BodyDef();
bodyDef1.type = BodyType.StaticBody;
bodyDef1.position.set(width * (2f / 100f) * WORLD_TO_BOX / 2f, height * WORLD_TO_BOX / 2);
Body left = mWorld.createBody(bodyDef1);
bodyDef1.position.set(width * WORLD_TO_BOX - width * (2f / 100f) * WORLD_TO_BOX / 2f, height * WORLD_TO_BOX / 2);
Body right = mWorld.createBody(bodyDef1);
shape = new PolygonShape();
shape.setAsBox(width * (2f / 100f) * WORLD_TO_BOX / 2f, height * WORLD_TO_BOX / 2);
fixDef.shape = shape;
left.createFixture(fixDef);
right.createFixture(fixDef);
shape.dispose();
}
private void createParticleStuff(float width, float height) {
ParticleSystemDef systemDef = new ParticleSystemDef();
systemDef.radius = 10f * WORLD_TO_BOX;
systemDef.dampingStrength = 0.2f;
systemDef.density = 1.3f;
mParticleSystem = new ParticleSystem(mWorld, systemDef);
mParticleGroupDef1 = new ParticleGroupDef();
mParticleGroupDef1.color.set(1f, 0, 0, 1);
mParticleGroupDef1.flags.add(ParticleType.b2_waterParticle);
mParticleGroupDef1.position.set(width * (30f / 100f) * WORLD_TO_BOX, height * (80f / 100f) * WORLD_TO_BOX);
PolygonShape particleGroupShape = new PolygonShape();
particleGroupShape.setAsBox(width * (70f / 100f) * WORLD_TO_BOX / 2f, width * (70f / 100f) * WORLD_TO_BOX / 2f);
mParticleGroupDef1.shape = particleGroupShape;
mParticleSystem.createParticleGroup(mParticleGroupDef1);
}
@Override
public void render() {
Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
mWorld.step(Gdx.graphics.getDeltaTime(), 10, 6, mParticleSystem.calculateReasonableParticleIterations(Gdx.graphics.getDeltaTime()));
Matrix4 cameraCombined = camera.combined.cpy();
cameraCombined.scale(BOX_TO_WORLD, BOX_TO_WORLD, 1);
mParticleDebugRenderer.render(mParticleSystem, BOX_TO_WORLD, cameraCombined);
mDebugRenderer.render(mWorld, cameraCombined);
}
public void createBoxBody(float x, float y){
BodyDef bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(x * WORLD_TO_BOX, y * WORLD_TO_BOX);
boxBody = mWorld.createBody(bodyDef);
PolygonShape shape;
shape = new PolygonShape();
shape.setAsBox(50 * MyGdxGame.WORLD_TO_BOX, 50 * MyGdxGame.WORLD_TO_BOX);
FixtureDef fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 3;
boxBody.createFixture(fixtureDef);
shape.dispose();
}
@Override
public void dispose() {
mParticleGroupDef1.shape.dispose();
mWorld.dispose();
mDebugRenderer.dispose();
}
@Override
public boolean touchDown(int p1, int p2, int pointer, int button) {
float screenY = Gdx.graphics.getHeight() - p2;
if(boxBody != null){
mWorld.destroyBody(boxBody);
}
createBoxBody(p1, screenY);
return true;
}
@Override
public boolean touchUp(int screenX, int screenY, int pointer, int button) {
if(button != Input.Buttons.LEFT && button != Input.Buttons.RIGHT && button != Input.Buttons.MIDDLE) return false;
return true;
}
@Override
public boolean touchDragged(int screenX, int screenY, int pointer) {
return false;
}
@Override
public boolean mouseMoved(int screenX, int screenY) {
return false;
}
@Override
public boolean scrolled(float p1, float p2)
{
// TODO: Implement this method
return false;
}
@Override
public boolean keyDown(int keycode) {return false;}
@Override
public boolean keyUp(int keycode) {return false;}
@Override
public boolean keyTyped(char character) {return false;}
}