I'm using the last version of the AndEngine, branch GLES2, with two devices: HTC Desire and a Galaxy Nexus.
I have a problem when using a SpriteGroup with Sprites scrolling down on the screen. New sprites are attached to a SpriteGroup on the top of the screen and detached when they go off the bottom. And I use a pool to avoid using to much memory.
As soon as there are some sprites detached, some newly attached sprites begin to blink randomly for a few frames. This is very annoying and I have no idea why...
I tried to setVisible(false) the sprites when recycling them, I also tried without the pool but it doesn't change a thing.
I think that SpriteGroup may have a bug, but not sure where. I tried to attach the children in SpriteGroup in the begin() method to be sure it didn't happen during the loop of onUpdateSpriteBatch(), without luck.
Here is an example based on the AndEngineExamples project. You can directly replace the SpriteBatchExample class, launch the project and go to Simple/Drawing a SpriteBatch, to see the problem.
Thanks in advance for any idea !
package org.andengine.examples;
import java.util.Iterator;
import org.andengine.engine.camera.Camera;
import org.andengine.engine.handler.timer.ITimerCallback;
import org.andengine.engine.handler.timer.TimerHandler;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.resolutionpolicy.RatioResolutionPolicy;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.Background;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.sprite.batch.SpriteGroup;
import org.andengine.entity.util.FPSLogger;
import org.andengine.opengl.texture.TextureOptions;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.vbo.VertexBufferObjectManager;
import org.andengine.ui.activity.SimpleBaseGameActivity;
import org.andengine.util.adt.list.SmartList;
import org.andengine.util.adt.pool.GenericPool;
public class SpriteBatchExample extends SimpleBaseGameActivity {
// ===========================================================
// Constants
// ===========================================================
private static final int CAMERA_WIDTH = 720;
private static final int CAMERA_HEIGHT = 480;
// ===========================================================
// Fields
// ===========================================================
private BitmapTextureAtlas mBitmapTextureAtlas;
private ITextureRegion mFaceTextureRegion;
private float mSecondsElapsedSinceLastGeneration = 0;
// ===========================================================
// Constructors
// ===========================================================
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
@Override
public EngineOptions onCreateEngineOptions() {
final Camera camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
return new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), camera);
}
@Override
public void onCreateResources() {
BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
this.mBitmapTextureAtlas = new BitmapTextureAtlas(this.getTextureManager(), 32, 32, TextureOptions.BILINEAR);
this.mFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(this.mBitmapTextureAtlas, this, "face_box.png", 0, 0);
this.mBitmapTextureAtlas.load();
}
@Override
public Scene onCreateScene() {
this.mEngine.registerUpdateHandler(new FPSLogger());
final Scene scene = new Scene();
scene.setBackground(new Background(0.09804f, 0.6274f, 0.8784f));
final SpriteGroup spriteGroup = new SpriteGroup(this.mBitmapTextureAtlas, 500, this.getVertexBufferObjectManager());
spriteGroup.setPosition(0, 0);
scene.attachChild(spriteGroup);
final SpritePool lPool = new SpritePool(mFaceTextureRegion, getVertexBufferObjectManager());
final SmartList<Sprite> lSpriteList = new SmartList<Sprite>();
final float lCharactersPeriod = 0.4f;
scene.registerUpdateHandler(new TimerHandler(0.05f, true, new ITimerCallback() {
@Override
public void onTimePassed(final TimerHandler pTimerHandler) {
final float lSecondsElapsedSinceLastUpdate = 0.1f;
final Iterator<Sprite> li = lSpriteList.iterator();
while (li.hasNext()) {
final Sprite lChar = li.next();
boolean lRemoveChar = false;
// Character destruction OR movement
final float lY = lChar.getY();
if (lY > CAMERA_HEIGHT) {
lRemoveChar = true;
} else {
lChar.setPosition(lChar.getX(), lY + 60 * lSecondsElapsedSinceLastUpdate);
}
if (lRemoveChar) {
// Remove character from scene
lChar.detachSelf();
lPool.recyclePoolItem(lChar);
li.remove();
}
}
// Character generation
mSecondsElapsedSinceLastGeneration += lSecondsElapsedSinceLastUpdate;
if (mSecondsElapsedSinceLastGeneration > lCharactersPeriod) {
// generate sprite
final Sprite lSprite = lPool.obtainPoolItem();
lSprite.setPosition((float) Math.random() * CAMERA_WIDTH, 0);
spriteGroup.attachChild(lSprite);
lSpriteList.add(lSprite);
mSecondsElapsedSinceLastGeneration -= lCharactersPeriod;
}
}
}));
return scene;
}
// ===========================================================
// Methods
// ===========================================================
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
static class SpritePool extends GenericPool<Sprite> {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
private final VertexBufferObjectManager mVertexBufferObjectManager;
private ITextureRegion mFaceTextureRegion;
// ===========================================================
// Constructors
// ===========================================================
public SpritePool(final ITextureRegion pFaceTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager) {
mFaceTextureRegion = pFaceTextureRegion;
mVertexBufferObjectManager = pVertexBufferObjectManager;
}
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
@Override
protected Sprite onAllocatePoolItem() {
final Sprite lSprite = new Sprite(50, 0, mFaceTextureRegion, mVertexBufferObjectManager);
lSprite.setIgnoreUpdate(true);
return lSprite;
}
@Override
protected void onHandleRecycleItem(final Sprite pSprite) {
}
@Override
protected void onHandleObtainItem(final Sprite pSprite) {
}
}
}