Java Swing mousePressed и getSource () не отображают нарисованные фигуры на JPanel - PullRequest
0 голосов
/ 05 марта 2019

Я сейчас пытаюсь разработать головоломку.Все, что я получил, это мое приложение с моим игровым полем и игровыми фигурами.Следующим шагом является нажатие на один из моих игровых элементов, чтобы выбрать его и иметь возможность перемещать его с помощью клавиш со стрелками (более того, я хочу, чтобы они двигались только в том случае, если следующий шаг - который будет состоять из 100 пикселей - не содержитлюбой другой игровой элемент).

Проблема, с которой я сейчас сталкиваюсь: использование addMouseListener() на моем основном JPanel, а затем использование getSource() возвращает только мое игровое поле (называемое View вмой код), но мне нужно вернуть желаемый игровой элемент (например, topLeft).Я уже пробовал приводить getSource() к Piece, но это не работает (Cannot cast View to Piece).

Итак, мне нужно найти способ добавить слушателя мыши, который возвращает игровой элемент, по которому щелкнуличтобы я мог изменить местоположение и проверить, нет ли столкновения с любым другим игровым элементом.Заранее спасибо!

Отредактированный код благодаря @ camickr.

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.AffineTransform;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Puzzle {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(Puzzle::new);
    }

    private final static int[] SHAPE_X = { -100, 100, 100, 0, 0, -100 };
    private final static int[] SHAPE_Y = { -100, -100, 0, 0, 100, 100 };

    public Puzzle() {
        JFrame frame = new JFrame("Puzzle");
        frame.setSize(400, 600);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        View view = new View();
        frame.setContentPane(view);
        view.addMouseListener(new MouseAdapterMod(view));

        Shape polyShape = new Polygon(SHAPE_X, SHAPE_Y, SHAPE_X.length);
        Piece topLeft = new Piece(Color.YELLOW, polyShape,   0, 100, 100);
        view.pieces.add(topLeft);

        Piece topRight = new Piece(Color.CYAN, polyShape, 90, 300, 100);
        view.pieces.add(topRight);

        Piece bottomRight = new Piece(Color.GREEN,  polyShape, 180, 300, 300);
        view.pieces.add(bottomRight);

        Piece bottomLeft = new Piece(Color.RED,  polyShape, 270, 100, 300);
        view.pieces.add(bottomLeft);

        Piece square = new Piece(Color.ORANGE, new Rectangle(200, 200), 0, 100, 100);
        view.pieces.add(square);

        frame.setVisible(true);
    }

}

class View extends JPanel {

    final List<Piece> pieces = new ArrayList<>();

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        Graphics2D gc = (Graphics2D) g;
        for (Piece piece : pieces) {
            piece.draw(gc);
        }

    }
}

class Piece {
    final Color color;
    final Shape shape;
    final int angle;

    int x;
    int y;

    Piece(Color color, Shape shape, int angle, int x, int y) {
        this.color = color;
        this.shape = shape;
        this.angle = angle;
        this.x = x;
        this.y = y;
    }

    void draw(Graphics2D gc) {
        AffineTransform tf = gc.getTransform();
        gc.translate(x, y);
        gc.rotate(Math.toRadians(angle));
        gc.setColor(color);
        gc.fill(shape);
        gc.setTransform(tf);
    }

    Shape getShape() {
    return shape;
    }
}

class MouseAdapterMod extends MouseAdapter {

    final View view;

    public MouseAdapterMod(View view) {
    this.view = view;
    }

    @Override
    public void mousePressed(MouseEvent e) {
    for(Piece piece : view.pieces) {
        if(piece.getShape().contains(e.getX(), e.getY())) {
        System.out.println("yes");
        }
    }
    }
}

Ответы [ 2 ]

1 голос
/ 06 марта 2019

Я вижу, что вы использовали мой ответ из этого вопроса в качестве основы вашей головоломки, вместо того, чтобы продолжать свой собственный код. Поймите, я дал вам минимальный, полный, проверяемый пример для рисования фигур на JPanel. Я никогда не говорил, что это подходит для непосредственного использования; в действительности, сделав пример «минимальным», это может привести к тому, что расширение кода для поддержки таких вещей, как тестирование попаданий, станет более трудным. Но так как вы решили продолжить с моим кодом в качестве основы ...

