Trouble Using MouseMotionListener - java

I just started coding just a while back. I'm trying to make a FruitNinja type game right now using a JPanel and I've pretty much done with everything(with the exception of the loops that make the game go on and the rest of the fruit/bomb animations)
So far, I've only animated the Apple.png (will get to animating other fruits once I'm done with this)
I'm trying to make a checkHit method that checks whether or not my Mouse goes over the image(slicing through the fruit), thus the MouseMotionListener that needs to be used. If the mouse does go over the fruit, I need it to disappear/move off the frame.
So how do I retrieve the coordinates from MouseMotionListener, check to see if it is within 40 pixels of my fruit and if it is, to move that fruit of the frame? If possible, not only to do that but to also play a sound when that is done.
I've got another user to help me out with this issue but I still can't quite figure it out.
import javax.swing.*;//imports JPanel class
import java.awt.*;//imports the Graphics class
import java.awt.event.*;
import java.awt.event.MouseMotionListener;
import java.awt.event.MouseEvent;
import java.awt.event.ActionListener;
//imports packages needed for the hovering
public class FruitNinja extends JPanel{
private Image dojo;
private Image apple;
private Image orange;
private Image pear;
private Image strawberry;
private Image banana;
private Image bomb;
//declares the import image variables
private javax.swing.Timer timer;
private int dx, dy;
private int vx =40;
//velocity of the object moving in the x direction
private int x=-10;
private int vy=40;
//velocity of the object moving in the y direction
private int y=770;
private int divide=(int)(2*Math.random())+1;//sets random number
//determines when the fruit will bounce off
public FruitNinja() { // a constructor to set up graphics windo
super();
setBackground(Color.WHITE);
loadImage();
dx = 25;
dy = 25;
timer = new javax.swing.Timer( 30, new TimerListener() );
//interval of 10 milliseconds
timer.start();
//timer is a facility for threads to schedule tasks for future execution in a background thread.
}
private void loadImage() {
ImageIcon ii = new ImageIcon("Dojo.jpg");
dojo = ii.getImage();
ImageIcon oo = new ImageIcon("Orange.ico");
orange = oo.getImage();
ImageIcon ss = new ImageIcon("Strawberry.png");
strawberry = ss.getImage();
ImageIcon bb = new ImageIcon("Banana.png");
banana = bb.getImage();
ImageIcon pp = new ImageIcon("Pear.png");
pear = pp.getImage();
ImageIcon aa = new ImageIcon("Apple.png");
apple = aa.getImage();
ImageIcon bo=new ImageIcon("Bomb.png");
bomb=bo.getImage();
//loads neccaseary images for this game
}#Override
public void paintComponent(Graphics g){ // draw graphics in the panel
super.paintComponent(g);// to make panel display correctly
g.drawImage(dojo, 0,0, this);
//draws out dojo
g.drawImage(apple, x,y, this);
g.drawImage(orange, -300,-300, this);
g.drawImage(pear, -300,-300, this);
g.drawImage(banana, -300,-300, this);
g.drawImage(strawberry, -300,-300, this);
//draws out the fruits somewhere
g.drawImage(bomb,-300,-300,this);
//draws out the bomb that will make the player lose
}
private class TimerListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
//implements the ActionListenter
x+=vx; //adds velocity to the x, which makes it travel in x direction
if (x<0){
vx=(-1*vx);
//tells the velocity to change direction
}
y+=vy; //adds velocity to the y, which makes it travel in y direction
if (y>=getHeight()||y<=getHeight()/4){
vy=(-1*vy);
//tells the velocity to change direction
}
repaint(); // causes paintComponent to be called by the JVM
}
}
public static void main(String[] args) {
FruitNinja panel = new FruitNinja(); // window for drawing
JFrame f = new JFrame(); // the program itself
f.setTitle("Fruit Ninja");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//when the X button is clicked, the program quits
f.setSize(1280,800);//size of the frame
Container pane = f.getContentPane();//pane refers to the interior of the JFrame
FruitNinja p1 = new FruitNinja();
pane.add(p1);//add the FacePanel object to the interior of the frame
f.setVisible(true);
}
}
Please let me know if I'm doing anything wrong with what I have here or/and how I can use this MouseMotionListner inside it. I'm still quite new to this, so I don't know how to retrieve the coordinates or set up the 'MouseMotionListener'. If my question is unclear, feel free to go into the comments and let me know if that is the case; I'm willing to explain the issue more thoroughly.
Thanks
Edit:
Is this the method?
private class HandleMouse extends MouseAdapter {
//extends MouseAdapter rather than implement Mouse Adapter
public void mousePressed( MouseEvent e ){
Rectangle hitBox = new Rectangle(e.getX() - 20, e.getY() - 20, 40, 40);
Rectangle appleHitBox=new Rectangle(ax-128,ay-128,256,256);
Area area = new Area(hitBox);
area.intersect(new Area(appleHitBox));
if(!area.isEmpty()){
ax=-500;
ay=-500;
avx=0;
avy=0;
}
else{
numOfMisses++;
}
}
}

