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

LibGDX碰撞检测异常:仅部分可碰撞实体生效问题排查

问题描述

我通过父类创建图形实体,可设置为可碰撞/不可碰撞类型。当前项目里Circle和Rectangle是可碰撞实体,Ellipse不可碰撞。但创建多个可碰撞实体后,只有最新创建的一对能触发碰撞,其余都不行。我原本以为子类继承父类属性后,同父类实体行为应该一致,完全搞不懂哪里出问题了。

相关代码

daCircle实体类

public class daCircle extends Collidable{

    protected float circleRadius;
    protected int upKey;
    protected int downKey;
    protected int leftKey;
    protected int rightKey;

    public daCircle(int circleXPos, int circleYPos, float circleRadius, int circleSpeed, Color circleColor, 
    int upKey, int downKey, int leftKey, int rightKey) {
        super(circleXPos, circleYPos, circleColor, circleSpeed);
        this.circleRadius = circleRadius;
        super.keyMovementList.set(0, upKey);
        super.keyMovementList.set(1, downKey);
        super.keyMovementList.set(2, leftKey);
        super.keyMovementList.set(3, rightKey);
    }
}

Collidable类的checkForCollision方法

public void checkForCollision(ArrayList<GeometricObjects> listOfAllShapes, String direction) {      
        for (GeometricObjects daShape : listOfAllShapes) {
            if (daShape instanceof Collidable) {
                Iterator<GeometricObjects> iter = listOfAllShapes.iterator();
                while(iter.hasNext()) {
                    GeometricObjects nextShape = iter.next();
                    if (daShape != nextShape) {
                        if (daShape instanceof daCircle && nextShape instanceof daCircle) {
                            setCirclesCollisionFlag(isCirclesColliding((daCircle)daShape, (daCircle)nextShape, direction));
                        }
                        if (daShape instanceof daRect && nextShape instanceof daRect) {
                            setRectanglesCollisionFlag(isRectanglesColliding((daRect)daShape, (daRect)nextShape, direction));
                        }
                        if (daShape instanceof daCircle && nextShape instanceof daRect ) {
                            setCircleRectangleCollisionFlag(circIntersectRect((daCircle)daShape, (daRect)nextShape, direction));
                        } 
                    } 
                } 
            }
        }
    }

Controller类的movementController方法

public void movementController(ArrayList<GeometricObjects> allGeometricShapes) { 
        int temporaryObjSpeedHolder = 0;

        GeometricObjects daObject = (GeometricObjects) this;
        if (daObject instanceof Collidable) {
            collidableShape = (Collidable) daObject;
            daObject = collidableShape;
        }

        // if (Gdx.input.isTouched()) {
        //     daObject.setXPos(Gdx.input.getX());
        //     daObject.setYPos(Gdx.graphics.getHeight() - Gdx.input.getY());
        // }

        if(Gdx.input.isKeyPressed(keyMovementList.get(0))){
            if (daObject instanceof Collidable) {
                collidableShape.checkForCollision(allGeometricShapes, "UP");
            }
            
            if (circlesAreColliding || rectanglesAreColliding || circleRectangleAreColliding) {
                temporaryObjSpeedHolder = incomingCollisionSpeed;
            } else {
                temporaryObjSpeedHolder = objectSpeed;
            }

            daObject.yPos += temporaryObjSpeedHolder;
        
        } else if(Gdx.input.isKeyPressed(keyMovementList.get(1))){
            if (daObject instanceof Collidable) {
                collidableShape.checkForCollision(allGeometricShapes, "DOWN");
            }

            if (circlesAreColliding || rectanglesAreColliding || circleRectangleAreColliding) {
                temporaryObjSpeedHolder = incomingCollisionSpeed;
            } else {
                temporaryObjSpeedHolder = objectSpeed;
            }

            daObject.yPos -= temporaryObjSpeedHolder;

        }

        if(Gdx.input.isKeyPressed(keyMovementList.get(2))){
            if (daObject instanceof Collidable) {
                collidableShape.checkForCollision(allGeometricShapes, "LEFT");
            }

            if (circlesAreColliding || rectanglesAreColliding || circleRectangleAreColliding) {
                temporaryObjSpeedHolder = incomingCollisionSpeed;
            } else {
                temporaryObjSpeedHolder = objectSpeed;
            }

            daObject.xPos -= temporaryObjSpeedHolder;

        } else if(Gdx.input.isKeyPressed(keyMovementList.get(3))){
            if (daObject instanceof Collidable) {
                collidableShape.checkForCollision(allGeometricShapes, "RIGHT");
            }

            if (circlesAreColliding || rectanglesAreColliding || circleRectangleAreColliding) {
                temporaryObjSpeedHolder = incomingCollisionSpeed;
            } else {
                temporaryObjSpeedHolder = objectSpeed;
            }

            daObject.xPos += temporaryObjSpeedHolder;
        }
}

排查方向与解决方案

  • 检查碰撞标志的作用域:如果circlesAreColliding、rectanglesAreColliding这类变量是静态的,所有实体共享同一个状态,最新的碰撞会覆盖之前的结果。把它们改成Collidable类的实例成员变量,让每个实体自己维护碰撞状态。
  • 重构checkForCollision逻辑:当前方法遍历所有实体再互相检查,会导致重复检测和状态覆盖。应该只检查**当前实体(this)**与列表中其他实体的碰撞,而不是遍历整个列表。比如去掉外层循环,直接用this作为daShape去和列表里的其他实体对比。
  • 重置碰撞标志:每次调用checkForCollision前,先把所有碰撞标志设为false,避免上次的碰撞状态残留影响当前判断。
  • 确认keyMovementList的实例化方式:如果父类的keyMovementList是静态变量,所有daCircle实例会共享同一个列表,导致按键配置被覆盖。改成实例变量,让每个实体拥有独立的按键设置。
  • 优化碰撞判断逻辑:当前的if判断会多次覆盖碰撞标志,比如先检测到A和B碰撞设为true,再检测A和C不碰撞又设为false,最终结果错误。应该用逻辑或(||)来更新标志,只要有一次碰撞就保持true,而不是直接赋值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 10:51:11