AndEngine - SpriteGroup blinks on new attachChild

I am using the latest version of AndEngine, the GLES2 branch, with two devices: HTC Desire and Galaxy Nexus.

I have a problem when using SpriteGroup with scroll sprites on the screen. New sprites attach to the SpriteGroup at the top of the screen and detach when they leave the bottom. And I use the pool so as not to use a lot of memory.

As soon as some sprites are disconnected, some recently attached sprites begin to flash randomly for several frames. This is very annoying, and I have no idea why ...

I tried to set Visible (false) sprites when reusing them, I also tried without a pool, but that does not change anything.

I think SpriteGroup may have a bug, but don’t know where. I tried linking the children in SpriteGroup in the begin () method to make sure that this did not happen during the onUpdateSpriteBatch () loop, with no luck.

Here is an example based on the AndEngineExamples project. You can directly replace the SpriteBatchExample class, start the project and go to Simple / Drawing 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) {
        }
    }
}
+5
source share
1 answer

I had the same problem (the last visible sprite added in the group started blinking whenever I set any sprite to the invisible) and solved it by overwriting these 2 methods in SpriteGroup:

SpriteGroup result = new SpriteGroup(atlas, capacity, vertexBufferObjectManager) {
    @Override
    protected boolean onUpdateSpriteBatch() {
            return false;
    }

    @Override
    protected void onManagedUpdate(float pSecondsElapsed) {
            super.onManagedUpdate(pSecondsElapsed);
            final SmartList<IEntity> children = this.mChildren;
            if(children != null) {
                    final int childCount = children.size();
                    for(int i = 0; i < childCount; i++) {
                            this.drawWithoutChecks((Sprite)children.get(i));
                    }
                    submit();
            }
    };

Source: http://www.andengine.org/forums/gles2/blinking-last-sprite-in-spritegroup-t7617.html

+3
source

All Articles