Search code examples
javalibgdxshape-rendering

LibGDX draw shapes in response to click


I'm trying to draw a circle in the application window wherever the user clicks the mouse.

in the below example I draw a circle on the screen at fixed position. That works. Then I try to draw circles based on mouse click coords. The click registers and I can print out the coords on click. The coords are what I expect them to be for wherever I click.

current guesses:

  • the camera (or something else important) isn't wired into the PedigreeInputHandler correctly.
  • something is wrong with the way I'm using screens
  • the circle is being drawn but gets drawn over somehow

I'm not stuck with this implementation strategy if there's a better one.

public class PedigreeInputHandler implements InputProcessor {
     VGame game;

     public PedigreeInputHandler(VGame game){
          this.game = game;
     }

     
     ...

     @Override
     public boolean touchDown(int screenX, int screenY, int pointer, int button) {
          game.shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
          game.shapeRenderer.setColor(Color.BLACK);
          game.shapeRenderer.circle(screenX, screenY, 100);
          System.out.println(screenX);
          System.out.println(screenY);
          game.shapeRenderer.end();
          return false;
     }

     ...

     //other required functions are stubs
}

the PedigreeInputHandler is created in this main VGame class

package com.mygdx.vdna;

import com.badlogic.gdx.Game;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.glutils.ShapeRenderer;
import java.util.Random;

public class VGame extends Game {

    public OrthographicCamera camera;
    public ShapeRenderer shapeRenderer;
    public SpriteBatch batch;
    public double width;
    public double height;
    public float [] bgColor = {100, 0, 50};

    // Screens
    public MainMenuScreen mainMenuScreen;
    public GameScreen gameScreen;

    public void create() {
        width = 800;
        height = 480;
        batch = new SpriteBatch();

        camera = new OrthographicCamera();
        shapeRenderer = new ShapeRenderer();

        pedigreeInputHandler = new PedigreeInputHandler(this); // <-- 
        Gdx.input.setInputProcessor(pedigreeInputHandler);

        mainMenuScreen = new MainMenuScreen(this);
        gameScreen = new GameScreen(this);
        this.setScreen(mainMenuScreen); 
    }

    public void render() {
        super.render(); // important!
    }
    

This is the game screen that's showing. The black circle gets drawn correctly


public class GameScreen implements Screen {
    final VGame game;

    public GameScreen(VGame game) {
        this.game = game;
    }

    @Override
    public void render(float delta) {
        ScreenUtils.clear(game.bgColor[0], game.bgColor[1], game.bgColor[2], 1);
        game.shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
        game.shapeRenderer.circle(100,100,100);
        game.shapeRenderer.end();
    }
}

the game starts on a Menu screen defined by this class

public class MainMenuScreen implements Screen {

    final VGame game;

    OrthographicCamera camera;

    public MainMenuScreen(final VGame game) {
        this.game = game;

        camera = new OrthographicCamera();
        camera.setToOrtho(false, (float) game.width, (float)game.height);
    }

    @Override
    public void render(float delta) {
        ScreenUtils.clear(0, 0, 0.2f, 1);

        camera.update();
        game.batch.setProjectionMatrix(camera.combined);

        game.batch.begin();
        game.font.draw(game.batch, "Tap anywhere to begin!", 100, 100);
        game.batch.end();

        if (Gdx.input.isTouched()) {
            game.setScreen(game.gameScreen);
            game.gameScreen.render(0.0F);
            dispose();
        }
    }
     
    ...
    // other required methods are stubs

}

Solution

  • The comment from sorifiend was the solution

    Added the circle info to a list in the InputProcessor

         @Override
         public boolean touchDown(int screenX, int screenY, int pointer, int button) {
              float [] circArgs = {screenX, (float) (game.height - screenY), 100};
              game.pedigreeScreen.circlesToRender.add(circArgs);
              return false;
         }
    

    and read from it in the screen's render function

        @Override
        public void render(float delta) {
            ScreenUtils.clear(game.bgColor[0], game.bgColor[1], game.bgColor[2], 1);
            game.shapeRenderer.begin(ShapeRenderer.ShapeType.Filled);
            for (float [] c : game.pedigreeScreen.circlesToRender){
                game.shapeRenderer.circle(c[0], c[1], c[2]);
            }
            game.shapeRenderer.end();
    
        }