Search code examples
libgdx

LibGdx - Adding array of actors to a table, with delay


I want to have several comets falling in the background of my UI,I have a working comet Actor that does what it is supposed to, but I am not sure how to create a continuous spawn with these comets (with a random delay between each) in a table, without scene2d/actors it would look something like:

cometTimer += delta
if(cometTimer >= interval){
    addCometToArray();
    cometTimer = 0;
}

With the cometArray being looped over and drawn every frame, and then removing the entity when it goes out of bounds.

The only way I know how to add Actors to a table is like this:

table().add(new DialogComet());

How would I go about adding this type of behaviour using Scene2d?


Solution

  • Not sure if this is what you were looking for, but the below is a small working app that shows comets "falling" from the top to bottom, using Tables and having the tables manage the comets (no separate array/data structure). I created a small Comet class that extends Actor as well, to allow for movement and placement.

    "main" class:

    import java.util.Iterator;
    
    import com.badlogic.gdx.ApplicationListener;
    import com.badlogic.gdx.Gdx;
    import com.badlogic.gdx.graphics.GL20;
    import com.badlogic.gdx.graphics.OrthographicCamera;
    import com.badlogic.gdx.graphics.g2d.Batch;
    import com.badlogic.gdx.graphics.g2d.BitmapFont;
    import com.badlogic.gdx.graphics.g2d.SpriteBatch;
    import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
    import com.badlogic.gdx.graphics.glutils.ShapeRenderer.ShapeType;
    import com.badlogic.gdx.scenes.scene2d.Actor;
    import com.badlogic.gdx.scenes.scene2d.Stage;
    import com.badlogic.gdx.scenes.scene2d.ui.Table;
    
    public class StageComet  implements ApplicationListener {
    
        private static final float INTERVAL = 0.3f;
    
        private Batch batch;
        private ShapeRenderer shapeRenderer;
        private OrthographicCamera camera;
        private BitmapFont font;
    
        private Table rootTable;
        private Table cometTable;
        private Stage stage;
        private Iterator<Actor> iter;
        private Comet comet;
    
        private float cometTimer = 0;
        private float delta = 0;
    
        @Override
        public void create() {
    
            camera = new OrthographicCamera();
            camera.setToOrtho(false, 960, 640);
    
            shapeRenderer = new ShapeRenderer();
            batch = new SpriteBatch();
            font = new BitmapFont();
    
            stage = new Stage();
    
            /*
             * The root table could contain main "play" actors. It is empty in this example.
             */
            rootTable = new Table();
            rootTable.setFillParent(true);
    
            /*
             * Usually in Scene2d I think the practice is only to have 1 root table that takes up the entire screen (above), 
             * but for simplicity/illustrative purposes, I created a cometTable only, set it to Fill Parent as well, and the
             * getChildren() of the table will have our array of comets in play at any given time.
             */
            cometTable = new Table();
            cometTable.setFillParent(true);
    
            stage.addActor(rootTable);
            stage.addActor(cometTable);
        }
    
    
        @Override
        public void render() {
            Gdx.gl.glClearColor(0, 0, 0.2f, 1);
            Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    
            camera.update();
            batch.setProjectionMatrix(camera.combined);
    
            delta = Gdx.app.getGraphics().getDeltaTime();
            stage.act(delta);                                               // make sure the comets "fall"
    
            shapeRenderer.begin(ShapeType.Filled);                          // simple rendering of comets, they are just a circle ...
            iter = cometTable.getChildren().iterator();                     // Table subclasses Group, which has a snapshot array of its Actors 
            while ( iter.hasNext() ) {
                comet = (Comet)iter.next();
    
                shapeRenderer.circle(comet.getX(), comet.getY(), 20.0f);    // Draw the comet
    
                if ( comet.getY() < -100 ) {                                // Hack/hardcode, if the comet fell far enough "off stage" ...
                    iter.remove();                                          // ... remove it from the stage
                }
            }
            shapeRenderer.end();
    
            /*
             * Sample code from original question on how to create a comet without scene2d ...
             */
            cometTimer += delta;
            if ( cometTimer > INTERVAL ) {
                cometTable.add(new Comet());                                // ... but in this case, we use scene2d
                cometTimer = 0;
            }
    
            /*
             * To keep track, display a simple message of # of comets on stage at any given time.
             */
            batch.begin();
            font.draw(batch, "Comets on stage: " + cometTable.getChildren().size, 100, 100);
            batch.end();
         }
    
        /*
         * I may have missed disposing something, but you get the idea ...
         */
        @Override
        public void dispose() {
            shapeRenderer.dispose();
            batch.dispose();
            stage.dispose();
            font.dispose();
        }
    
        @Override
        public void resize(int width, int height) {  }
    
        @Override
        public void pause() { }
    
        @Override
        public void resume() { }
    }
    

    And the small Comet class:

    import com.badlogic.gdx.Gdx;
    import com.badlogic.gdx.scenes.scene2d.Actor;
    
    public class Comet extends Actor{
    
        /*
         * Spawn a comet at the top of the screen, in the middle
         */
        public Comet() {
            super();
            this.setY(Gdx.app.getGraphics().getHeight());
            this.setX(Gdx.app.getGraphics().getWidth()/2.0f);
        }
    
        /*
         * Let the comet fall (same speed) to the bottom of the screen ...
         */
        @Override
        public void act (float delta) {
            this.setY(this.getY() - 10);
            super.act(delta);
        }
    
    }