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