LibGDX精灵点击输入方法中timesClicked变量修改问题
解决LibGDX精灵点击计数与计时器的变量访问问题
问题根源
Java中内部类(比如你用到的TimerTask)访问方法内的局部变量时,要求变量必须是final或等效final,但基本类型的局部变量一旦声明为final就无法修改,这就是核心矛盾。而直接用静态变量会导致多个精灵共享同一计数,出现点击不同精灵时计数混乱的问题,并非合理方案。
可行解决方案
方案1:使用可变包装类
用可修改内部值的对象包装计数,比如AtomicInteger(线程安全)或自定义简单Holder类,内部类可通过final的对象引用修改内部值。
示例代码(用AtomicInteger):
import java.util.concurrent.atomic.AtomicInteger; public static void displayItem(Player Dawid, Item item, Sprite itemSprite){ // 用AtomicInteger包装点击计数 AtomicInteger timesClicked = new AtomicInteger(0); if (Gdx.input.justTouched()) { camera.unproject(touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0)); if (itemSprite.getBoundingRectangle().contains(touchPoint.x, touchPoint.y)) { if (timesClicked.get() == 1){ Shop.checkRequirement(item.getBuyPrice(), Dawid, item); Dawid.setGold(Dawid.getGold() - item.getBuyPrice()); item.setStock(item.getStock()+1); topText = "Kupiłeś eliksir zdrowia!"; } Assets.sellText = item.getSellPrice() + "g"; Assets.buyText = item.getBuyPrice() + "g"; timesClicked.incrementAndGet(); timer.schedule(new TimerTask() { @Override public void run() { timesClicked.set(0); } }, 500); } } }
自定义Holder类替代方案:
// 在当前类内部定义静态Holder类 static class IntHolder { int value; } // 方法内使用 public static void displayItem(Player Dawid, Item item, Sprite itemSprite){ IntHolder timesClicked = new IntHolder(); if (Gdx.input.justTouched()) { camera.unproject(touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0)); if (itemSprite.getBoundingRectangle().contains(touchPoint.x, touchPoint.y)) { if (timesClicked.value == 1){ Shop.checkRequirement(item.getBuyPrice(), Dawid, item); Dawid.setGold(Dawid.getGold() - item.getBuyPrice()); item.setStock(item.getStock()+1); topText = "Kupiłeś eliksir zdrowia!"; } Assets.sellText = item.getSellPrice() + "g"; Assets.buyText = item.getBuyPrice() + "g"; timesClicked.value++; timer.schedule(new TimerTask() { @Override public void run() { timesClicked.value = 0; } }, 500); } } }
方案2:将计数设为类成员变量(非静态)
如果点击计数属于当前类实例而非全局共享,把timesClicked定义为类的非静态成员变量,内部类可直接访问,无需final修饰。
示例代码:
// 在类内部声明成员变量 private int timesClicked = 0; public void displayItem(Player Dawid, Item item, Sprite itemSprite){ if (Gdx.input.justTouched()) { camera.unproject(touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0)); if (itemSprite.getBoundingRectangle().contains(touchPoint.x, touchPoint.y)) { if (timesClicked == 1){ Shop.checkRequirement(item.getBuyPrice(), Dawid, item); Dawid.setGold(Dawid.getGold() - item.getBuyPrice()); item.setStock(item.getStock()+1); topText = "Kupiłeś eliksir zdrowia!"; } Assets.sellText = item.getSellPrice() + "g"; Assets.buyText = item.getBuyPrice() + "g"; timesClicked++; timer.schedule(new TimerTask() { @Override public void run() { timesClicked = 0; } }, 500); } } }
注意:若方法处理多个精灵点击,需给每个精灵绑定独立计数(比如在Item类中添加点击计数属性),避免不同精灵共用同一计数。
方案3:使用LibGDX自带的Timer
LibGDX的com.badlogic.gdx.utils.Timer在主线程执行任务,避免Java Timer的线程问题,写法更简洁:
import com.badlogic.gdx.utils.Timer; public static void displayItem(Player Dawid, Item item, Sprite itemSprite){ AtomicInteger timesClicked = new AtomicInteger(0); if (Gdx.input.justTouched()) { camera.unproject(touchPoint.set(Gdx.input.getX(), Gdx.input.getY(), 0)); if (itemSprite.getBoundingRectangle().contains(touchPoint.x, touchPoint.y)) { if (timesClicked.get() == 1){ Shop.checkRequirement(item.getBuyPrice(), Dawid, item); Dawid.setGold(Dawid.getGold() - item.getBuyPrice()); item.setStock(item.getStock()+1); topText = "Kupiłeś eliksir zdrowia!"; } Assets.sellText = item.getSellPrice() + "g"; Assets.buyText = item.getBuyPrice() + "g"; timesClicked.incrementAndGet(); // LibGDX Timer参数为秒,0.5秒即500毫秒 Timer.schedule(new Timer.Task() { @Override public void run() { timesClicked.set(0); } }, 0.5f); } } }
注意事项
- 禁止用静态变量存点击计数:静态变量全局共享,多精灵点击时会互相干扰,导致计数逻辑混乱。
- 线程安全:Java的
TimerTask在后台线程执行,修改UI相关变量需注意线程安全;LibGDX的Timer任务在主线程执行,更适配UI操作。
内容的提问来源于stack exchange,提问作者Dawid Kaim
相关产品推荐
相关产品推荐

