Java类布尔值调用set修改后update方法读取仍为旧值问题求助
问题原因分析
1. update方法无法识别removeSnake布尔值变更的原因
- 实例不匹配:你调用
setRemoveSnake(true)的Snake实例,和主update中遍历执行enemy.update(dt)的Snake实例不是同一个对象。比如你在碰撞检测时拿到的是临时创建的对象副本、或者取错了列表里的实例,修改的是副本的属性,原实例的removeSnake自然还是false。可以在setRemoveSnake和update方法中分别打印System.identityHashCode(this),如果两个日志输出的哈希值不一致,就可以确认是该问题。 - 多线程可见性问题:libGDX中Box2D的碰撞回调是在物理计算线程执行,而游戏主update/render是在UI渲染线程执行,如果你是在碰撞回调里调用的
setRemoveSnake,两个线程没有同步的话,布尔值的修改不会被渲染线程感知到。这种情况只要给removeSnake变量加volatile关键字即可:protected volatile boolean removeSnake;
2. 无法进入遍历enemies的for循环的原因
看日志可以发现,击杀Snake后,只有遍历死亡列表的work outside for loops日志输出,没有遍历敌人列表的work insade enemy for loop日志,说明creator.getEnemies()返回的列表在击杀后为空/遍历提前终止,常见原因如下:
- 你在碰撞回调中直接把击杀的Snake从
enemies列表中移除了:Box2D物理步执行过程中修改游戏对象集合,会触发ConcurrentModificationException,即使没有抛出异常,也会导致遍历集合的逻辑提前中断,没有输出后续日志。 - 你修改
deadEnemiesList和遍历deadEnemiesList的时机冲突:比如在遍历enemies的过程中同时修改deadEnemiesList的长度,导致内层循环判断i < creator.getDeadEnemiesList().size()直接不满足,跳过内层逻辑。
修复建议
- 所有和Box2D相关的对象修改、列表修改操作,都不要直接在碰撞回调中执行,先把要删除的对象引用存入临时的死亡列表,等
world.step()执行完毕后,再在主update的安全位置统一处理删除逻辑。 - 不要用
System.identityHashCode作为对象匹配的标识,直接存Snake对象的引用到死亡列表,避免哈希冲突、对象被回收后哈希复用的问题。 - 删除对象时不要直接在增强for循环遍历的原集合上执行删除操作,可以先遍历把要保留的对象存入新列表,再替换原列表,或者用迭代器的
remove()方法执行删除。
内容的提问来源于stack exchange,提问作者pga2
相关产品推荐
相关产品推荐

