-1

I am working on a project, develop a game called Don't get mad bro.

I have a JPanel with shapes (circles) draw on it and JLabel components that contains images.I need that whenever I click "Throw dice" (which in background return a number between 1 and 6) I should wait for current player to click on one of his pawns, and that pawn should move after n positions, where n is equal with number that dice returned.

My question is, should I create a new thread in which I wait for mouseClick event? And how to get coordinates of mouseClick?

Here is my class that inherits panel and draw circles and add labels.

public class ImagePanel extends JPanel{

private static final long serialVersionUID = 1L;
ImageMatrix imageMatrix;
BufferedImage[] images;
public static JLabel[][] labels;
DrawGameBoard board = new DrawGameBoard();
List<GameFigure> gameCircles;
List<FinishFigure> finishCircles;
int initialHeight = 528;
int initialWidth = 596;
ThreadForPawnsClick labelsClick;

public ImagePanel(){
    labels = new JLabel[4][4];
    images = new BufferedImage[4];
    setBackground(new Color(255,255,153));
    gameCircles = new ArrayList<GameFigure>();
    finishCircles = new ArrayList<FinishFigure>();
    imageMatrix = new ImageMatrix(initialWidth,initialHeight);

    try {
        images[0] = ImageIO.read(new File("C:\\Users\\babii\\.eclipse\\DontGetMad\\resource\\red.png"));
        images[1] = ImageIO.read(new File("C:\\Users\\babii\\.eclipse\\DontGetMad\\resource\\green.png"));
        images[2] = ImageIO.read(new File("C:\\Users\\babii\\.eclipse\\DontGetMad\\resource\\blue.png"));
        images[3] = ImageIO.read(new File("C:\\Users\\babii\\.eclipse\\DontGetMad\\resource\\yellow.png"));
    } catch (IOException e) {
        e.printStackTrace();
    }
    for(int i=0;i<4;i++)
    {
        for(int j=0;j<4;j++)
        labels[i][j] = new JLabel(new ImageIcon(images[i]));
    }
    setLayout(null);
    board.DrawHomeBoard(imageMatrix, labels);
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
            add(labels[i][j]);
}

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

    int width = this.getWidth();
    int height = this.getHeight();
    imageMatrix.update(width, height);

    setLayout(null);
    gameCircles = board.DrawMainBoard(g, imageMatrix);
    //labels = board.DrawHomeBoard(g, imageMatrix, labels);
    //board.DrawHomeBoard(imageMatrix, labels);
    finishCircles = board.DrawFinishBoard(g, imageMatrix);
    /*for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
            add(labels[i][j]);
    */
}
}

Also, why my imageMatrix doesn't extend on whole screen, even if I call update matrix in paintComponent()?

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
  • 1
    1) For better help sooner, post a [MCVE] or [Short, Self Contained, Correct Example](http://www.sscce.org/). 2) One way to get image(s) for an example is to hot link to images seen in [this Q&A](http://stackoverflow.com/q/19209650/418556). 3) Application resources will become embedded resources by the time of deployment, so it is wise to start accessing them as if they were, right now. An [tag:embedded-resource] must be accessed by URL rather than file. See the [info. page for embedded resource](http://stackoverflow.com/tags/embedded-resource/info) for how to form the URL. .. – Andrew Thompson Jun 17 '18 at 14:53
  • .. 4) If the loading of the images fails, so will adding the images to labels. Put that loop inside the `try`. 5) `setLayout(null);` This is not something that is necessary when custom painting, and the paint methods should not update the component in any way, as that is likely to trigger a `repaint()` 6) Please learn common Java nomenclature (naming conventions - e.g. `EachWordUpperCaseClass`, `firstWordLowerCaseMethod()`, `firstWordLowerCaseAttribute` unless it is an `UPPER_CASE_CONSTANT`) and use it consistently. – Andrew Thompson Jun 17 '18 at 14:56
  • Please see edits to answer and ask if anything is confusing. – Hovercraft Full Of Eels Jun 18 '18 at 22:49

1 Answers1

1

My question is, should I create a new thread in which I wait for mouseClick event?

