Removing sprite when Touched

397 views Asked by At

The sprite is spawned every second and when it's touched, it should be removed.

This is what I did:

//Render the sprites and making them move:
public void draw(SpriteBatch batch) {
    for(Sprite drawEnemy:enemies) {
        drawEnemy.draw(batch);
        drawEnemy.translateY(deltaTime * movement);
        touchInput(drawEnemy.getX(),drawEnemy.getY(),
            drawEnemy.getWidth(),drawEnemy.getHeight(),drawEnemy);
    }
}

//Detecting the touch input:
public void touchInput(float x,float y,float w,float h,Sprite sprite){
    float touchX=Gdx.input.getX();
    float touchY=Gdx.input.getY();

    if(Gdx.input.justTouched()){
        if(touchX > x && touchX < x+w ){
            enemyIterator.remove();
            Pools.free(sprite);
        }
    }
}

The touch input is detected, but I'm not sure how to remove them.
The result is an error when I touch them.

1

There are 1 answers

0
Tenfour04 On

You cannot reuse an iterator, so your enemyIterator is invalid and will cause exceptions.

To avoid needing to do this, change your touchInput method to simply test whether the object should be removed, not to remove it. Also note that you need to convert screen coordinates to world coordinates, so you must use the camera as well.

private Vector3 TMPVEC = new Vector3();

public boolean touched(float x,float y,float w,float h) {
    TMPVEC.set(Gdx.input.getX(), Gdx.input.getY(), 0);
    camera.unproject(TMPVEC);
    return Gdx.input.justTouched() && TMPVEC.x > x && TMPVEC.x < x+w;
}

You can only use the iterator at the place where you're iterating. So you must acquire a local reference at the loop like this:

public void draw(SpriteBatch batch) {
    for (Iterator<Sprite> iterator = enemies.iterator(); iterator.hasNext();) {
        Sprite drawEnemy = iterator.next();
        drawEnemy.draw(batch);
        drawEnemy.translateY(deltaTime * movement);
        if (touched((drawEnemy.getX(),drawEnemy.getY(), drawEnemy.getWidth(),drawEnemy.getHeight())){
            iterator.remove();
            Pools.free(sprite);
        }
    }
}

However, the above is kind of muddy because you're mixing update and drawing code up together, and drawing before updating, and checking for touches over and over without need. I would redo it all like this:

private Vector3 TMPVEC = new Vector3();

public void update (Camera camera, float deltaTime) {
    boolean checkTouch = Gdx.input.justTouched();
    if (checkTouch) {
        TMPVEC.set(Gdx.input.getX(), Gdx.input.getY(), 0);
        camera.unproject(TMPVEC);
    } //This way we only unproject the point once for all sprites

    for (Iterator<Sprite> iterator = enemies.iterator(); iterator.hasNext();) {
        Sprite enemy = iterator.next();
        enemy.translateY(deltaTime * movement);

        if (checkTouch && touched(enemy, TMPVEC)){
            iterator.remove();
            Pools.free(sprite);
        }
    }
}

private void touched (Sprite sprite, Vector3 touchPoint){
    return sprite.getX() <= touchPoint.x && 
        sprite.getX() + sprite.getWidth() <= touchPoint.x;
}

public void draw (SpriteBatch batch){
    for (Sprite sprite : enemies) sprite.draw(batch);
}

Here you would call update before draw from the owning class.