My problem is that my game had micro lags when I was using the Limited FPS engine because the delta time was too inconsistent.
I described this Problem here: Andengine PhysicsHandler makes player look laggy
Now I am using the Fixed step engine to get a consistent delta time but now its lagging even more.
Maybe I did some mistakes with the game desing.
Here is the Code:
For the Fixed step engine I use this line:
#Override
public Engine onCreateEngine(EngineOptions pEngineOptions)
{
return new FixedStepEngine(pEngineOptions, 60);
}
For the player I am using these two classes (Blocks is the game grid):
public abstract class ActorObject extends AnimatedSprite {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
public PhysicsHandler mPhysicsHandler;
public Camera camera;
// ===========================================================
// Constructors
// ===========================================================
public ActorObject(final float pX, final float pY, final ITiledTextureRegion pTiledTextureRegion, final VertexBufferObjectManager pVertexBufferObjectManager, Camera camera) {
super(pX, pY, pTiledTextureRegion, pVertexBufferObjectManager);
this.mPhysicsHandler = new PhysicsHandler(this);
this.camera=camera;
this.registerUpdateHandler(this.mPhysicsHandler);
//updater=new Updater(this.camera,this);
this.registerUpdateHandler(new IUpdateHandler() {
#Override
public void onUpdate(final float pSecondsElapsed) {
onMove(pSecondsElapsed);
}
#Override
public void reset() {
// TODO Auto-generated method stub
}});
}
public void onMove(float pSecondsElapsed){};
}
public class Player extends ActorObject {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
public int direction;
public int desDirection;
public boolean canmove_vert;
public boolean canmove_hor;
Blocks[][] block;
boolean final_goal=false;
GameScene gm;
Rectangle rects;
Rectangle rects2;
VertexBufferObjectManager pVertexBufferObjectManager;
private int lastX;
private int lastY;
// ===========================================================
// Constructors
// ===========================================================
public Player(final float pX, final float pY, final VertexBufferObjectManager pVertexBufferObjectManager, Blocks[][] block2, int i, int p,final Camera camera,final GameScene gm) {
super(pX, pY, ResourcesManager.getInstance().player_region, pVertexBufferObjectManager,camera);
block=block2;
this.pVertexBufferObjectManager=pVertexBufferObjectManager;
this.gm=gm;
rects=new Rectangle(this.getX(),this.getY(),78,78,ResourcesManager.getInstance().vbom);
rects2=new Rectangle(this.getX(),this.getY(),2f,2f,ResourcesManager.getInstance().vbom);
canmove_hor=false;
canmove_vert=false;
direction=Globals.RIGHT;
setCullingEnabled(true);
final long[] PLAYER_ANIMATE = new long[] { 130, 130, 130,130, 130, 130,130, 130, 130,130, 130, 130, 130, 130, 130, 130, 130, 130, 130, 130,130,130 };
// animate(PLAYER_ANIMATE, 0, 21, true);
}
// ===========================================================
// Methods
// ===========================================================
public Rectangle getBounds(){
return rects;
}
public Rectangle getSmallBounds(){
return rects2;
}
public void setDirection(int dir){
direction=dir;
}
#Override
public void onMove(final float sec){
rects.setX(this.getX());
rects.setY(this.getY());
rects2.setPosition(this.getX(), this.getY());
for(int i=0;i<Globals.OFFSETX;i++){
for(int p=0;p<Globals.OFFSETY;p++){
if(this.getBounds().collidesWith(block[i][p].getBounds())){
this.mPhysicsHandler.setVelocity(0, 0);
this.loadLastPos();
}
else if(this.getSmallBounds().collidesWith(block[i][p].getSmallBounds())){
switch(desDirection){
case Globals.LEFT:
if(block[i][p].links_frei){
direction=Globals.LEFT;
desDirection=Globals.NICHTS;
this.setPosition(block[i][p].x, block[i][p].y);
this.mPhysicsHandler.setVelocityY(0);
this.mPhysicsHandler.setVelocityX(-150);
this.setRotation(270);
}
break;
case Globals.RIGHT:
if(block[i][p].rechts_frei){
direction=Globals.RIGHT;
desDirection=Globals.NICHTS;
this.setPosition(block[i][p].x+1, block[i][p].y+1);
this.mPhysicsHandler.setVelocityY(0);
this.mPhysicsHandler.setVelocityX(150);
this.setRotation(90);
}
break;
case Globals.UP:
if(block[i][p].oben_frei){
direction=Globals.UP;
desDirection=Globals.NICHTS;
this.setPosition(block[i][p].x+1, block[i][p].y+1);
this.mPhysicsHandler.setVelocityY(-150);
this.mPhysicsHandler.setVelocityX(0);
this.setRotation(0);
}
break;
case Globals.DOWN:
if(block[i][p].unten_frei){
direction=Globals.DOWN;
desDirection=Globals.NICHTS;
this.setPosition(block[i][p].x+1, block[i][p].y+1);
this.mPhysicsHandler.setVelocityY(150);
this.mPhysicsHandler.setVelocityX(0);
this.setRotation(180);
}
break;
}
}
}
}
this.saveLastPos();
}//end onmove
public void saveLastPos(){
lastX=(int) this.getX();
lastY=(int) this.getY();
}
public void loadLastPos() {
this.setX((float)lastX);
this.setY((float)lastY);
}
I am not using the Physics Box 2d extension.
Does anyone have a solution for this?
Try using the following engine. It's a custom engine I use in all my Andengine projects that allows for a smooth gameplay at a set step/rate without skipping, and it's more predictable than the other engines.
public class FixedStepMaxFPSEngine extends Engine {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
private final long mStepLength;
private long mSecondsElapsedAccumulator;
private final UpdateHandlerList mConstantUpdateHandlers = new UpdateHandlerList(8);
// ===========================================================
// Constructors
// ===========================================================
/**
* Create a new Fixed Step Max FPS engine.
* #param pEngineOptions {#link EngineOptions} Engine options to use.
* #param pStepsPerSecond {#link integer} How many updates a second?
*/
public FixedStepMaxFPSEngine(EngineOptions pEngineOptions, final int pStepsPerSecond) {
super(pEngineOptions);
this.mStepLength = TimeConstants.NANOSECONDS_PER_SECOND / pStepsPerSecond;
}
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
#Override
public void onUpdate(final long pNanosecondsElapsed) throws InterruptedException {
this.mSecondsElapsedAccumulator += pNanosecondsElapsed;
final long stepLength = this.mStepLength;
while(this.mSecondsElapsedAccumulator >= stepLength) {
final float pSecondsElapsed = stepLength * TimeConstants.SECONDS_PER_NANOSECOND;
this.onConstantUpdateUpdateHandlers(pSecondsElapsed);
this.mSecondsElapsedAccumulator -= stepLength;
}
super.onUpdate(pNanosecondsElapsed);
}
protected void onConstantUpdateUpdateHandlers(final float pSecondsElapsed) {
this.mConstantUpdateHandlers.onUpdate(pSecondsElapsed);
}
/**
* Register an {#link IUpdateHandler} to be updated using our constant game speed.
* #param pUpdateHandler {#link IUpdateHandler} to update.
* #see FixedStepMaxFPSEngine
*/
public void registerConstantUpdateHandler(final IUpdateHandler pUpdateHandler) {
this.mConstantUpdateHandlers.add(pUpdateHandler);
}
/**
* Unregister a {#link IUpdateHandler} from being updated using our constant game speed.
* #param pUpdateHandler {#link IUpdateHandler} to unregister.
*/
public void unregisterConstantUpdateHandler(final IUpdateHandler pUpdateHandler) {
this.mConstantUpdateHandlers.remove(pUpdateHandler);
}
/**
* Clear all {#link IUpdateHandler} registered for constant game speed updates.
*/
public void clearConstantUpdateHandlers() {
this.mConstantUpdateHandlers.clear();
}
// ===========================================================
// Methods
// ===========================================================
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
}
Related
I want to move background vertically.I tried it but it's not working.By applying below code image background remain still.I tried it by changing it's direction here (bgEntity = new VerticalParallaxEntity(0.0f, background, direction)) but cause no effect.
autoParallaxBackground = new VerticalParallaxBackground(0, 0, 0);
background = new Sprite(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT,
this.mParallaxLayerBack, this.vbom);
bgEntity = new VerticalParallaxEntity(0.0f, background, 1);
autoParallaxBackground.attachVerticalParallaxEntity(bgEntity);
autoParallaxBackground.attachVerticalParallaxEntity(bgEntity);
mainScene.setBackground(autoParallaxBackground);
I used this class :
public class VerticalParallaxBackground extends ParallaxBackground {
public static int SCROLL_DOWN = -1;
public static int SCROLL_UP = 1;
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
private final ArrayList<VerticalParallaxEntity> mParallaxEntities = new ArrayList<VerticalParallaxEntity>();
private int mParallaxEntityCount;
protected float mParallaxValue;
// ===========================================================
// Constructors
// ===========================================================
public VerticalParallaxBackground(float red, float green, float blue) {
super(red, green, blue);
// TODO Auto-generated constructor stub
}
// ===========================================================
// Getter & Setter
// ===========================================================
public void setParallaxValue(final float pParallaxValue) {
this.mParallaxValue = pParallaxValue;
}
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
#Override
public void onDraw(final GLState pGLState, final Camera pCamera) {
super.onDraw(pGLState, pCamera);
final float parallaxValue = this.mParallaxValue;
final ArrayList<VerticalParallaxEntity> parallaxEntities = this.mParallaxEntities;
// Log.d("VAPB", "VAPB onDraw pre entity");
for (int i = 0; i < this.mParallaxEntityCount; i++) {
parallaxEntities.get(i).onDraw(pGLState, pCamera, parallaxValue);
}
}
// ===========================================================
// Methods
// ===========================================================
public void attachVerticalParallaxEntity(
final VerticalParallaxEntity pParallaxEntity) {
this.mParallaxEntities.add(pParallaxEntity);
this.mParallaxEntityCount++;
}
public boolean detachVerticalParallaxEntity(
final VerticalParallaxEntity pParallaxEntity) {
this.mParallaxEntityCount--;
final boolean success = this.mParallaxEntities.remove(pParallaxEntity);
if (success == false) {
this.mParallaxEntityCount++;
}
return success;
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
public static class VerticalParallaxEntity {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
final float mParallaxFactor;
final IAreaShape mShape;
private int direction;
// ===========================================================
// Constructors
// ===========================================================
public VerticalParallaxEntity(final float pParallaxFactor,
final IAreaShape pShape) {
this.mParallaxFactor = pParallaxFactor;
this.mShape = pShape;
this.direction = VerticalParallaxBackground.SCROLL_DOWN;
}
public VerticalParallaxEntity(final float pParallaxFactor,
final IAreaShape pShape, int direction) {
this.mParallaxFactor = pParallaxFactor;
this.mShape = pShape;
this.direction = direction;
}
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
// ===========================================================
// Methods
// ===========================================================
public void onDraw(final GLState pGL, final Camera pCamera,
final float pParallaxValue) {
pGL.pushModelViewGLMatrix();
final float cameraHeight = pCamera.getHeight();
final float shapeHeightScaled = this.mShape.getHeightScaled();
float baseOffset = (pParallaxValue * this.mParallaxFactor)
% shapeHeightScaled;
while (baseOffset > 0) {
baseOffset -= shapeHeightScaled;
}
pGL.translateModelViewGLMatrixf(0, (direction * baseOffset), 0);
float currentMaxY = baseOffset;
do {
this.mShape.onDraw(pGL, pCamera);
pGL.translateModelViewGLMatrixf(0,
(direction * shapeHeightScaled), 0);
currentMaxY += shapeHeightScaled;
} while (currentMaxY < (cameraHeight + shapeHeightScaled));
// Added shapeHeightScaled to cameraHeight so the drawing flows in
// instead of popping in.
pGL.popModelViewGLMatrix();
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
}
}
Any suggestions?
Thanks in advance!
I can't add a comment to the previous answer so I'll just add to it here.
You need to use AutoVerticalParallaxBackground. This is not provided by default with the game engine but AndAppsUK has created the classes for us (both AutoVerticalParallaxBackground and VerticalParallaxBackground) - http://www.andengine.org/forums/post306324.html#p31347
After you have added the class to your code, simply change this line
autoParallaxBackground = new VerticalParallaxBackground(0, 0, 0);
to (notice the extra argument for the change speed and the different class)
autoParallaxBackground = new AutoVerticalParallaxBackground(0, 0, 0, 15);
Also, change the speed value on your VerticalParallaxEntity to like 0.2f
bgEntity = new VerticalParallaxEntity(0.2f, background, 1);
Then a little bit of experimentation should get you the result you want.
Hope this helps.
It looks like you've done everything right. Just increase the parallax factor here:
bgEntity = new VerticalParallaxEntity(0.0f, background, 1);
0.0f - is no factor so it doesn't move
You can also try
new VerticalParallaxBackground(0, 0, 0, 5);
where the last argument are changes per sec
I'm trying to implement Navigation Drawer using Drawer Layout without Action Bar.
Everything went smooth until i figured out that the drawer image didn't animate/slide like YouTube or Google Plus app.
What i meant with drawer image
Then i tried to implement my custom DrawerListener. Here is my activity class.
lstMenuDrawer.setOnItemClickListener(new OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> arg0, View arg1, int pos, long arg3) {
selectMenu(pos);
}
});
drawerToggle = new GRHDrawerToggle(MainActivity.this, imvDrawer.getDrawable());
drawerLayout.setDrawerListener(drawerToggle);
And here is my listener class
public class GRHDrawerToggle implements DrawerListener {
private Activity mActivity;
private SlideDrawable mSlider;
/** Fraction of its total width by which to offset the toggle drawable. */
private static final float TOGGLE_DRAWABLE_OFFSET = 1 / 3f;
public GRHDrawerToggle(Activity activity, Drawable drawerImage){
mActivity = activity;
mSlider = new SlideDrawable(drawerImage);
mSlider.setOffset(TOGGLE_DRAWABLE_OFFSET);
}
#Override
public void onDrawerClosed(View arg0) {
// TODO Auto-generated method stub
mSlider.setPosition(0);
}
#Override
public void onDrawerOpened(View arg0) {
// TODO Auto-generated method stub
mSlider.setPosition(1);
}
#Override
public void onDrawerSlide(View drawerView, float slideOffset) {
// TODO Auto-generated method stub
float glyphOffset = mSlider.getPosition();
if (slideOffset > 0.5f) {
glyphOffset = Math.max(glyphOffset, Math.max(0.f, slideOffset - 0.5f) * 2);
} else {
glyphOffset = Math.min(glyphOffset, slideOffset * 2);
}
mSlider.setPosition(glyphOffset);
}
#Override
public void onDrawerStateChanged(int arg0) {
// TODO Auto-generated method stub
}
private class SlideDrawable extends InsetDrawable implements Drawable.Callback {
private final boolean mHasMirroring = Build.VERSION.SDK_INT > 18;
private final Rect mTmpRect = new Rect();
private float mPosition;
private float mOffset;
private SlideDrawable(Drawable wrapped) {
super(wrapped, 0);
}
/**
* Sets the current position along the offset.
*
* #param position a value between 0 and 1
*/
public void setPosition(float position) {
mPosition = position;
invalidateSelf();
}
public float getPosition() {
return mPosition;
}
/**
* Specifies the maximum offset when the position is at 1.
*
* #param offset maximum offset as a fraction of the drawable width,
* positive to shift left or negative to shift right.
* #see #setPosition(float)
*/
public void setOffset(float offset) {
mOffset = offset;
invalidateSelf();
}
#Override
public void draw(Canvas canvas) {
copyBounds(mTmpRect);
canvas.save();
// Layout direction must be obtained from the activity.
final boolean isLayoutRTL = ViewCompat.getLayoutDirection(
mActivity.getWindow().getDecorView()) == ViewCompat.LAYOUT_DIRECTION_RTL;
final int flipRtl = isLayoutRTL ? -1 : 1;
final int width = mTmpRect.width();
canvas.translate(-mOffset * width * mPosition * flipRtl, 0);
// Force auto-mirroring if it's not supported by the platform.
if (isLayoutRTL && !mHasMirroring) {
canvas.translate(width, 0);
canvas.scale(-1, 1);
}
super.draw(canvas);
canvas.restore();
}
}
}
But still no sliding animation in my drawer button.
And then i realized method draw(Canvas canvas) in my listener class was never triggered.
Can someone tell me please where is my errors?
Many thanks.
gellaps
I try to use SurfaceGestureDetector This class use only SurfaceGestureDetector and not work. i a msg "03-14 20:40:47.746: I/AndEngine(8963): org.anddev.andengine.input.touch.TouchEvent$TouchEventPool was exhausted, with 0 item not yet recycled. Allocated 1 more." Only Tag Log.d("test", "TouchEvent"); work
public class MainActivity extends BaseGameActivity {
// ===========================================================
// Constants
// ===========================================================
private static final int CAMERA_WIDTH = 480;
private static final int CAMERA_HEIGHT = 320;
// ===========================================================
// Fields
// ===========================================================
private Camera mCamera;
//private Texture mTexture, mBatTexture;
//private TiledTextureRegion mBatTextureRegion;
//private TextureRegion mSplashTextureRegion;
private Handler mHandler;
//static protected Music mMusic;
private Scene mScene;
private SurfaceGestureDetector surfaceGestureDetector;
private TouchEvent pSceneTouchEvent;
// ===========================================================
// Constructors
// ===========================================================
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
#Override
public Engine onLoadEngine() {
mHandler = new Handler();
this.mCamera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
return new Engine(new EngineOptions(true, ScreenOrientation.LANDSCAPE, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT), this.mCamera));
}
#Override
public void onLoadResources() {
}
#Override
public Scene onLoadScene() {
this.mEngine.registerUpdateHandler(new FPSLogger());
this.mScene = new Scene();
setupGestureDetaction();
return mScene;
}
#Override
public void onLoadComplete() {
//mHandler.post(mLaunchTask);
}
private Runnable mLaunchTask = new Runnable() {
public void run() {
Intent myIntent = new Intent(MainActivity.this, TMXTiledMapExample.class);
MainActivity.this.startActivity(myIntent);
}
};
private void setupGestureDetaction(){
surfaceGestureDetector = new SurfaceGestureDetector(1f) {
#Override
protected boolean onSingleTap() {
// TODO Auto-generated method stub
Log.d("test", "onSingleTap");
return true;
}
#Override
protected boolean onDoubleTap() {
Log.d("test", "onDoubleTap");
// TODO Auto-generated method stub
return false;
}
#Override
protected boolean onSwipeUp() {
// TODO Auto-generated method stub
return false;
}
#Override
protected boolean onSwipeDown() {
// TODO Auto-generated method stub
return false;
}
#Override
protected boolean onSwipeLeft() {
// TODO Auto-generated method stub
return false;
}
#Override
protected boolean onSwipeRight() {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean onManagedTouchEvent(TouchEvent pSceneTouchEvent) {
return super.onManagedTouchEvent(pSceneTouchEvent);
}
#Override
public boolean onSceneTouchEvent(Scene pScene,
TouchEvent pSceneTouchEvent) {
Log.d("test", "TouchEvent");
return super.onSceneTouchEvent(pScene, pSceneTouchEvent);
//return false;
}
};
// if (pSceneTouchEvent!=null){
// TouchEvent.recycle(pSceneTouchEvent);}
surfaceGestureDetector.setEnabled(true);
mScene.setOnSceneTouchListener(surfaceGestureDetector);
}
// ===========================================================
// Methods
// ===========================================================
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
}
This question is old as i write this reply, but the log message you show above is a not an error message. It is an appropriate message letting you know that the Object Pool for touch events did not contain any touches, so it created more.
This is a normal message from Andengine, and you will see it when you first start using touches, but less as the app runs, because the pool size will grow, and so a touch will be recycled rather than created.
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) {
}
}
}
i had the same issue (last added visible sprite(s) in the group started blinking whenever i set any sprite to invisible), and solved it by overwriting those 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
I have code like this:
public class SnowFallService extends BaseLiveWallpaperService implements IOnAreaTouchListener{
// ===========================================================
// Constants
// ===========================================================
private static final int CAMERA_WIDTH = 480;
private static final int CAMERA_HEIGHT = 800;
private ArrayList<Sprite> allSnow = new ArrayList<Sprite>();
// ===========================================================
// Fields
// ===========================================================
private ScreenOrientation screenOrientation;
private static TextureRegion snowTexture;
private static TextureRegion backgroundTexture;
private static Textures texture = null;
private Scene mScene;
public org.anddev.andengine.engine.Engine onLoadEngine() {
return new org.anddev.andengine.engine.Engine(new EngineOptions(true, this.screenOrientation, new FillResolutionPolicy(), new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT)));
}
public void onLoadResources() {
texture = new Textures(this, getEngine());
}
public void onUnloadResources() {
}
public Scene onLoadScene() {
final Scene mScene = new Scene();
backgroundTexture = texture.getBackground();
mScene.attachChild(new Sprite(0, 0, backgroundTexture));
snowTexture = texture.getSnowTextureRegion();
mScene.registerUpdateHandler(new IUpdateHandler() {
private long lastRaindropAdd = 0;
#Override
public void onUpdate(final float pSecondsElapsed) {
int size = allSnow.size();
int tmpInt = 0;
Random randGen = new Random();
for (int i = 0; i < size; i++) {
if (allSnow.get(i) != null){
Sprite snow = allSnow.get(i);
tmpInt = randGen.nextInt(4);
snow.setPosition(snow.getX() + (randGen.nextInt(5) - randGen.nextInt(5)) * randGen.nextInt(3), snow.getY() + tmpInt);
if (snow.getY() > CAMERA_HEIGHT || snow.getX() > CAMERA_WIDTH) {
synchronized(snow) {
size--;
allSnow.remove(i);
mScene.detachChild(snow);
}
}
}
}
tmpInt = randGen.nextInt(5000);
if (System.currentTimeMillis() - lastRaindropAdd > tmpInt) {
lastRaindropAdd = System.currentTimeMillis();
tmpInt = randGen.nextInt(CAMERA_WIDTH);
Sprite snow = getRaindrop(tmpInt, 0);
allSnow.add(snow);
mScene.attachChild(snow);
}
}
#Override
public void reset() {
}
});
return mScene;
}
public void onLoadComplete() {
// TODO Auto-generated method stub
}
public void onPauseGame() {
// TODO Auto-generated method stub
}
public void onResumeGame() {
// TODO Auto-generated method stub
}
public Sprite getRaindrop(float x, float y) {
return (new Sprite(x, y, snowTexture.deepCopy()));
}
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent,ITouchArea pTouchArea, float pTouchAreaLocalX, float pTouchAreaLocalY) {
if(pSceneTouchEvent.isActionDown()) {
// HERE I WANT PLACE CODE, THAT WILL START ANIMATION.
return true;
}
return false;
}
}
So how to start animation on click? I want to make something like small cartoon.
In your onLoadScene method after registering update handler disable it.
mUpdateHandler.setEnabled(false);
And in onAreaTouched method enable it.
mUpdateHandler.setEnabled(true);
Btw I think it's not good practice to create Random instance every time in onUpdate method.
Here Josh describes how to override onTouch method (andEngine does not handle touch events for livewallpaper correctly, so you have to do it on your own). In few words, all you have to do is to override following function in BaseWallpaperGLEngine class (class is a part of andEngine live wallpaper extension:
#Override
public void onTouchEvent (MotionEvent event)
{
}