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
相关产品推荐
相关产品推荐

