我正在开发一款涉及ff的简单AndEngine游戏。精灵
a。)坦克 b。)士兵 c。)炸弹我在这里有一个类似的问题:Android AndEngine: Simple sprite collision
游戏的样子:
然而,在解决最初的问题时,又出现了另一个问题:
当炸弹(飞机当前所在的地方并垂直下降,直到它到达目标或地板,通过鼠标点击)击中目标,比如一名士兵,士兵精灵必须分离并留下它血液飞溅精灵1秒钟,以及炸弹爆炸精灵。但是,游戏力关闭会产生indexOutOfBoundError。据我所知,这可能是炸弹与其目标之间精灵数量的差异,导致出现数组错误,但logCat根本没有帮助。
09-22 11:13:37.585: E/AndroidRuntime(735): FATAL EXCEPTION: UpdateThread
09-22 11:13:37.585: E/AndroidRuntime(735): java.lang.IndexOutOfBoundsException: Invalid index 5, size is 5
09-22 11:13:37.585: E/AndroidRuntime(735): at java.util.ArrayList.throwIndexOutOfBoundsException(ArrayList.java:251)
09-22 11:13:37.585: E/AndroidRuntime(735): at java.util.ArrayList.get(ArrayList.java:304)
09-22 11:13:37.585: E/AndroidRuntime(735): at org.andengine.entity.Entity.onManagedUpdate(Entity.java:1402)
09-22 11:13:37.585: E/AndroidRuntime(735): at org.andengine.entity.Entity.onUpdate(Entity.java:1167)
09-22 11:13:37.585: E/AndroidRuntime(735): at org.andengine.entity.Entity.onManagedUpdate(Entity.java:1402)
09-22 11:13:37.585: E/AndroidRuntime(735): at org.andengine.entity.scene.Scene.onManagedUpdate(Scene.java:284)
09-22 11:13:37.585: E/AndroidRuntime(735): at org.andengine.entity.Entity.onUpdate(Entity.java:1167)
09-22 11:13:37.585: E/AndroidRuntime(735): at org.andengine.engine.Engine.onUpdateScene(Engine.java:591)
09-22 11:13:37.585: E/AndroidRuntime(735): at org.andengine.engine.Engine.onUpdate(Engine.java:586)
09-22 11:13:37.585: E/AndroidRuntime(735): at org.andengine.engine.Engine.onTickUpdate(Engine.java:548)
09-22 11:13:37.585: E/AndroidRuntime(735): at org.andengine.engine.Engine$UpdateThread.run(Engine.java:820)
如此处所示,logCat没有在我的代码上给出错误,但在AndEngine本身上,并且很可能不是这样。
我在onCreateScene Update Handler中运行的新代码(根据上面链接的上一个问题的帮助):
protected void checkSoldierCollision() {
// TODO Auto-generated method stub
int numBombs = bombGroup.getChildCount();
int numTroops = troopsGroup.getChildCount();
final ArrayList<Sprite> toBeDetached = new ArrayList<Sprite>();
for (int i = 0; i < numBombs; i++) {
Sprite s = (Sprite) bombGroup.getChildByIndex(i);
for (int j = 0; j < numTroops; j++) {
Sprite s2 = (Sprite) troopsGroup.getChildByIndex(j);
if (s.collidesWith(s2)) {
/*Sprite splat = createSplat();
splat.setPosition(s.getX(), s.getY());
getEngine().getScene().attachChild(splat);*/
Sprite splode = createExplosion();
splode.setPosition(s.getX(), s.getY());
getEngine().getScene().attachChild(splode);
// WARNING: cannot detach from the list
//while looping through the list
toBeDetached.add(s);
toBeDetached.add(s2);
}
}
}
runOnUpdateThread(new Runnable() {
@Override
public void run() {
for (Sprite s : toBeDetached) {
s.detachSelf();
Sprite splode = createExplosion();
splode.setPosition(s.getX(), s.getY());
getEngine().getScene().attachChild(splode);
}
toBeDetached.clear();
}
});
}
我注意到它只能是一个splat或爆炸,因为它没有错误。如果在碰撞时两个splat和爆炸都填充场景,则会发生错误。
此外,即使炸弹没有击中士兵(但是在击中地板时仍然分离并用爆炸云取代),它也会出现类似的错误:
我的createBomb功能:
public Sprite createBomb(float x, float y) {
Sprite bombSprite = new Sprite(x, y, this.mBombTextureRegion,
getVertexBufferObjectManager());
MoveYModifier downModBomb = new MoveYModifier(1, 60, FLOOR);
downModBomb.addModifierListener(new IModifierListener<IEntity>() {
@Override
public void onModifierStarted(IModifier<IEntity> pModifier,
IEntity pItem) {
}
@Override
public void onModifierFinished(IModifier<IEntity> pModifier,
final IEntity pItem) {
pItem.detachSelf();
AnimatedSprite explodeSprite = createExplosion();
explodeSprite.setPosition(pItem.getX(), FLOOR);
getEngine().getScene().attachChild(explodeSprite);
}
});
bombSprite.registerEntityModifier(downModBomb); // register action
return bombSprite;
}
我的onCreateScene炸弹功能和碰撞updateHandler:
scene.setOnSceneTouchListener(new IOnSceneTouchListener() {
@Override
public boolean onSceneTouchEvent(Scene pScene,
TouchEvent pSceneTouchEvent) {
if (pSceneTouchEvent.getAction() == TouchEvent.ACTION_UP) {
runOnUiThread(new Runnable() {
@Override
public void run() {
Sprite bomb = createBomb(f16Sprite.getX(),
f16Sprite.getY());
bombGroup.attachChild(bomb);
}
});
return true;
}
return false;
}
});
// periodic checks
scene.registerUpdateHandler(new IUpdateHandler() {
@Override
public void onUpdate(float pSecondsElapsed) {
// checkTankCollision();
// checkSoldierBackCollision();
checkSoldierCollision();
}
@Override
public void reset() {
}
});
我的createExplosion方法:
public AnimatedSprite createExplosion() {
AnimatedSprite boomSprite = new AnimatedSprite(0, 0,
this.mExplodeTextureRegion, getVertexBufferObjectManager());
DelayModifier delay = new DelayModifier(.3f); // delay in seconds, can
// take float numbers .5
// seconds
delay.addModifierListener(new IModifierListener<IEntity>() {
@Override
public void onModifierStarted(IModifier<IEntity> pModifier,
IEntity pItem) {
((AnimatedSprite) pItem).animate(new long[] { 100, 100, 100 }, // durations/frame
new int[] { 1, 2, 3 }, // which frames
true); // loop
}
@Override
public void onModifierFinished(IModifier<IEntity> pModifier,
final IEntity pItem) {
((AnimatedSprite) pItem).detachSelf();
}
});
boomSprite.registerEntityModifier(delay); // register action
return boomSprite;
}
我该如何解决这个问题?循环逻辑并不完全是我的强项。我也对如何实现这一点持开放态度。
更新:刚刚意识到即使碰撞的结果是啪啪声或爆炸声,也没关系,如果玩家持续发送垃圾邮件(比如说4-5次)整个游戏部队关闭。
- 无论何时创建焊料/罐的实例,似乎都存在允许的爆炸次数。每当炸弹袭击一名士兵时,我就会先关闭制造爆炸(所以血液板只会留在原位而不是两者)。它工作正常,但超过4-6枚炸弹,游戏结束。当一个新的士兵实例产生时(意味着旧的士兵离开屏幕并分离),然后在游戏部队关闭之前给予玩家4-6枚炸弹。
答案 0 :(得分:4)
问题可能是由于您通过调用runOnUiThread在UI线程上附加炸弹而检查更新线程上的冲突。尝试在runOnUpdateThread中添加炸弹。
通常,您希望保持一致的用于操作事物的线程,否则会出现奇怪的错误,这些错误很难调试。
旁注:UI线程非常适合显示Toasts,请参阅此示例:
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(GameActivity.this, "Hello!", Toast.LENGTH_SHORT).show();
}
});
答案 1 :(得分:1)
为了对此进行调试,您需要按输出进行监视(可能通过Log),有多少被实际添加到bombGroup
和troopsGroup
,这应该与已经有多少人一致添加。还要尝试输出getChildCount()
的值以及i和j参数。
如果想一想,请试试这个:
for (int i = 0; i < toBeDetached.size(); i++) {
toBeDetached.get(i).detachSelf();
}
答案 2 :(得分:1)
在JohnEye先生的帮助下,我已经能够解决我的代码中的问题了。请考虑以下代码段:
protected void checkSoldierCollision() {
// TODO Auto-generated method stub
int numBombs = bombGroup.getChildCount();
int numTroops = troopsGroup.getChildCount();
final ArrayList<Sprite> toBeDetached = new ArrayList<Sprite>();
for (int i = 0; i < numBombs; i++) {
Sprite s = (Sprite) bombGroup.getChildByIndex(i);
for (int j = 0; j < numTroops; j++) {
Sprite s2 = (Sprite) troopsGroup.getChildByIndex(j);
if (s.collidesWith(s2)) {
Sprite splat = createSplat();
splat.setPosition(s.getX(), s.getY());
getEngine().getScene().attachChild(splat);
Sprite splode = createExplosion();
splode.setPosition(s.getX(), s.getY());
explodeGroup.attachChild(splode);
// getEngine().getScene().attachChild(splode);
// WARNING: cannot detach from the list
// while looping through the list
toBeDetached.add(s);
toBeDetached.add(s2);
}
}
}
runOnUpdateThread(new Runnable() {
@Override
public void run() {
for (Sprite s : toBeDetached) {
s.detachSelf();
Sprite splat = createSplat();
splat.setPosition(s.getX(), s.getY());
getEngine().getScene().attachChild(splat);
Sprite splode = createExplosion();
splode.setPosition(s.getX(), s.getY());
explodeGroup.attachChild(splode);
// getEngine().getScene().attachChild(splode);
}
toBeDetached.clear();
}
});
}
正如我所提到的,由于两个碰撞对象之间的数量不一致,游戏崩溃了。正如JohnEye先生指出的那样,当一个精灵在UI线程中产生,但在更新线程中也没有产生这种情况。此外,请考虑我的createExplosion,createBomb和createSplat函数:
创建BOMB
public Sprite createBomb(float x, float y) {
Sprite bombSprite = new Sprite(x, y, this.mBombTextureRegion,
getVertexBufferObjectManager());
MoveYModifier downModBomb = new MoveYModifier(1, 60, FLOOR);
downModBomb.addModifierListener(new IModifierListener<IEntity>() {
@Override
public void onModifierStarted(IModifier<IEntity> pModifier,
IEntity pItem) {
}
@Override
public void onModifierFinished(IModifier<IEntity> pModifier,
final IEntity pItem) {
runOnUpdateThread(new Runnable() {
@Override
public void run() {
pItem.detachSelf();
}
});
AnimatedSprite explodeSprite = createExplosion();
explodeSprite.setPosition(pItem.getX(), FLOOR);
explodeGroup.attachChild(explodeSprite);
// getEngine().getScene().attachChild(explodeGroup);
}
});
bombSprite.registerEntityModifier(downModBomb);
return bombSprite;
}
创建爆炸
public AnimatedSprite createExplosion() {
AnimatedSprite boomSprite = new AnimatedSprite(0, 0,
this.mExplodeTextureRegion, getVertexBufferObjectManager());
DelayModifier delay = new DelayModifier(.3f); // delay in seconds, can
// take float numbers .5
// seconds
delay.addModifierListener(new IModifierListener<IEntity>() {
@Override
public void onModifierStarted(IModifier<IEntity> pModifier,
IEntity pItem) {
((AnimatedSprite) pItem).animate(new long[] { 100, 100, 100 }, // durations/frame
new int[] { 1, 2, 3 }, // which frames
true); // loop
}
@Override
public void onModifierFinished(IModifier<IEntity> pModifier,
final IEntity pItem) {
runOnUpdateThread(new Runnable() {
@Override
public void run() {
((AnimatedSprite) pItem).detachSelf();
}
});
}
});
boomSprite.registerEntityModifier(delay); // register action
return boomSprite;
}
创建SPLAT
public Sprite createSplat() {
Sprite splatSprite = new Sprite(0, 0, this.mSplatTextureRegion,
getVertexBufferObjectManager());
DelayModifier delay = new DelayModifier(.3f); // delay in seconds, can
// take float numbers .5
// seconds
delay.addModifierListener(new IModifierListener<IEntity>() {
@Override
public void onModifierStarted(IModifier<IEntity> pModifier,
IEntity pItem) {
}
@Override
public void onModifierFinished(IModifier<IEntity> pModifier,
final IEntity pItem) {
runOnUpdateThread(new Runnable() {
@Override
public void run() {
pItem.detachSelf();
}
});
}
});
splatSprite.registerEntityModifier(delay); // register action
return splatSprite;
}
请注意,所有这些都在runOnUpdate线程中分离/生成其他精灵。游戏在我早期的运行中崩溃,因为我没有在runOnUpdate类上分离/生成所有这些精灵。