No, absolutely not. You need instead to change the state of the GUI somehow to wait-for-mouse-click mode, and then alter the behavior of the GUI's response to mouse clicks depending on its state. Usually state is represented by instance fields of the class. So when you need to wait, you change one of these state fields, and on mouse click, you check the state of the field and vary what happens depending on that. For instance in a turn based game of chess, one state field could be private boolean blackTurn, and then base what mouse does based on its state.

And how to get coordinates of mouseClick?

In the MouseListener the MouseEvent parameter gives you the x and y position of the mouse relative to the listened to component and to the screen. If your MouseListener is attached to the JLabels, then you can get a reference to the clicked JLabel via the MouseEvent's getSource() method, and then can get the location of the JLabel relative to its container JPanel (if needed) by calling getLocation() on it.

Side note: in a Swing GUI where you're moving around sprites, it's usually better not to put the sprites into JLabels but rather to simply draw them directly in the paintComponent method of a drawing JPanel.


As an example of what I mean, here is a program that draws 4 colored circles, circles that are draggable, but only draggable when the corresponding JRadioButton has been selected with the JRadioButton setting the "state" of the GUI. Here the state is represented by an enum called ColorState that holds 4 colors and corresponding text. Here is this enum:

import java.awt.Color;

public enum ColorState {
    RED("Red", Color.RED), 
    GREEN("Green", Color.GREEN), 
    BLUE("Blue", Color.BLUE), 
    ORANGE("Orange", Color.ORANGE);

    private String text;
    private Color color;

    private ColorState(String text, Color color) {
        this.text = text;
        this.color = color;
    }

    public String getText() {
        return text;
    }

    public Color getColor() {
        return color;
    }
}

Then we create a drawing JPanel, one that holds four Ellipse2D Shape objects in a Map,

private Map<ColorState, Shape> colorStateMap = new EnumMap<>(ColorState.class);

Within a for loop, we create the JRadioButtons, give them ActionListeners that set the object's state, and populate the Map with Ellipse2D Shape objects

for (final ColorState state : ColorState.values()) {
    // create the JRadioButton
    JRadioButton radioButton = new JRadioButton(state.getText());
    add(radioButton); // add to GUI
    buttonGroup.add(radioButton); // add to ButtonGroup

    // give it an ActionListener that changes the object's state
    radioButton.addActionListener(e -> {
        colorState = state;
    });

    // create a randomly placed Ellipse2D and place into Map:
    double x = Math.random() * (W - CIRCLE_WIDTH);
    double y = Math.random() * (H - CIRCLE_WIDTH);
    Ellipse2D ellipse = new Ellipse2D.Double(x, y, CIRCLE_WIDTH, CIRCLE_WIDTH);
    colorStateMap.put(state, ellipse);
}

We draw the ellipses within paintComponent:

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

    // make for smooth graphics
    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    // iterate through the enum, extracting the ellipse and drawing it
    for (ColorState state : ColorState.values()) {
        Shape shape = colorStateMap.get(state);
        if (shape != null) {
            g2.setColor(state.getColor());
            g2.fill(shape); // draw the ellipse
        }
    }
}   

Finally in a MouseAdapter (both MouseListener and MouseMotionListener), we listen for mouse presses and register success if the left mouse is clicked and if it is clicked within the appropriate Shape:

private class MyMouse extends MouseAdapter {
    private Shape selectedShape = null;
    private Point2D offset = null;

    @Override
    public void mousePressed(MouseEvent e) {
        // check that correct button pressed
        if (e.getButton() != MouseEvent.BUTTON1) {
            return;
        }

        // has our colorState been set yet? If not, exit
        if (colorState == null) {
            return;
        }

        // is an appropriate Shape held by the Map? If so, get it
        Shape shape = colorStateMap.get(colorState);
        if (shape == null) {
            return;
        }

        // does this shape contain the point where the mouse was pressed?
        if (!shape.contains(e.getPoint())) {
            return;
        }

        // Get the selected shape, get the mouse point location relative to this shape
        selectedShape = shape;
        double x = e.getX() - shape.getBounds2D().getX();
        double y = e.getY() - shape.getBounds2D().getY();
        offset = new Point2D.Double(x, y);
    }

