snowy500 snowy500 - 5 months ago 20
Java Question

Java 2D Game - MouseClicked & MouseMoved methods

Problem

I have two MouseEvent handlers (mouseClicked and mouseMoved), and they both work, but only separately.

If I click the mouse, the action gets processed fine. (bullet gets fired)

If I move the mouse, the action gets processed fine. (the sprite moves)

The problem occurs when I do both actions at the same time (moving mouse whilst clicking). The mouseMoved event goes through fine, but the mouseClicked event doesn't get called.

The below code is in my Game class constructor, which is extending JPanel.

this.addMouseListener(new MouseAdapter(){
@Override
public void mouseClicked(MouseEvent e){
//This creates a new bullet, and adds to an array to get drawn.
bullet = new Bullet(105, e.getY()+5, bulletTexture);
bulletsOnScreen.add(bullet);
e.consume();
}
});



this.addMouseMotionListener(new MouseAdapter(){
@Override
public void mouseMoved(MouseEvent e){
//This increments the sprites position on the screen.
player.setYPosition(e.getY()-50);
e.consume();
};
});


What I've tried

I have tried using SwingWorker objects to run the mouseMoved in a background thread, but the results are the same (bullet doesn't fire).

@Override
public void mouseMoved(MouseEvent e){

SwingWorker myWorker = new SwingWorker<Void, Void>(){

@Override
protected Void doInBackground() throws Exception {
player.setYPosition(e.getY()-50);
e.consume();

return null;
}

};

myWorker.execute();
};


I have also tried to check for a mouseClick within the mouseMoved method, again to no success.

public void mouseMoved(MouseEvent e){
if(e.getButton() == MouseEvent.MOUSE_CLICKED){
//Create bullet and add to array (but this never gets called)
}

player.setYPosition(e.getY()-50);
e.consume();
};


If anyone has any ideas or pointers, it would be great thanks.

Answer

Here's some code I cooked to have full working example of behavior you described.

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

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

public class Main {

    public static void main(String[] args) {
        JFrame frame = new JFrame();
        frame.addMouseListener(new MouseAdapter() {
            @Override
            public void mousePressed(MouseEvent e) {
                System.out.println("Pressed");
            }

            @Override
            public void mouseClicked(MouseEvent e) {
                System.exit(1);
            }
        });


        frame.addMouseMotionListener(new MouseAdapter() {
            @Override
            public void mouseMoved(MouseEvent e) {
                System.out.println("Moved");
            }
        });

        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setSize(100, 100);
                frame.setVisible(true);
            }
        });

    }
}

As you will see when moving around frame you will get lots of "Moved" events.
Most interesting for you will be part that when you press mouse button down you will see "Pressed". If you release without moving there will be clicked event ( app will exit ). Closing app might be a bit extreme but we have to be sure that we don't miss that event.
But when you press down mouse button, hold it and move, you won't see any move event triggered. Then, when you release, you won't get clicked event fired either.

I'm not sure about this part but it looks like mouseClicked will be triggered only if mousePressed and mouseReleased event occur one after another.

In your game, when you click and move your mouse at the same time you basically do

mousePressed -> mouseMoved -> mouseReleased

but this doesn't fire mouseClicked as a result.

My advice on that would be that you handle mousePressed instead of mouseClicked or try to adapt MouseAdapter#mouseDragged method to your needs.