AndEngine - SpriteGroup blinks on newly attachChild - android

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

Related

Andengine micro lags with Fixed step engine

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
// ===========================================================
}

Camera does not follow player

I use libgdx have one player which moves in x direction from left to right. Now I want the camera to follow it (like in Flappy Bird for example).
What happen is that the player go out off screen when it reaches the right border of screen and the camera don't follow him.
I have tried following options but none of them worked:
camera.position.set(player.getX(), camera.position.y, 0);
camera.position.set(player.getX(), 0, 0);
Vector3 vector3= camera.unproject(new Vector3(player.getX(), 0f, 0f));
player.setX(vector3.x);
I know that this question already exists on SO but none answer works in this case. Maybe I miss something important that i don't know.
The code:
Game.java class
public class Game extends com.badlogic.gdx.Game implements ApplicationListener {
public static Vector2 VIEWPORT = new Vector2(320, 480);
public static int WIDTH;
public static int HEIGHT;
#Override
public void create() {
WIDTH = Gdx.graphics.getWidth();
HEIGHT = Gdx.graphics.getHeight();
// VIEWPORT = new Vector2(WIDTH/2, HEIGHT/2);
VIEWPORT = new Vector2(WIDTH, HEIGHT);
setScreen(new GameScreen(this));
}
#Override
public void resize(int width, int height) {
// TODO Auto-generated method stub
super.resize(width, height);
}
#Override
public void resume() {
}
#Override
public void pause() {
}
}
GameScreen.java class
import android.util.Log;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.Preferences;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.audio.Sound;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureAtlas;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Image;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.utils.ChangeListener;
import com.badlogic.gdx.utils.viewport.FitViewport;
import java.util.Collections;
public class GameScreen implements Screen {
private OrthographicCamera camera;
private Player player;
private PlayerInputHandler inputHandler1, inputHandler2;
private Sound sound;
FitViewport viewp;
public static int WIDTH;
public static int HEIGHT;
int width_spacing = 0;
int height_spacing = 0;
Stage stage;
Skin skin;
public GameScreen(Game game) {
stage = new Stage(new FitViewport(Game.WIDTH, Game.HEIGHT));
camera = (OrthographicCamera) stage.getCamera();
Gdx.input.setInputProcessor(stage);
}
#Override
public void show() {
resetGame();
}
public void resetGame() {
WIDTH = Gdx.graphics.getWidth();
HEIGHT = Gdx.graphics.getHeight();
width_spacing = Game.WIDTH / 24;
height_spacing = Game.HEIGHT / 14;
stage.clear();
skin = new Skin(Gdx.files.internal("data2/uiskin.json"));
prepareInputHandlers();
prepare_stage();
}
public void addPlayer() {
Texture texture = new Texture("player.png");
player = new Player(texture);
player.setPosition(Game.WIDTH / 2, Game.HEIGHT * 2 / 3);
stage.addActor(player);
}
#Override
public void resize(int width, int height) {
stage.getViewport().update(width, height, true);
}
#Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (delta > 1 / 60f) {
player.setX(player.getX() + (4 * delta));
camera.position.set(player.getX(), camera.position.y, 0);
}
update();
stage.act(delta);
stage.draw();
}
private void update() {
camera.update();
}
private void prepareInputHandlers() {
inputHandler2 = new PlayerInputHandler(player, Input.Keys.LEFT, Input.Keys.RIGHT, Input.Keys.UP, Input.Keys.DOWN);
}
#Override
public void dispose() {
sound.dispose();
player.getTexture().dispose();
}
public void prepare_stage() {
addPlayer();
player.setWidth(64);
player.setHeight(64);
}
#Override
public void resume() {
// TODO Auto-generated method stub
}
#Override
public void hide() {
// TODO Auto-generated method stub
}
#Override
public void pause() {
// TODO Auto-generated method stub
}
}
Player.java class
import com.badlogic.gdx.graphics.Texture;
public class Player extends com.badlogic.gdx.scenes.scene2d.ui.Image{
private Texture texture;
public Player(Texture texture) {
super(texture);
}
public Texture getTexture() {
return texture;
}
#Override
public void act(float delta) {
super.act(delta);
}
}
try to use stage's camera instead of creating your own. Change your GameScreen constructor like this:
public GameScreen(Game game)
{
stage = new Stage(new FitViewport(Game.WIDTH, Game.HEIGHT));
camera = (OrthographicCamera) stage.getCamera();
Gdx.input.setInputProcessor(stage);
}
then in the render method set the camera position just like
camera.position.set(player.getX(), camera.position.y, 0);
before camera.update() call
There is also something strange in your code - why you have camera.position.set() and setting player x in this condition:
if (delta > 1 / 60f) //??
{
player.setX(player.getX() + (4 * delta));
camera.position.set(player.getX(), camera.position.y, 0);
}
I'm pretty sure you don't need this - but even if you need the
camera.position.set(player.getX(), camera.position.y, 0);
should be out of if statement because what is happening now is that even if you are changing your player position (using keybord through PlayerInputHandler object) you **don't update camera position. Try to remove if statement or at least do something like
public void render(float delta)
{
Gdx.gl.glClearColor(1, 1, 1, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
if (delta > 1 / 60f)
{
player.setX(player.getX() + (100 * delta));
}
camera.position.set(player.getX(), camera.position.y, 0);
update();
stage.act(delta);
stage.draw();
}
last thing is that if your stage is empty (excluding player) when camera will start to follow player - you will see as player not moving at all :) Add someting more to stage