So how do I retrieve the coordinates from MouseMotionListener,
MouseMotionListener passes a MouseEvent to the method, which contains the various properties of the event, this includes the coordinates of the event in the component coordinate context
check to see if it is within 40 pixels of my fruit and if it is
So, this is basic collision detection, there is a number of possible ways you might approach this, but because I'm lazy, I might consider using Rectangle to represent the user hit box
Rectangle hitBox = new Rectangle(e.getX() - 20, e.getY() - 20, 40, 40);
This generates a box 20 pixels around the center point of the MouseEvent.
"But why?" you ask? Because Rectangle has a number of helpful methods which can be used for collision detection including
intersection
intersects
union
to name a few
So given the x/y position and size of the fruit, you can simply create a second Rectangle and determine if the first hits the second
and if it is, to move that fruit off the frame?
Well, this would be a process of setting up a flag, which the "main loop" (ie your TimerListener) that tells it that the fruit has been hit, it's now up to the "main loop" to remove it from the "paint" list and setup the next object
If possible, not only to do that but to also play a sound when that is done
As a general answer, is. Once you been able to detect that a collision has occured, playing a sound is relatively simple, I'd be tempted, again, to use the "main loop" to do this as well, when it detects that a hit has occured

Related

Only One Thread Paints in my JFrame object, why not the other? [duplicate]

This question already has answers here:
Why does the first panel added to a frame disappear?
(2 answers)
Closed 5 years ago.
I've been trying all day long to make this happen with no success. What can be going wrong?
I want 2 threads printing simultaneously in my JFrame:
Thread-1: Prints Squares
Thread-2: Prints Circles
I'am ending up with only one thread printing on the JFrame. The other get executed but don't print in the JFrame.
Look, only squares are getting printed:
This is my main class:
public class Main {
public static void main(String[] args) {
FigurePlacer circle = new FigurePlacer("circle");
FigurePlacer square = new FigurePlacer("square");
JFrame window = new JFrame();
window.add(circle);
window.add(square);
window.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
window.setTitle("Task");
window.setSize(700, 700);
window.setLocationRelativeTo(null);
window.setVisible(true);
}
}
This is the Threading Class:
import java.awt.Graphics;
import javax.swing.JPanel;
import java.awt.Color;
import java.util.Random;
public class FigurePlacer extends JPanel implements Runnable{
String figure;
final int width = 700;
final int height = 700;
int x_pos = 0;
int y_pos = 0;
int x_width = 50;
int y_height = 50;
public FigurePlacer(String str){
figure = str;
randomCoord();
Thread th = new Thread (this);
th.start();
}
private void randomCoord(){ //this ramdomize x,y coord to place a new object
Random random = new Random();
x_pos = random.nextInt(width);
y_pos = random.nextInt(height);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.BLACK); //sets the black color in background
g.fillRect(0, 0, 700, 700);
System.out.println(figure);
switch (figure){
case "square":
g.setColor(Color.GREEN);
g.fillRect(x_pos, y_pos, x_width, y_height);
break;
case "circle":
g.setColor(Color.BLUE);
g.fillOval(x_pos, y_pos, x_width, y_height);
break;
}
}
#Override
public void run(){ //paints the objects
while (true){
randomCoord();
paintImmediately(x_pos, y_pos, x_width, y_height);
try{
Thread.sleep (50);
}
catch (InterruptedException ex){}
}
}
}
JFrame window = new JFrame();
window.add(circle);
window.add(square);
The default layout manager for a JFrame is the BorderLayout. When you add a component to a panel using the BorderLayout and don't specify a constraint then the component goes to the CENTER. However only one component can ever be displayed in the CENTER, so only the last component added is painted.
You could use the OverlayLayout, which allows you to stack two panels on top of one another. Of course you will need to make the top panel non-opaque.
The easier solution is to not attempt to use two panels, just create on panel that can display circles or squares.
Also, your painting code is wrong. You should not be using paintImmediately(...) to do painting. The paintComponent() method should paint every object every time the method is invoked. Try resizing your frame and you will see that all your object disappear since the paintComponent() method will clear all the old paintings.
See Custom Painting Approaches for the two common approaches for this kind of painting.

