You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用LibGDX+LiquidFun时物体与粒子交互异常问题求助

LibGDX + LiquidFun 粒子异常问题

使用LibGDX结合LiquidFun开发游戏时遇到以下异常行为:

  • 当动态物体沉入粒子群时,粒子会被吸入物体当前朝向的顶部一侧,并从底部对侧喷出,呈现类似涡轮机的流动效果,同时推动物体向顶部朝向的方向偏移
  • 若物体顶部贴靠墙壁或地面,粒子会从与顶部相连的角落被吸入

演示效果:
粒子涡轮机式异常流动

以下是简化的Demo代码:

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;}

}

内容的提问来源于stack exchange,提问作者Michael

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.15 22:50:40