    @Override
    public void mouseDragged(MouseEvent e) {
        // drag shape to new location
        if (selectedShape != null) {
            double x = e.getX() - offset.getX();
            double y = e.getY() - offset.getY();

            Rectangle2D bounds = selectedShape.getBounds2D();
            bounds.setFrame(new Rectangle2D.Double(x, y, bounds.getWidth(), bounds.getHeight()));

            ((Ellipse2D) selectedShape).setFrame(bounds);
            repaint();
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        selectedShape = null;
    }
}   

Note that the mouse dragging code is thanks to MadProgrammer's answer here. Please up-vote this answer.

The entire class looks like so:

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Point2D;
import java.awt.geom.Rectangle2D;
import java.util.EnumMap;
import java.util.Map;
import javax.swing.*;

@SuppressWarnings("serial")
public class StateDependentMouseListener extends JPanel {
    private static final int W = 800;
    private static final int H = 650;
    private static final double CIRCLE_WIDTH = 60.0;
    private ButtonGroup buttonGroup = new ButtonGroup();
    private ColorState colorState = null;
    private Map<ColorState, Shape> colorStateMap = new EnumMap<>(ColorState.class);

    public StateDependentMouseListener() {
        setPreferredSize(new Dimension(W, H));
        for (final ColorState state : ColorState.values()) {
            // create the JRadioButton
            JRadioButton radioButton = new JRadioButton(state.getText());
            add(radioButton); // add to GUI
            buttonGroup.add(radioButton); // add to ButtonGroup

            // give it an ActionListener that changes the object's state
            radioButton.addActionListener(e -> {
                colorState = state;
            });

            // create a randomly placed Ellipse2D and place into Map:
            double x = Math.random() * (W - CIRCLE_WIDTH);
            double y = Math.random() * (H - CIRCLE_WIDTH);
            Ellipse2D ellipse = new Ellipse2D.Double(x, y, CIRCLE_WIDTH, CIRCLE_WIDTH);
            colorStateMap.put(state, ellipse);
        }

        MyMouse myMouse = new MyMouse();
        addMouseListener(myMouse);
        addMouseMotionListener(myMouse);
    }

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

        // make for smooth graphics
        Graphics2D g2 = (Graphics2D) g;
        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

        // iterate through the enum, extracting the ellipse and drawing it
        for (ColorState state : ColorState.values()) {
            Shape shape = colorStateMap.get(state);
            if (shape != null) {
                g2.setColor(state.getColor());
                g2.fill(shape); // draw the ellipse
            }
        }
    }   

    private class MyMouse extends MouseAdapter {
        private Shape selectedShape = null;
        private Point2D offset = null;

        @Override
        public void mousePressed(MouseEvent e) {
            // check that correct button pressed
            if (e.getButton() != MouseEvent.BUTTON1) {
                return;
            }

            // has our colorState been set yet? If not, exit
            if (colorState == null) {
                return;
            }

            // is an appropriate Shape held by the Map? If so, get it
            Shape shape = colorStateMap.get(colorState);
            if (shape == null) {
                return;
            }

            // does this shape contain the point where the mouse was pressed?
            if (!shape.contains(e.getPoint())) {
                return;
            }

            // Get the selected shape, get the mouse point location relative to this shape
            selectedShape = shape;
            double x = e.getX() - shape.getBounds2D().getX();
            double y = e.getY() - shape.getBounds2D().getY();
            offset = new Point2D.Double(x, y);
        }

        @Override
        public void mouseDragged(MouseEvent e) {
            // drag shape to new location
            if (selectedShape != null) {
                double x = e.getX() - offset.getX();
                double y = e.getY() - offset.getY();

                Rectangle2D bounds = selectedShape.getBounds2D();
                bounds.setFrame(new Rectangle2D.Double(x, y, bounds.getWidth(), bounds.getHeight()));

                ((Ellipse2D) selectedShape).setFrame(bounds);
                repaint();
            }
        }

        @Override
        public void mouseReleased(MouseEvent e) {
            selectedShape = null;
        }
    }   

    private static void createAndShowGui() {
        StateDependentMouseListener mainPanel = new StateDependentMouseListener();

        JFrame frame = new JFrame("StateDependentMouseListener");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(mainPanel);
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> createAndShowGui());
    }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373