Search code examples
androidlibgdx

How to select a tile in grid and change its color


I made a 5x5 grid by brute force, and now I want to change the tile's color upon click. The problem is in the touch down method which I can't seem to solve. I am a newbie at libgdx.

package ksmd.tiles.Screens;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.utils.viewport.FitViewport;
import com.badlogic.gdx.utils.viewport.Viewport;

import ksmd.tiles.Tiles;
import ksmd.tiles.UI.Tile;

public class PlayScreen implements Screen, InputProcessor{



    private Tiles game;
    private Tile[][] tiles;
    private Viewport viewport;
    private OrthographicCamera camera;
    private boolean selected;
    private SpriteBatch batch;
    private Texture tex;
    private TextureRegion lit;
    private TextureRegion dark;
    private Vector3 mouse;

    private float WORLD_WIDTH = 480, WORLD_HEIGHT = 800; //to see 50 x 50 units of the world
    private float TILE_SIZE; //on tile is 10 units big

    public PlayScreen(Tiles game) {
        this.game = game;
    }

    @Override
    public void show() {

        camera = new OrthographicCamera(WORLD_WIDTH, WORLD_HEIGHT);
        camera.position.set(camera.viewportWidth / 2, camera.viewportHeight / 2, 0); // center the camera
        viewport = new FitViewport(WORLD_WIDTH, WORLD_HEIGHT, camera); // create a viewport which sees 50 x 50 units of the game world

        batch = new SpriteBatch();

        tex = new Texture(Gdx.files.internal("badlogic.jpg"));

        lit = Tiles.res.getAtlas("pack").findRegion("lit");
        dark = Tiles.res.getAtlas("pack").findRegion("dark");
        tiles = new Tile[5][5];
        TILE_SIZE = WORLD_WIDTH / tiles[0].length; //on tile is 10 units big

        //Create the tiles
        for(int row = 0; row < tiles.length; row++){
            for(int col = 0; col < tiles[0].length; col++){
                if (selected) {
                    tiles[row][col] = new Tile(col * TILE_SIZE, row * TILE_SIZE,TILE_SIZE, TILE_SIZE, lit);
                } else {
                    tiles[row][col] = new Tile(col * TILE_SIZE, row * TILE_SIZE,TILE_SIZE, TILE_SIZE, dark);

                }

            }
        }
    }

    public void setSelected (boolean b) {
        selected = b;
    }

    public boolean getSelected() {return selected; }

    //render the Tiles
    @Override
    public void render(float delta) {
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        batch.setProjectionMatrix(viewport.getCamera().combined);

        batch.begin(); //call batch.begin() (this is the only call of batch.begin() !!! )
        for(int row = 0; row < tiles.length; row++){
            for(int col = 0; col < tiles[0].length; col++){
                tiles[row][col].render(batch, delta); // call the render method of each tile
            }
        }
        batch.end();//call batch.end() (this is the only call of batch.end() !!! )
    }

    @Override
    public void resize(int width, int height) {
        viewport.update(width, height);
    }

    @Override
    public void dispose() {
        //dispose disposable objects
        batch.dispose();
    }

    @Override
    public void pause() {
    }

    @Override
    public void resume() {
    }

    @Override
    public void hide() {
    }

    @Override
    public boolean keyDown(int keycode) {
        return false;
    }

    @Override
    public boolean keyUp(int keycode) {
        return false;
    }

    @Override
    public boolean keyTyped(char character) {
        return false;
    }

    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) 
   {
    Vector3 clickPos = new Vector3(screenX, screenY,0);
    camera.unproject(clickPos);

    for(int row = 0; row < tiles.length; row++){
        for(int col = 0; col < tiles[0].length; col++){
            if(tiles[row][col].getBounding().contains(clickPos.x, clickPos.y)){
                //Tile tiles[row][col] was clicked
               selected = true;
            }
        }
    }

    return false;
}

    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {
        return false;
    }

    @Override
    public boolean touchDragged(int screenX, int screenY, int pointer) {
        return false;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        return false;
    }

    @Override
    public boolean scrolled(int amount) {
        return false;
    }
}

The problem is in touch down. I am not sure how to get x and y of the tile and change its color upon click.

package ksmd.tiles.UI;

import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.Sprite;
import com.badlogic.gdx.graphics.g2d.TextureRegion;

public class Tile {

private Sprite texture;
private Rectangle bounding;

public Tile(float x, float y, float widht, float height, TextureRegion tex) {
    texture = new Sprite(tex);
    texture.setBounds(x + 4, y *1.55f + 4, widht - 8, height* 1.55f - 8); // set bounds of Sprite
    bounding = new Rectangle(x + 4, y *1.55f + 4, widht - 8, height* 1.55f - 8);

}

public void render(Batch batch, float delta){
    //draw the sprite, but not call batch.begin() !!! because batch.begin() is already called!
    texture.draw(batch);
}

public Rectangle getBounding() { return bounding; }

}

I have edited the code to include tile class. This is a grid with rectangular tiles.


Solution

  • In your Tile class create a com.badlogic.gdx.math.Rectangle object which can check if a point is in this Rectangle:

    public class Tile {
        ...
        private Rectangle bounding;
    
        public Tile(float x, float y, float width, float height){
            ...
            bounding = new Rectangle(x, y, width, height);
    
        }
    
        public Rectangle getBounding() { return bounding; }
    }
    

    And then in your touchDown method:

    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        Vector3 clickPos = camera.unproject(screenX, screenY, 0);
    
        for(int row = 0; row < tiles.length; row++){
            for(int col = 0; col < tiles[0].length; col++){
                if(tiles[row][col].getBounding().contains(clickPos.x, clickPos.y)){
                    //Tile tiles[row][col] was clicked
                    return true;
                }
            }
        }
    
        return false;
    }