как определить касание мышкой объекта(отрисованного в swing окне), находящегося в массиве

Я новичок в java, недавно начал писать свою игру(на подобие worldbox).

У меня есть двумерный массив типа int, это поле игры, которое я отрисовываю с помощью Graphics g. Если в массиве под нужной клеткой 1, то это земля (зеленная клетка), 2 - то вода(синяя клетка) и так далее.

Столкнулся с такой проблемой, по задумке игрок должен влиять на виртуальный мир с помощью мышки. Внизу есть кнопки, если нажата одна, то выбран инструмент земля, вторая - вода и так далее. То есть мне нужно определять, касается ли мышка объектов массива, и если да, то какого?

Если кто то знает как это осуществить, то пожалуйста опишите подробно как это сделать.


Ответы (1 шт):

Автор решения: Alexander Chernin

У нас есть мир, разбитый на клеточки разного типа (Земля, Вода). Значит заведем класс World и наследуем его от чего-нибудь на чем можно рисовать и размещать кнопки.

Приведу пример класса отрисовки игрового поля. Также на нем расположены 2 кнопки (не показаны). Код максимально упрощен и для наглядности, и потому что стал подзабывать Java :)

public class World extends JFrame {
    // Класс для хранения номера ячейки сетки
    class MeshCell {
        int row;
        int col;
    }

    // Данный enum нужен для определения типа квадратиков/тайлов
    public enum TileType {        
        LAND,
        WATER;
    };

    // Эти два поля будут хранить разметы мира
    private final int worldWidth;
    private final int worldHeight;

    // Это ассоциативный массив для хранения связи тип тайла - картинка
    // В приложении не используется. Добавил для наглядности
    private Map<TileType, BufferedImage> tiles = new HashMap<>();

    // Сетка для хранения типа тайла в ячейке
    private TileType[][] mesh = null;

    // Размер клеточки тайла
    private int tileSize = 10;

    // Конструктор
    // row - количество тайлов мира по-вертикали
    // column - по-горизонтали
    // tileSize - размер стороны тайла/клеточки мира
    public World(int row, int column, int tileSize) {
        super();
        initComponents();

        // Создаем сетку значений тайлов
        this.mesh = new TileType[row][column];
        this.tileSize = tileSize;

        // Вычисляем физический размер игрового поля
        this.worldHeight = tileSize*row;
        this.worldWidth = tileSize*column;

        // "Заливаем" все поле водой
        for(int i = 0; i < row; i++) {
            for(int j = 0; j < column; j++) {
                mesh[i][j] = TileType.WATER;
            }
        }        
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, this.getWidth(), getHeight());
        int posX = 0, posY = 0;
        for(int row = 0; row < mesh.length; row++) {
            posX = 0;
            for(int col = 0; col < mesh[row].length; col++) {
                // Здесь я просто закрашиваю нужный квадратик сплошным цветом,
                // если нужно рисовать картинку, то надо вызвать getTileImage
                // и отрисовывать изображение
                g.setColor(mesh[row][col] == TileType.WATER? Color.BLUE: Color.GREEN);
                g.fillRect(posX, posY, tileSize, tileSize);
                g.setColor(Color.BLACK);
                g.drawRect(posX, posY, tileSize, tileSize);
                posX += tileSize;
            }
            posY += tileSize;
        }
    }    

    // Задаем изображение соответствующее типу тайла
    public void setTileImage(TileType type, BufferedImage tile) {
        tiles.put(type, tile);
    }

    // Метод определения номер ячейки в сетке mesh
    // Возвращает cell, чей col - это номер столбца в сетке
    //                      row - это номер строки в сетке
    public MeshCell getCellBy(Point point) {
        MeshCell cell = new MeshCell();
        if( point.x > this.worldWidth )
            cell.col = -1;
        else
            cell.col = point.x / tileSize;

        if( point.y > this.worldHeight )
            cell.row = -1;
        else
            cell.row = point.y / tileSize;
        return cell;
    }

    public BufferedImage getTileImage(TileType type) {
        return tiles.getOrDefault(type, null);
    }

    // Функция обработки клика по поверхности игрового мира
    private void formMouseClicked(java.awt.event.MouseEvent evt) {                                  
        // Какую ячейку выбрали
        Point p = getCellBy(evt.getPoint());
        // Если клик находится за границей игрового мира, то ничего не делаем и выходим их функции
        if( p.x == -1 || p.y == -1 )
            return;


        // Какой тип поверхности выбран. По-умолчанию вода
        TileType type = TileType.WATER;
        if( this.jToggleButtonLAND.isSelected() )
            type = TileType.LAND;

        // Устанавливаем новое значение в ячейку игровой сетки
        mesh[p.y][p.x] = type;
        // Перерисовываем поле
        repaint();
    } 

Результат: ( Опять же кнопки книзу не отрисовались, потому что почему-то стираются. Почему, не знаю, а разбираться лень :) ):

введите сюда описание изображения

→ Ссылка