Move background vertically in andengine

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

GLMatrixStackOverflowExceptionwith SceneManager

I am developing a scene manager with AndEngine and am getting a GLMatrixStackOverflowExceptionerror:
E/AndroidRuntime(1906): FATAL EXCEPTION: GLThread 130
E/AndroidRuntime(1906): org.andengine.opengl.util.GLMatrixStack$GLMatrixStackOverflowException
E/AndroidRuntime(1906): at org.andengine.opengl.util.GLMatrixStack.glPushMatrix(GLMatrixStack.java:94)
E/AndroidRuntime(1906): at org.andengine.opengl.util.GLState.pushProjectionGLMatrix(GLState.java:574)
E/AndroidRuntime(1906): at org.andengine.entity.scene.Scene.onManagedDraw(Scene.java:243)
E/AndroidRuntime(1906): at org.andengine.entity.Entity.onDraw(Entity.java:1348)
E/AndroidRuntime(1906): at org.andengine.entity.Entity.onManagedDraw(Entity.java:1585)
E/AndroidRuntime(1906): at org.andengine.entity.scene.Scene.onManagedDraw(Scene.java:259)
2 Classes below: GameActivity and SceneManager
The problem occurs in GameActivity on this line:
sceneManager.setCurrentScene(SceneType.MENU); // ???
What am I doing wrong?
package com.example;
import java.io.IOException;
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.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.ui.activity.BaseGameActivity;
import android.util.Log;
import com.example.scenemanager.SceneManager;
import com.example.scenemanager.SceneManager.SceneType;
/**
* Example of using a SceneManager with GLES2 AnchorCenter
*/
public class GameActivity extends BaseGameActivity {
Scene mScene;
protected static final int CAMERA_WIDTH = 800;
protected static final int CAMERA_HEIGHT = 480;
BitmapTextureAtlas playerTexture;
ITextureRegion playerTextureRegion;
SceneManager sceneManager;
Camera mCamera;
#Override
public EngineOptions onCreateEngineOptions() {
mCamera = new Camera (0,0, CAMERA_WIDTH, CAMERA_HEIGHT);
EngineOptions engineOptions = (new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT) , mCamera));
return engineOptions;
}
#Override
public void onCreateResources(
OnCreateResourcesCallback pOnCreateResourcesCallback)
throws IOException {
// mEngine is from superclass
sceneManager = new SceneManager(this, mEngine, mCamera);
sceneManager.loadSplashSceneResources();
// let the game engine know we are done loading the resources we need
pOnCreateResourcesCallback.onCreateResourcesFinished();
}
#Override
public void onCreateScene(OnCreateSceneCallback pOnCreateSceneCallback)
throws IOException {
pOnCreateSceneCallback.onCreateSceneFinished(sceneManager.createSplashScene());
}
#Override
public void onPopulateScene(Scene pScene, OnPopulateSceneCallback pOnPopulateSceneCallback)
throws IOException {
mEngine.registerUpdateHandler(new TimerHandler(3.0f, new ITimerCallback() { // 3 seconds to load all stuff
#Override
public void onTimePassed(TimerHandler pTimerHandler) {
Log.d("onPopulateScene()", "onTimePassed()");
// unregister so as only do this once
mEngine.unregisterUpdateHandler(pTimerHandler);
// done displaying splash, so go to menu
sceneManager.loadMenuSceneResources();
sceneManager.createMenuScene();
mScene.registerUpdateHandler(new IUpdateHandler() {
#Override
public void reset() { }
#Override
public void onUpdate(final float pSecondsElapsed) {
Log.d("onPopulateScene()", "onUpdate()");
sceneManager.setCurrentScene(SceneType.MENU); // ???
}
});
}
}));
pOnPopulateSceneCallback.onPopulateSceneFinished();
}
}
package com.example.scenemanager;
import org.andengine.engine.Engine;
import org.andengine.engine.camera.Camera;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.Background;
import org.andengine.entity.sprite.Sprite;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.region.TextureRegion;
import org.andengine.ui.activity.BaseGameActivity;
public class SceneManager {
private SceneType currentScene;
private BaseGameActivity activity;
private Engine engine;
private Camera camera;
private Scene splashScene;
private Scene menuScene;
private Scene gameScene;
private BitmapTextureAtlas splashTextureAtlas;
private TextureRegion splashTextureRegion;
private BitmapTextureAtlas menuTextureAtlas;
private TextureRegion menuTextureRegion;
private float xPosition;
private float yPosition;
public enum SceneType
{
SPLASH,
MENU,
GAME
}
/**
* constructor
*
* #param baseGameActivity
* #param engine
* #param camera
*/
public SceneManager(BaseGameActivity baseGameActivity, Engine engine, Camera camera) {
this.activity = baseGameActivity;
this.engine = engine;
this.camera = camera;
xPosition = camera.getWidth()/2;
yPosition = camera.getHeight()/2;
}
public void loadSplashSceneResources() {
BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
splashTextureAtlas = new BitmapTextureAtlas(this.activity.getTextureManager(),256, 256);
splashTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(splashTextureAtlas, this.activity, "splash.png", 0, 0);
splashTextureAtlas.load();
}
public void loadMenuSceneResources() {
BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
menuTextureAtlas = new BitmapTextureAtlas(this.activity.getTextureManager(),256, 256);
menuTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(menuTextureAtlas, this.activity, "menu.png", 0, 0);
menuTextureAtlas.load();
}
public void loadGameSceneResources() {
}
public Scene createSplashScene() {
// Set background color and add the splash image
splashScene = new Scene();
splashScene.setBackground(new Background(0, 1, 0)); // green
Sprite splash = new Sprite(0, 0, splashTextureRegion, activity.getVertexBufferObjectManager());
splash.setPosition(xPosition, yPosition);
splashScene.attachChild(splash);
return splashScene;
}
public Scene createMenuScene() {
menuScene = new Scene();
menuScene.setBackground(new Background(0,0,0));
Sprite sprite = new Sprite (0, 0, menuTextureRegion, engine .getVertexBufferObjectManager());
sprite.setPosition(xPosition, yPosition);
menuScene.attachChild(menuScene);
return menuScene;
}
public void createGameScene() {
//Create the Main Game Scene and set background colour to blue
gameScene = new Scene();
gameScene.setBackground(new Background(0, 0, 1));
}
public SceneType getCurrentScene() {
return currentScene;
}
public void setCurrentScene(SceneType scene) {
if (scene != currentScene) {
currentScene = scene;
switch (scene)
{
case SPLASH:
break;
case MENU:
engine.setScene(menuScene);
break;
case GAME:
engine.setScene(gameScene);
break;
default:
break;
}
}
}
}