How to make Round JButtons in Java

First, I am a Web Developer and a novice Java programmer.
My boss is asking me to make this button in an application:
My custom button class must extend JButton or BasicButtonUI so that it can be reused.
I did some research on Stack Overflow, but I did not understand the answers, especially with the time restraints from my boss.
You should create your own component for this.
Override the paintComponent method on a JPanel, and inside the paintComponent method draw (ie fill) a rounded rectangle2D in the color gray :
RoundRectangle2D roundedRectangle = new RoundRectangle2D.Float(x, y, w, h, 10, 10);
g.fill(roundedRectangle);
(The last two values determine the curvature. Play around until you get what you want)
Now move the x,y and reduce width and height so that when you draw the next rectangle, it sits inside the gray rectangle. Set the graphics color to blue then do something like this :
RoundRectangle2D roundedRectangle2 = new RoundRectangle2D.Float(x + 5, y + 5, w - 10, h - 10, 10, 10);
g.fill(roundedRectangle2);
You will also need to add text. Adding text requires an x and y position. The exact x and y position can be tricky to calculate, so you may need to use FontMetrics to get some more information about the rectanglar shape of the string. Fontmetrics has methods like stringWidth() and getHeight() which will help you determine what your x and y should be.
g.drawString("Click Me", x, y);
Finally you need to have a mouse motion listener on your panel. The listener needs to find when the mouse is over the button and then redraw the component.
Your rectangle can be cast to a shape object, and a calculation can be made as to whether the mouse is in the shape. Eg :
shape.contains(x,y)
If it contains, change the color, then call repaint() or updateUI() on the panel.
Note: your color object should be kept as a class level field in the class, so that it can be changed via the mouseover.
Hope this helps!
If you don't want to draw the images by yourself using the graphics API or you can't becaue the images come from a graphic designer, than you can use them as ImageIcon objects and use setRolloverIcon() and setIcon().
In this case I would do it this way
class ButtonRollover {
private String normalImagePath;
private String rolloverImagePath;
public ButtonRollover(String normalImagePath, String rolloverImagePath) {
this.normalImagePath = normalImagePath;
this.rolloverImagePath = rolloverImagePath;
}
public void apply(AbstractButton abstractButton) {
abstractButton.setBorderPainted(false);
abstractButton.setBackground(new Color(0, 0, 0, 0));
abstractButton.setRolloverIcon(createImageIcon(rolloverImagePath));
abstractButton.setIcon(createImageIcon(normalImagePath));
}
private ImageIcon createImageIcon(String path) {
java.net.URL imgURL = getClass().getResource(path);
if (imgURL != null) {
return new ImageIcon(imgURL);
} else {
System.err.println("Couldn't find file: " + path);
return null;
}
}
}
and than use it. E.g.
public class Main extends JFrame {
public static void main(String[] args) {
Main main = new Main();
main.setBackground(Color.WHITE);
main.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
main.setSize(640, 480);
Container contentPane = main.getContentPane();
ButtonRollover buttonRollover = new ButtonRollover("/bt_normal.png",
"/bt_hover.png");
JButton btn = new JButton();
buttonRollover.apply(btn);
contentPane.add(btn);
main.setVisible(true);
}
}
Just put the image files in the classpath.
There are ways to do it.
1) JButton has inbuilt API setIcon. You could set ImageIcon here.
2) You could add mouse listener (Mouse entered, Mouse exited) change the icons to the needed ones.
3) Make a button round - Refer for creating the curvy buttons.
public class Main extends JFrame {
public static void main(String[] args) {
Main main = new Main();
main.setBackground(Color.WHITE);
main.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
main.setSize(640, 480);
Container contentPane = main.getContentPane();
ButtonRollover buttonRollover = new ButtonRollover("/bt_normal.png",
"/bt_hover.png");
JButton btn = new JButton();
buttonRollover.apply(btn);
contentPane.add(btn);
main.setVisible(true);
}
}

Understanding paintComponent

