Reputation: 39
Im working on an assignment where an image moves around and when the user clicks on the image it will change and as soon as it moves again via timer class, the images chages back to the original. As of now I can click the image to change it, but it wont change back when it is time to move again. Is there a way to change back after it moves?
Here is my code
Main:
import java.awt.*;
import javax.swing.*;
public class Catch_The_Creature
{
public static void main(String[] args)
{
JFrame frame = new JFrame("Catch the Creature");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JOptionPane.showMessageDialog(frame, "Catch Pikachu!");
frame.getContentPane().add(new Creature());
frame.pack();
frame.setVisible(true);
}
}
Panel:
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Random;
import javax.swing.ImageIcon;
import javax.swing.JPanel;
import javax.swing.Timer;
public class Creature extends JPanel
{
private static final int DELAY=900;
private Random generator = new Random();
private ImageIcon image, image1;
private Timer timer;
private int x, y;
private int catchCount=0;
public Creature()
{
image = new ImageIcon ("pikachu.png");
image1 = new ImageIcon ("pokeball.png");
timer = new Timer(DELAY, new MoveListener());
x = generator.nextInt( 1900 );
y = generator.nextInt(1000);
addMouseListener (new MouseClickedListener());
setBackground (Color.green);
setPreferredSize(new Dimension(1900,1000));
timer.start();
}
//Draws the image.
public void paintComponent(Graphics page)
{
super.paintComponent(page);
image.paintIcon (this, page, x, y);
page.drawString("Pikachus Captured: " + catchCount, 10, 35);
setFont(new Font("Arial", Font.BOLD,35));
}
//Method for moving the image.
public void move()
{
timer.start();
x = generator.nextInt( 1900 );
y = generator.nextInt(1000);
if (timer.isRunning())
{
x = generator.nextInt( 1900 );
y = generator.nextInt(1000);
}
repaint();
}
//Method for getting the number of times caught.
public int getCatchCount()
{
return catchCount;
}
//Makes the image move
private class MoveListener implements ActionListener
{
public void actionPerformed(ActionEvent event)
{
move();
repaint();
}
}
//Records when the user clicks the image.
private class MouseClickedListener extends MouseAdapter
{
public void mouseClicked(MouseEvent event)
{
if((event.getButton() == MouseEvent.BUTTON1) && between(event.getX(), x, x + image.getIconWidth()) && between(event.getY(), y, y + image.getIconHeight()))
{
System.out.println("CAUGHT ONE!");
catchCount++;
move();
image=image1;
}
}
}
private static boolean between(int x, int lower, int upper)
{
return (x >= lower) && (x <= upper);
}
}
Upvotes: 0
Views: 2250
Reputation: 37835
You need a way to paint either Image. Right now you are just assigning image
to image1
and when you do that the Image that is from "pikachu.png"
disappears.
Without restructuring too much you can just make a flag for which one to paint:
/* as a field */
private boolean justCaptured;
Now you have to change your painting logic a little:
if (justCaptured) {
image1.paintIcon (this, page, x, y);
} else {
image.paintIcon (this, page, x, y);
}
Now the first thing you do is instead of reassigning image
, set the flag to true:
System.out.println("CAUGHT ONE!");
catchCount++;
justCaptured = true;
move();
There's one last thing you need to do which is to set the flag back to false for the next draw. There are some different ways to approach this but the simplest I see without refactoring a number of things is to queue it for later:
System.out.println("CAUGHT ONE!");
catchCount++;
justCaptured = true;
move();
SwingUtilities.invokeLater(new Runnable() {
@Override public void run() {
justCaptured = false;
}
});
Using invokeLater will enqueue it at the end of EventQueue and it will be changed after previously queued tasks complete. So after the mouse event exits and then after the repaint you've just requested in move
.
"I post all of it in case anyone would like to give advice on other things general things."
timer.start
in move
and this doesn't appear necessary. Timers repeat by default.move
generates x
and y
twice. Since you call timer.start
in the constructor, timer.isRunning
will always be true.MoveListener
calls repaint
after calling move
but move
also calls repaint
."Also so people can test it themselves if they would like to."
We can't run it because we don't have your images. If you want to post it so we can run it change the code so it works without them. Otherwise we have to go and change it somehow ourselves. Here's a static method that returns a blank ImageIcon:
public static ImageIcon createBlankIcon(int w, int h, Color color) {
BufferedImage img = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
Graphics2D g2d = img.createGraphics();
g2d.setColor(color);
g2d.fillRect(0, 0, w, h);
g2d.dispose();
return new ImageIcon(img);
}
You can substitute something like that for content, eg: image = getBlankIcon(50, 50, Color.RED);
.
Upvotes: 1
Reputation: 2876
i hope i understand what do you try to achieve. first you need 3 Images:
private ImageIcon imageToDraw, image1, image2;
Creature will look like this now:
public Creature()
{
image1 = new ImageIcon ("pikachu.png");
image2 = new ImageIcon ("pokeball.png");
imageToDraw = image1;
...
}
in move() you should set the image to image1:
public void move()
{
imageToDraw = image1;
timer.start();
x = generator.nextInt( 1900 );
...
}
dont forget to change image to imageToDraw in paint():
public void paintComponent(Graphics page)
{
super.paintComponent(page);
imageToDraw.paintIcon (this, page, x, y);
...
}
remove move(); from onclick-event and change image to imageToDrwa in click-action:
public void mouseClicked(MouseEvent event)
{
if((event.getButton() == MouseEvent.BUTTON1) && between(event.getX(), x, x + image.getIconWidth()) && between(event.getY(), y, y + image.getIconHeight()))
{
System.out.println("CAUGHT ONE!");
catchCount++;
//move(); should be removed
imageToDraw=image1;
}
}
edit:move(); removed from onclick-event
Upvotes: 1