Sunday, November 10, 2019

libgdx - How to make members of an Array into an actor and add them to stage?



I have an animation (enemies) that I would like to add multiple times on the screen. From what I know, I can save memory and framerate-per-second by using one animating image and make an arraylist of it wherein each member is turned to an actor and added multiple times to the stage. I have searched similar problems like this but the answers were really not that helpful. Any help will be appreciated. Here's my code:


EnemyAnimation class:


    public class EnemyAnimation extends Actor{

Ninja app;
LevelOneScreen levelOneScreen;

private Animation animation;
private static final int FRAME_COLS_WALK = 10;
private static final int FRAME_ROWS_WALK= 1;

public TextureRegion currentFrame;
private float stateTime = 0f;

public float Xpos;
public float Ypos;
public static final int fallSpeed = 250;
public boolean remove = false;
final float delta = Gdx.graphics.getDeltaTime();




public animation(final Ninja app){
this.app = app;
Texture ninSprite = new Texture(Gdx.files.internal("ninSprite.jpg"), true);
ninSprite.setFilter(Texture.TextureFilter.MipMapLinearNearest,Texture.TextureFilter.MipMapLinearNearest);



TextureRegion[][] tmp = TextureRegion.split(ninSprite, (int) ninSprite.getWidth() / FRAME_COLS_WALK, (int) ninSprite.getHeight() / FRAME_ROWS_WALK);
TextureRegion[] ninTexRegion = new TextureRegion[FRAME_COLS_WALK * FRAME_ROWS_WALK];

int index = 0 ;
for (int i = 0; i < FRAME_ROWS_WALK; i++) {
for (int j = 0; j < FRAME_COLS_WALK; j++) {
ninTexRegion[index++] = tmp[i][j];
}
}

animation = new Animation(0.044f,ninTexRegion);
currentFrame = animation.getKeyFrame(stateTime, true);


}

public void draw(Batch batch, float parentAlpha) {

super.draw(batch, parentAlpha);

final float delta = Gdx.graphics.getDeltaTime();

stateTime += delta;


TextureRegion currentFrame = animation.getKeyFrame(stateTime, true);


batch.draw(currentFrame,Xpos,Ypos,getWidth(),getHeight());

}
}

LevelOneScreen class:


