javalibgdxspawning

libgdx Temporary sprite movement after being spawned


public class Player {
    private Sprite enemy;

    public Rectangle bounds;
    private SpriteBatch batch;
    private float deltaTime;
    private float timer;

    private ArrayList<Sprite> enemies;
    private Iterator<Sprite> enemyIterator;
    private ArrayList<Vector2> posCoordinate;
    Sprite newEnemy;

    public void create(){
        batch=new SpriteBatch();
        timer=0;

        enemy=new Sprite(new Texture(Gdx.files.internal("spr_player.png"))); 
        bounds=new Rectangle(200,700,82,80);

        enemies=new ArrayList<Sprite>();
        posCoordinate=new ArrayList<Vector2>();
        newEnemy=Pools.obtain(Sprite.class);

    }

    public void update(){
        deltaTime=Gdx.graphics.getDeltaTime();
        enemyIterator=enemies.iterator();
        timer+=1*deltaTime;

        if(timer>=1f){
            newEnemy();  //method called every second
            timer-=1;
        }

    }

    public void newEnemy(){

        Vector2 position=Pools.obtain(Vector2.class); //vector2 is created for each enemy every second.
        position.set(200,700);
        posCoordinate.add(position);

        newEnemy=Pools.obtain(Sprite.class); //enemy created every second
        newEnemy.set(enemy);

        enemies.add(newEnemy);
    }

    public void draw(SpriteBatch batch){

        //this is where the enemy position is set and movement
        for(Sprite enemy:enemies){
            enemy.draw(batch);
        }for(Vector2 position:posCoordinate){
            newEnemy.setPosition(position.x,position.y);
            position.y-=2;

        }
            }

        }

newEnemy() method is being called every second that's why a new sprite is being rendered every second.

Basically what I'm trying to do is that when a new enemy is spawned, it must move downward until it goes outside the screen.But what is happening is that the enemy will only move for one second.


Solution

  • I think you've confused things by introducing the member variable newEnemy. You have a method that creates a new enemy and adds it to your enemies list, and after that, there should not be a reason to reference it separately from the list, so you should just allow the newEnemy reference to be discarded.

    Therefore, you should remove the Sprite newEnemy line from your class, and just declare it within the newEnemy() method.

    Also, there's no need for your list of Vector2's for positions, because the Sprite class already stores a position. You just need to move the individual sprites. So remove everything related to posCoordinate as well. Your newEnemy() method should just look like this:

    private void newEnemy(){
        Sprite newEnemy = Pools.obtain(Sprite.class);
        newEnemy.set(enemy); //I recommend renaming your `enemy` variable to something like `prototypeEnemy` for clarity
        newEnemy.setPosition(200, 700); //need to start it at correct location.
        enemies.add(newEnemy);
    }
    

    Finally, in your draw method (which is the wrong place for updates) you're trying to move only the most recent enemy created, instead of moving all of them. Note that every iteration of the loop is affecting the same instance: newEnemy, which is only the last enemy you created.

    Here's how I would revise your class.

    1) The movement speed should be a constant, measured in world units per second, so declare something like this at the top of your class:

    private static final float ENEMY_SPEED = -120f;
    

    2) At the bottom of your update() method, you can add this to cause all of your enemies to move:

    for (Sprite sprite : enemies){
        sprite.translateY(deltaTime * ENEMY_SPEED);
    }
    

    3) Under that, you can add a check for when they are off screen, so you can remove them. The iterator instance must be used to avoid a ConcurrentModificationException.

    Iterator<Sprite> enemyIterator = enemies.iterator();
    while (enemyIterator.hasNext()){
        Sprite sprite = enemyIterator.next();
        if (sprite.getY() + sprite.getHeight() < screenBottom) //screenBottom is something you can calculate from your camera like camera.getPosition().y - camera.getHeight()/2
            removeEnemy(sprite);
    }
    

    4) And to remove them, since you're using pooling, you should put them back in the pool when you finish with them

    private void removeEnemy(Sprite sprite){
        enemies.remove(sprite);
        Pools.free(sprite);
    }
    

    5) In your draw method, remove the second for loop, now that we're handling the position update in the update method.