Android AndEngine: proper collision detection processing

I am working on a simple AndEngine game that includes ff. sprites

a.) b) soldiers c) bombs

I have a similar question located here: Android AndEngine: Simple sprite clash

What does the game look like:

enter image description here

However, when fixing the original task, another problem arose:

When a bomb (appears when the plane is currently located and goes down vertically until it reaches the target or the floor, with a click of the mouse) hits the target, say, a soldier, the soldier sprite should detach and leave blood spatter behind for 1 second, as well as an explosive sprite from a bomb. However, the game force closes, giving indexOutOfBoundError. I understand that this could probably be the discrepancy between the sprite count between the bomb and its target, which caused a linked array error, but logCat does not help at all.

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) 

As you can see here, logCat does not give an error for my code, but AndEngine itself, and this is most likely not the case.

My new code that runs in the onCreateScene update handler (as per the help on the previous previous issue):

 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(); } }); } 

What I noticed is that it can only be a sign or an explosion so that it does not have an error. If both characters and the explosion were supposed to fill the scene in a collision, an error occurs.

In addition, even if the bombs do not hit the soldiers (but still separate and are replaced by an explosion cloud when they hit the floor), it also gives a similar error:

My createBomb function:

  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; } 

My onCreateScene bomb function and collision update Handler:

  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() { } }); 

My createExplosion method:

  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; } 

How can i fix this? Loop logic is not exactly my forte. I also discover how to implement this.

UPDATE: I just realized that even if the result of a collision is either a bit or an explosion, it does not matter if the player holds spam bombs (for example, 4-5 times), all the game power is closed.

- It seems that there is an allowable amount of bombing whenever a soldering iron / tank is created. I turned off the creation of the explosion first whenever a bomb hits a soldier (so that the bloody platinum will simply remain in its place, and not both). It works fine, but exceeds 4-6 bombs, and the game closes. When a new soldier’s instance appears (which means that the old ones leave the screen and separate), the player is given 4-6 bombs until the game force closes.

+6
source share
3 answers

The problem may be caused by the fact that you are attaching bombs to the user interface thread by calling runOnUiThread, but you are checking for conflicts in the update thread. Try adding bombs inside runOnUpdateThread.

As a rule, you want to constantly monitor which thread you use to manipulate things, otherwise strange errors will occur that cause debugging.

On the side of the note: the UI thread is great for displaying Toasts, see this example:

 runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(GameActivity.this, "Hello!", Toast.LENGTH_SHORT).show(); } }); 
+4
source

To debug this, you need to track with the output (possibly through Log) how many of them were added to ACTUALLY in bombGroup and troopsGroup , and this should correspond to the number of added MUST. Try also to get getChildCount() and your parameters i and j.

For a wild guess, try the following:

 for (int i = 0; i < toBeDetached.size(); i++) { toBeDetached.get(i).detachSelf(); } 
+1
source

Well, with the help of Mr. Jonay, I was able to fix the problem in my code. Consider the following snippet:

  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(); } }); } 

As I mentioned, the game crashes due to a mismatch in the count between two colliding objects. This situation occurs when, as Mr. John Eyey notes, a sprite is created in the user interface thread, but not in the update thread. In addition, consider my createExplosion, createBomb, and createSplat functions:

CREATE 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; } 

CREATE EXPLOSION

 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; } 

CREATE 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; } 

Note that they all separate / generate other sprites in the runOnUpdate stream. The game ends in my previous passes because I did not separate / generate all these sprites in the runOnUpdate class.

+1
source

Source: https://habr.com/ru/post/925974/


All Articles