Manipulating variables in an activity with a method in another class

I am working on a game and have run into some issues. My architecture is something like this:
class GameView is used to draw bitmaps on my surfaces
class GameLoopThread is used to implement my game loop (if it wasn't obvious...)
class MovementUtils is used to hold all of my utilities related to moving objects
I want to house methods like gravity and movement controls in MovementUtils, but I'm having trouble actually updating the values in GameView. I tried using an intent, to no avail. I'll post my code, and maybe someone can show me what I should do. Also, ignore the Accelerometer lines, that's another problem entirely...
GameView.java
package com.example.connorgame;
import java.util.EventObject;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceHolder.Callback;
import android.view.SurfaceView;
public class GameView extends SurfaceView {
private Bitmap platform;
private Bitmap character;
private Bitmap background;
private SurfaceHolder holder;
private GameLoopThread gameLoopThread;
private MainActivity mainactivity;
private MovementUtils moveutil;
public float charX = 0;
public float charY = 0;
private boolean isFalling = true;
private boolean isJumping = false;
private float initialJumpY = 0;
private int initialFrame;
private int currentFrame;
private int frameDifference;
public GameView(Context context) {
super(context);
gameLoopThread = new GameLoopThread(this);
mainactivity = (MainActivity) context;
moveutil = new MovementUtils();
holder = getHolder();
holder.addCallback(new Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO Auto-generated method stub
}
#Override
public void surfaceCreated(SurfaceHolder holder) {
// TODO Auto-generated method stub
gameLoopThread.setRunning(true);
gameLoopThread.start();
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO Auto-generated method stub
}
});
platform = BitmapFactory.decodeResource(getResources(), R.drawable.platform);
character = BitmapFactory.decodeResource(getResources(), R.drawable.character);
background = BitmapFactory.decodeResource(getResources(), R.drawable.background);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(background, 0, 0, null);
canvas.drawBitmap(platform, 30, 700, null);
canvas.drawBitmap(character, charX, charY, null);
moveutil.gravity(charY, isFalling);
if (charY > getHeight() - character.getHeight()) {
initialFrame = gameLoopThread.numFrames;
initialJumpY = charY;
isFalling = false;
isJumping = true;
}
if (isJumping == true && isFalling == false) {
currentFrame = gameLoopThread.numFrames;
frameDifference = (currentFrame - initialFrame);
charY = charY - 5;
if (charY == initialJumpY - 100) {
isJumping = false;
isFalling = true;
}
}
}
}
MovementUtils.java
package com.example.connorgame;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
public class MovementUtils {
public void gravity (float charY, boolean isFalling) {
if(isFalling == true){
charY = charY + 5;
}
}
}
If I understand what you're doing correctly, you're trying to have charY in the GameView class modified by the gravity function. The issue is that float is a primitive, so it is based by value and only the local copy will be modified. If you passed an object instead, the object would be modified.
One solution is probably to just return the new Y position instead of trying to make gravity() change the Y position.
Another solution is to pass the GameView to MovementUtils and let MovementUtils modify it.
In other words, you would pass the GameView like this new MovementUtils(this);
And the gravity function would call a void setCharY(int y); in GameView.
public class MovementUtils {
private GameView gameView;
public MovementUtils(GameView view) {
this.gameView = view;
}
public void gravity (float charY, boolean isFalling) {
if(isFalling == true){
charY = charY + 5;
gameView.setCharY(charY);
}
}
}
Java only supports passing by value
So when you call moveutil.gravity(charY, isFalling);
and change it within the function, e.g.
public void gravity (float charY, boolean isFalling) {
if(isFalling == true){
charY = charY + 5;
}
Such change only occur in the local copy of the variable charY and does not affect the instance variable charY defined in your GameView class
To solve this, you can define your variables as objects as well as the argument to your functions, e.g.
public void gravity (Float charY, boolean isFalling) {}
And in your GameView class:
private Float charX = 0; // why you define them public !?
private Float charY = 0;
Alternatively, you can pass an instance of your GameView class or create a ValueObject class (similar to Context object in android) and use it to pass arguments

Categories

Resources