UPDATE 19/01/14(for people who has issues like this one)
The problem I described under originated from the fact that my circle class extends JPanel. So every circle I create from this class is in fact its own panel. Therefore by adding a layout I could see both circles. I've learned now that its Wiser to have a separate "board class" that extends JPanel, and the let the circles, in this case, extend nothing. That way I can implement a drawMySelf method in the circleclass and draw them in my board. This way I can have various geometric objects in the same panel!
UPDATE END.
I'm doing a task where I need to draw two circles. These circles are supposed to relocate randomly when I resize my frame. And needs to have a line between their centers which states the distance. I'm getting trouble with my class for the circles. When I add my custom circles to my testprogram, only one of them appears. I can't figure out why. I think there's an error in my code making the program skip some of it. because I only get one circle to appear. Can anyone see what is wrong with this code?
Keep in mind I'm supposed to use the tools I have learned so far. JPanel, JFrame, Overriding paintComponent().
The circle Class:
package oppgave4;
import javax.swing.*;
import java.awt.*;
public class Circle extends JPanel {
public static final int OVAL = 1;
public static final int ANOTHEROVAL = 2;
public int OVALCENTER = 0;
public int ANOTHEROVALCENTER = 0;
private int type = 1;
private boolean filled = false;
public Circle(){
}
public Circle(int type){
this.type = type;
}
public Circle(int type, boolean filled){
this.type = type;
this.filled = filled;
}
protected void paintComponent(Graphics g){
super.paintComponent(g);
int width = getWidth();
int height = getHeight();
int randomWidth = (int)(width * Math.random());
int randomHeight = (int)(height * Math.random());
switch (type){
case OVAL:
g.setColor(Color.BLUE);
if(filled)
g.fillOval(randomWidth, randomHeight, 30, 30);
else
g.drawOval(randomWidth, randomHeight, 30, 30);
case ANOTHEROVAL:
g.setColor(Color.RED);
if(filled)
g.fillOval(randomWidth, randomHeight, 30, 30);
else
g.drawOval(randomWidth, randomHeight, 30, 30);
break;
}
}
}
And the test program: When I run this, only the red circle will appear.
package oppgave4;
import javax.swing.*;
import java.awt.*;
public class TestProgram extends JFrame {
public TestProgram(){
add(new Circle(Circle.OVAL));
add(new Circle(Circle.ANOTHEROVAL));
}
public static void main(String[] args) {
TestProgram sirkel = new TestProgram();
sirkel.setSize(400, 300);
sirkel.setLocationRelativeTo(null);
sirkel.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
sirkel.setVisible(true);
}
}
Try adding them with a layout manager besides the default BorderLayout and see what happens
import java.awt.*;
public TestProgram(){
setLayout(new GridLayout(1, 2);
add(new Circle(Circle.OVAL));
add(new Circle(Circle.ANOTHEROVAL));
}
Another solution would just be to use the default BorderLayout of the JFrame. When you just .add(something), it will get added automatically to the BorderLayout.CENTER, unless you specify the position. A BorderLayout and only hold one component in each position. So when you try and add a second one, Only the second one will appear in the CENTER position.
If you did
public TestProgram(){
setLayout(new GridLayout(1, 2);
add(new Circle(Circle.OVAL), BorderLayout.CENTER);
add(new Circle(Circle.ANOTHEROVAL), BorderLayout.SOUTH);
}
it would also work
First off, by making each Circle a JPanel, you are going to have unexpected results because two JPanels cannot draw to the same place. Rather, they are placed my the LayoutManager. In this case, I would imagine that one of your panels is on top of the other, so you're only seeing one.
If you want the circles to be in the same "panel" (they can overlap) then you will need one JPanel which can draw multiple circles.
If you want them to be "side-by-side" in separate panels, I'd look at GridLayout

How can I react on Mouse events in a Java applet and then paint accordingly?

My homework is
Write an applet that draw the house shown on the left in Figure 14-32. When the user clicks on the door or windows, they should close. The figure on the right shows the house with its door and windows closed.
I basically want a Java Applet where, if a user clicks on a rectangle, another one is sudden created and drawn.
Here is my code so far.
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class test2 extends JApplet
{
private final int currentX = 0;
public void init()
{
addMouseListener(new MyMouseListener());
}
public void paint (final Graphics g)
{
super.paint (g);
g.drawRect(100, 100, 200, 200);
}
private class MyMouseListener extends MouseAdapter
{
currentX = e.getX();
}
}
Take a look at the Java Tutorial | How to Write a Mouse Listener. It will help you determine when and where a user clicks. Once you have these (x,y) coordinates you can check if they lie within the window or the door and if so, draw something else.
Sample code:
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
//check if (x,y) lie in a certain rectangle
if(x>100 && x<300 && y>100 && y<300){
//set a variable and repaint
closeDoors = true;
repaint();
}
}
In your paint method, you need to check if the closeDoors variable is set and if so, draw something else.
public void paint (final Graphics g){
super.paint (g);
g.drawRect(100, 100, 200, 200);
if(closeDoors){
g.fillRect(100, 100, 200, 200);
}
}
When the user clicks on the door or windows, then you check if the mouse coordinates are inside the window or door area and, if yes, you replace the drawing of an open door or open window by a drawing of a closed one, which then will look like: they should close.
So, that's what you have to do:
the "house" model consists of a building, a door and a window, each represented by coordinates
"door" and "window" can be painted either in "open" or "close" mode
You need test method to check, if a mouse click occured "on" the windoww or "on" the door
Tip: your current implementation of MouseListener doesn't work at all. You have to override methods from MouseAdapter and put your test in the appropriate method.

Slide JPanel Content in a JForm on Java

I have a question. I want to make a swing form that, when clicking in a button he slides a panel (with his content) to the left so the panel on the right replaces it with a smooth effect.
I Have tried to do a while how checks the size of the panel and then minimize it and shows the next one like this :
while (jpanelprincipal1.getWidth() < 439 || jpanelprincipal1.getHeight() > 250)
{
int panel1width = jpanelprincipal1.getWidth();
int panel2height = jpanelprincipal1.getHeight();
jpanelprincipal1.setSize(panel1width -- , panel2height --);
jpanelprincipal2.setSize(440,250);
}
I used this trick in C# but with the Application.DoEvent(); (how obviously it's not available on java).
Is there anyway i can make a slide effect of 2 or more panels?
BTW : Sorry for my very bad english !
Thanks In Advance,
Luis Da Costa
he slides a panel (with his content) to the left so the panel on the right replaces it with a smooth effect
You question mentions you want the panel to "slide", but the code looks like you are trying to get the panel to "shrink", so it is replaced by another panel.
Assuming you have two panels each with the same size, then you can "slide" one out of view while the other slides into view.
To do this you an use a panel with a GridLayout. This way each component will be the same size. Then you add the panel to a scrollpane without any scrollbars. The size of the scrollpane will need to be set to the size of the first compnoent. Then you can "slide" the two panels by changing the position of the viewport. So in your Timer you would have code something like:
JViewport viewport = scrollPane.getViewport();
Point position = viewport.getViewPosition();
position.x += 5;
viewport.setViewPosition( position );
You would then stop the Timer when the position is greater than the size of the component.
As suggested by #HFOE, javax.swing.Timer is a good choice for animation. The setDividerLocation() method of JSplitPane can be called from the ActionListener. See How to Use Split Panes for additional options.
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
/** #see http://stackoverflow.com/questions/5069152 */
public class SplitPaneTest {
double ratio = 0.5;
double delta = ratio / 10;
private void create() {
JFrame f = new JFrame("JSplitPane");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
MyPanel p1 = new MyPanel(Color.red);
MyPanel p2 = new MyPanel(Color.blue);
final JSplitPane jsp = new JSplitPane(
JSplitPane.HORIZONTAL_SPLIT, true, p1, p2);
Timer timer = new Timer(200, new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
ratio += delta;
if (ratio >= 1.0) {
ratio = 1.0;
delta = -delta;
} else if (ratio <= 0) {
delta = -delta;
ratio = 0;
}
jsp.setDividerLocation(ratio);
}
});
f.add(jsp);
f.pack();
f.setLocationRelativeTo(null);
f.setVisible(true);
timer.start();
}
private static class MyPanel extends JPanel {
Color color;
public MyPanel(Color color) {
this.color = color;
this.setPreferredSize(new Dimension(300, 300));
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(color);
g.drawLine(0, 0, getWidth(), getHeight());
g.drawLine(getWidth(), 0, 0, getHeight());
}
}
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
new SplitPaneTest().create();
}
});
}
}
I would probably do this with a Swing Timer. Change a class field representing the x, y position of the sliding JPanel in the timer's ActionListener and then call repaint on the container holding the JPanels. A JLayeredPane could work well as the container for the sliding JPanels.
Edit 1: regarding your request for code, I think the best thing is for you to try to create a very small compilable runnable program that attempts to do this, and then post your code with an explanation of your program's behavior as an edit to your original post. Also send us a comment to notify us of your changes. Then we can inspect your code, test it, modify it, and help you mold it into a working program. This is called creating a "Short, Self Contained, Correct (Compilable), Example" or SSCCE (please check the link).

Categories