public class LevelOneScreen implements Screen {


public Ninja app;
private Stage stage;
private Stage stageNinja;
public EnemyAnimation enemyAnimation;
private Image ninImage;
private Image levelOneImage;
private float deltaTime = Gdx.graphics.getDeltaTime();

public ArrayList enemyAnimate;



public LevelOneScreen(final Ninja app){
this.app = app;
this.stage = new Stage(new StretchViewport(app.screenWidth, app.screenHeight, app.camera));
this.stageNinja = new Stage(new StretchViewport(app.screenWidth, app.screenHeight, app.camera));
enemyAnimate = new ArrayList();
enemyAnimation = new EnemyAnimation(app);
}



@Override
public void show() {

InputMultiplexer inputMultiplexer = new InputMultiplexer();
inputMultiplexer.addProcessor(stage);
inputMultiplexer.addProcessor(stageNinja);
Gdx.input.setInputProcessor(inputMultiplexer);





levelOneBackground();
enemy();
}


public void enemy(){



stageNinja.addActor(enemyAnimate);


/*

From here I cannot add the Arraylist enemyAnimate to the
stage and I received some errors. I would like to add elements to
enemyAnimate and make each added elements into actors with
different positions to be added to the stage.


*/


}





@Override

public void render(float delta) {


Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

update(delta);

}




public void update(float deltaTime){

stage.draw();
stageNinja.draw();

stage.act(deltaTime);
stageNinja.act(deltaTime);


}

Update to my code:


I now use Array of libgdx but it still won't show the enemies on stage without an indexOutOfBounds error. Here's the code:


public class LevelOneScreen implements Screen {

public Ninja app;
private Stage stage;
private Stage stageNinja;
public EnemyAnimation enemyAnimation;

private Image ninImage;
private Image levelOneImage;
private float deltaTime = Gdx.graphics.getDeltaTime();

public Array enemyAnimate;


public LevelOneScreen(final Ninja app){
this.app = app;
this.stage = new Stage(new StretchViewport(app.screenWidth, app.screenHeight, app.camera));

this.stageNinja = new Stage(new StretchViewport(app.screenWidth, app.screenHeight, app.camera));
enemyAnimate = new Array();
enemyAnimate.add(new EnemyAnimation(app));
enemyAnimation = new EnemyAnimation(app);
}


@Override
public void show() {


InputMultiplexer inputMultiplexer = new InputMultiplexer();
inputMultiplexer.addProcessor(stage);
inputMultiplexer.addProcessor(stageNinja);
Gdx.input.setInputProcessor(inputMultiplexer);




levelOneBackground();
enemyAct1();

// ......
enemyAct4();
}


public void enemyAct1(){

for(int i = 0; i < 6; i++){enemyAnimate.add(new EnemyAnimation(app));}

enemyAnimate.get(1).setPosition(app.screenWidth*0.1f,app.screenHeight);

stageEnemy.addActor(enemyAnimate.get(1));
float enemyTimeDrop1 = (app.screenHeight/app.screenHeight)*4.85f ;
enemyAnimate.get(1).addAction(moveTo(app.screenWidth*0.1f,enemyDestination,enemyTimeDrop1));


enemyAnimate.get(2).setPosition(app.screenWidth*0.1f+enemyAnimation.enemyWidth,app.screenHeight+enemyAnimation.enemyHeight);
stageEnemy.addActor(enemyAnimate.get(2));
float enemyHeight2 = app.screenHeight+enemyAnimation.enemyHeight;
float enemyTimeDrop2 = (enemyHeight2/app.screenHeight)*4.85f ;
enemyAnimate.get(2).addAction(moveTo(app.screenWidth*0.1f+enemyAnimation.enemyWidth,enemyDestination,enemyTimeDrop2));



enemyAnimate.get(3).setPosition(app.screenWidth*0.1f+enemyAnimation.enemyWidth*2f,app.screenHeight+enemyAnimation.enemyHeight*2f);
stageEnemy.addActor(enemyAnimate.get(3));
float enemyHeight3 = app.screenHeight+enemyAnimation.enemyHeight*2f;
float enemyTimeDrop3 = (enemyHeight3/app.screenHeight)*4.85f ;
enemyAnimate.get(3).addAction(moveTo(app.screenWidth*0.1f+enemyAnimation.enemyWidth*2f,enemyDestination,enemyTimeDrop3));


enemyAnimate.get(4).setPosition(app.screenWidth*0.1f+enemyAnimation.enemyWidth*3f,app.screenHeight+enemyAnimation.enemyHeight*3f);

stageEnemy.addActor(enemyAnimate.get(4));
float enemyHeight4 = app.screenHeight+enemyAnimation.enemyHeight*3f;
float enemyTimeDrop4 = (enemyHeight4/app.screenHeight)*4.85f ;
enemyAnimate.get(4).addAction(moveTo(app.screenWidth*0.1f+enemyAnimation.enemyWidth*3f,enemyDestination,enemyTimeDrop4));


enemyAnimate.get(5).setPosition(app.screenWidth*0.1f+enemyAnimation.enemyWidth*4f,app.screenHeight+enemyAnimation.enemyHeight*4f);
stageEnemy.addActor(enemyAnimate.get(5));
float enemyHeight5 = app.screenHeight+(enemyAnimation.enemyHeight*4f);
float enemyTimeDrop5 = (enemyHeight5/app.screenHeight)*4.85f ;

enemyAnimate.get(5).addAction(moveTo(app.screenWidth*0.1f+enemyAnimation.enemyWidth*4f,enemyDestination,enemyTimeDrop5));


}

enemyAct1() is drawn but enemyAct4() is not and returns an indexOutOfBoundsError : index can't be >= size: 21 >= 17. Here's enemyAct4():


public void enemyAct4(){
for(int i = 20; i < 30; i++){
enemyAnimate.add(new EnemyAnimation(app));
}



enemyAnimate.get(21).setPosition(app.screenWidth/2-enemyAnimation.enemyWidth/2,app.screenHeight);
stageEnemy.addActor(enemyAnimate.get(21));
float enemyTimeDrop1 = 4.85f ;
enemyAnimate.get(21).addAction(moveTo(app.screenWidth/2-enemyAnimation.enemyWidth/2,enemyDestination,enemyTimeDrop1));



enemyAnimate.get(22).setPosition((app.screenWidth/2-enemyAnimation.enemyWidth/2)+enemyAnimation.enemyWidth,(app.screenHeight+enemyAnimation.enemyHeight));

stageEnemy.addActor(enemyAnimate.get(22));
float enemyHeight22 = (app.screenHeight+enemyAnimation.enemyHeight);
float enemyTimeDrop22 = (enemyHeight22/app.screenHeight)*4.85f ;
enemyAnimate.get(22).addAction(moveTo((app.screenWidth/2-enemyAnimation.enemyWidth/2)+enemyAnimation.enemyWidth,enemyDestination,enemyTimeDrop22));


enemyAnimate.get(23).setPosition((app.screenWidth/2-enemyAnimation.enemyWidth/2)-enemyAnimation.enemyWidth,app.screenHeight+(enemyAnimation.enemyHeight));
stageEnemy.addActor(enemyAnimate.get(23));
float enemyHeight23 = app.screenHeight+(enemyAnimation.enemyHeight);
float enemyTimeDrop23 = (enemyHeight23 /app.screenHeight)*4.85f ;

enemyAnimate.get(23).addAction(moveTo((app.screenWidth/2-enemyAnimation.enemyWidth/2)-enemyAnimation.enemyWidth,enemyDestination,enemyTimeDrop23));


enemyAnimate.get(24).setPosition((app.screenWidth/2-enemyAnimation.enemyWidth/2)+(enemyAnimation.enemyWidth*2f),app.screenHeight+(enemyAnimation.enemyHeight*2f));
stageEnemy.addActor(enemyAnimate.get(24));
float enemyHeight24 = app.screenHeight+(enemyAnimation.enemyHeight*2f);
float enemyTimeDrop24 = (enemyHeight24/app.screenHeight)*4.85f ;
enemyAnimate.get(24).addAction(moveTo((app.screenWidth/2-enemyAnimation.enemyWidth/2)+(enemyAnimation.enemyWidth*2f),enemyDestination,enemyTimeDrop24));



enemyAnimate.get(25).setPosition((app.screenWidth/2-enemyAnimation.enemyWidth/2)-(enemyAnimation.enemyWidth*2f),app.screenHeight+(enemyAnimation.enemyHeight*2f));
stageEnemy.addActor(enemyAnimate.get(25));
float enemyHeight25 = app.screenHeight+(enemyAnimation.enemyHeight*2f);
float enemyTimeDrop25 = (enemyHeight25/app.screenHeight)*4.85f ;
enemyAnimate.get(25).addAction(moveTo((app.screenWidth/2-enemyAnimation.enemyWidth/2)-(enemyAnimation.enemyWidth*2f),enemyDestination,enemyTimeDrop25));

}







@Override
public void render(float delta) {


Gdx.gl.glClearColor(0, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);


update(delta);

}



public void update(float deltaTime){

stage.draw();
stageNinja.draw();


stage.act(deltaTime);
stageNinja.act(deltaTime);

}

Answer



You load a new Texture in each EnemyAnimation which loads alot of memory.


For example if it's a 500x500 image, it has 250,000 pixels. One pixel has 3 bytes so it's 750000 bytes -> 0.71 MB. One enemy takes 1MB of RAM. Remember that I've mentioned 500x500 image, your is probably bigger.


It's unacceptable, you should reuse the image on all enemies.


Use AssetLoader/AssetManager as written here: https://github.com/libgdx/libgdx/wiki/Managing-your-assets



You should load your ninSprite.jpg with AssetManager and then in your NinjaAnimate class call


Texture tex = manager.get("data/mytexture.png", Texture.class);

Remember to use only one instance of your AssetManager and load them only once.


No comments:

Post a Comment

Simple past, Present perfect Past perfect

Can you tell me which form of the following sentences is the correct one please? Imagine two friends discussing the gym... I was in a good s...