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\$
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\$
  • \$\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 Jan 17 '17 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 Jan 17 '17 at 10:09
  • \$\begingroup\$ From what I have researched Array is better than ArrayList, or am I missing something? \$\endgroup\$ – JAlmazan Jan 18 '17 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 Jan 18 '17 at 7:47
  • \$\begingroup\$ I want to use the array that will let me add elements beyond 17. \$\endgroup\$ – JAlmazan Jan 18 '17 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\$
  • \$\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 Jan 17 '17 at 7:49
  • \$\begingroup\$ I also tried replacing ArrayList with Array of libgdx and the indexoutofbounds error is still there. \$\endgroup\$ – JAlmazan Jan 17 '17 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\$ – realUser404 Jan 17 '17 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 Jan 18 '17 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\$ – realUser404 Jan 18 '17 at 9:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.