Ваша проблема с тестом на попадание связана с тем, что щелчки мыши находятся в системе координат представления, но фигуры переводятся и поворачиваются в различные другие позиции для рисования. Вы можете решить эту проблему, изменив преобразование, переведя положение мыши в систему координат фигуры, а затем используя Shape.contains(Point2D).

class Piece {

    // ... omitted for brevity ...

    public boolean hitTest(Point point) {
        AffineTransform tf = new AffineTransform();
        tf.translate(x, y);
        tf.rotate(Math.toRadians(angle));
        try {
            Point2D pnt = tf.inverseTransform(point, null);
            return shape.contains(pnt);
        } catch (NoninvertibleTransformException e) {
            return false;
        }
    }
}

Затем просто зациклите каждую часть и спросите, находится ли она под мышкой.

class View extends JPanel {

    // ... omitted for brevity ...

    Piece hitTest(MouseEvent e) {
        Point pnt = e.getPoint();
        for (Piece piece : pieces) {
            if (piece.hitTest(pnt))
                return piece;
        }
        return null;
    }
}

Обратите внимание, что я возвращаю Piece здесь, а не Shape. Поскольку 4 из 5 фигур используют одинаковую форму polyShape, это не очень полезно.

hitTest() можно сократить с помощью потоков Java8:

    Piece hitTest(MouseEvent e) {
        final Point pnt = e.getPoint();
        return pieces.stream()
                     .filter(piece -> piece.hitTest(pnt))
                     .findFirst()
                     .orElse(null);
    }

Если фигуры могут накладываться друг на друга, то последняя, ​​которая появляется сверху, является последней. findFirst() вернет самый нижний фрагмент, нарисованный в данной точке мыши, а не самый верхний. Следующее изменение исправит поведение:

    Piece hitTest(MouseEvent e) {
        final Point pnt = e.getPoint();
        return pieces.stream()
                     .filter(piece -> piece.hitTest(pnt))
                     .reduce((first, second) -> second)
                     .orElse(null);
    }
1 голос
/ 05 марта 2019

Итак, мне нужно найти способ добавить слушателя мыши, который возвращает игровой элемент, по которому щелкнули

Вы используете методы getX () и getY () изMouseEvent.

Затем вы перебираете свой ArrayList «кусков» и вызываете метод contains(... для Shape, содержащийся в каждом Piece, чтобы увидеть, содержится ли точка мыши в этом кусочке.

Таким образом, вам также нужно добавить метод getShape(...) к вашему классу "Piece", чтобы вы могли получить доступ к Shape каждого Piece.

Редактировать:

Итак, ваша базовая логика может выглядеть примерно так:

//Shape polyShape = new Polygon(SHAPE_X, SHAPE_Y, SHAPE_X.length);
//Piece topLeft = new Piece(Color.YELLOW, polyShape,   0, 100, 100);
Polygon topLeftPolygon = new Polygon(SHAPE_X, SHAPE_Y, SHAPE_X.length);
topLeftPolygon.translate(100, 100);
//topLeftPolygon = ShapeUtils.rotate(...); // do rotation when required
Piece topLeft = new Piece(Color.YELLOW, topLeftPolygon);

Тогда код рисования в методе draw (..) просто:

gc.setColor(color);
gc.fill(shape);

Нет необходимости в преобразовании илиthe translate.

Edit 2:

Так что используйте Shape:

//topLeftPolygon = ShapeUtils.rotate(...); // do rotation when required
//Piece topLeft = new Piece(Color.YELLOW, topLeftPolygon);
Shape topLeftShape = ShapeUtils.rotate(...); // do rotation when required
Piece topLeft = new Piece(Color.YELLOW, topLeftShape);

Это в настоящее время соответствует вашему классу Piece, который все равно ожидает объект Shape.Пожалуйста, подумайте о предлагаемой концепции и не думайте, что размещенный код идеален, поскольку он явно не был протестирован.

...