1
\$\begingroup\$

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<EnemyAnimation> 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>();
        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<EnemyAnimation> 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<EnemyAnimation>();
        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);

    }
\$\endgroup\$
2

2 Answers 2

1
\$\begingroup\$

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.

\$\endgroup\$
11
  • \$\begingroup\$ Hey man, thanks for your response. I want to know if it's a smart choice to use array of libgdx instead of arraylist and from there I will also use AssetManager. \$\endgroup\$
    – JAlmazan
    Commented Jan 17, 2017 at 7:55
  • \$\begingroup\$ To be super-professional you should use Object Pooling: github.com/libgdx/libgdx/wiki/Memory-management Also, you shouldn't use Array class from GDX. Use classic ArrayList \$\endgroup\$
    – Jacob
    Commented Jan 17, 2017 at 10:09
  • \$\begingroup\$ From what I have researched Array is better than ArrayList, or am I missing something? \$\endgroup\$
    – JAlmazan
    Commented Jan 18, 2017 at 2:23
  • \$\begingroup\$ You have to specify, doyou want to use a normal array like Ninja[] or the Array class?libgdx.badlogicgames.com/nightlies/docs/api/com/badlogic/gdx/… \$\endgroup\$
    – Jacob
    Commented Jan 18, 2017 at 7:47
  • \$\begingroup\$ I want to use the array that will let me add elements beyond 17. \$\endgroup\$
    – JAlmazan
    Commented Jan 18, 2017 at 8:14
1
\$\begingroup\$

An EnemyAnimation is an actor in itself, you do not need to create an actor from the list of EnemyAnimation as the title of your post suggests.

EnemyAnimate is NOT an actor, it is a List of actors, so the line

stageNinja.addActor(enemyAnimate);

should be replaced by

stageNinja.addActor(enemyAnimate.get(i)); // where i is an iterator you need to set to get the actor you want to get.

In the LevelOneScreen constructor you initialize an EnemyAnimation object but you never add it to the List.

You can change the line

enemyAnimation = new EnemyAnimation(app);

to

enemyAnimate.add(new EnemyAnimation(app));

and you can get rid of the enemyAnimation variable as it will not be used anymore.

\$\endgroup\$
8
  • \$\begingroup\$ Sorry for the late reply, I tried using your solution and it worked but only to a limited number of 17 elements inside the arraylist. I get an error when I set a for loop with i being equal to more than 17, the error says indexOutOfBounds and that it should only be 17 max. \$\endgroup\$
    – JAlmazan
    Commented Jan 17, 2017 at 7:49
  • \$\begingroup\$ I also tried replacing ArrayList with Array of libgdx and the indexoutofbounds error is still there. \$\endgroup\$
    – JAlmazan
    Commented Jan 17, 2017 at 7:53
  • \$\begingroup\$ IndexOutOfBound is because the indexes start at 0 and go to size - 1. For example if you have a 17 elements array, you need to call myArray[16] to access last element, myArray[17] will cause an IndexOutOfBound \$\endgroup\$ Commented Jan 17, 2017 at 9:07
  • \$\begingroup\$ How can I set the size of an array? I will be using maybe 500 elements. When I make a for loop like this it gives an outofbounds error and says max is 17 when I don't even set the size of the array to 17. Here's the for loop: for(i = 20 ; i < 30; i++){} ==> gives an error saying 20>17 \$\endgroup\$
    – JAlmazan
    Commented Jan 18, 2017 at 2:25
  • \$\begingroup\$ An ArrayList has no fixed size. If you have an IndexOutOfBound exception it means you have added only 17 elements in your list, and you are trying to access the 20th, that's all. You can check the size of your list by doing enemyAnimate.size() \$\endgroup\$ Commented Jan 18, 2017 at 9:16

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .