JFrame Background is moving despite having fixed coordinates - java

I'm using JFrame to display some images. I've just started, and at this point I want to have a character move on screen. I have 2 files, one that extends JFrame (displays the images) and a runner file. One images is a stationary background while the other is the movable character, however, it seems that both images seem to move and the background position being stationary.
I just started using JFrame and have no idea whats going on.
This is the file that extends JPanel:
public class testScene extends JPanel{
private int x = 60;
private int y = 60;
private boolean end = false;
public void paintComponent(Graphics g){
super.paintComponent(g);
ImageIcon background = new ImageIcon("images\\map\\TestMap1.png");
background.paintIcon(this, g, 0, 0);
ImageIcon protag = new ImageIcon("images\\protag\\protag_f.png");
protag.paintIcon(this, g, x, y);
}
public int getX(){return x;}
public int getY(){return y;}
public boolean getEnd(){return end;}
public void setX(int i){x=i;}
public void setY(int i){y=i;}
public void setEnd(boolean b){end = b;}
}
This is the intended Runner:
public class testSceneRunner{
public static void main(String[] args){
testScene scene = new testScene();
scene.setBackground(Color.black);
JFrame jf = new JFrame();
InListner keyIn = new InListner(); //this is a keyboard listner
jf.addKeyListener(keyIn);
jf.setTitle("Test Scene");
jf.setSize(1020,600);
jf.setVisible(true);
jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
jf.add(scene);
while(!scene.getEnd()){
//just changes x or y based on keyboard input
try {
Thread.sleep(25);
} catch (InterruptedException e) {
e.printStackTrace();
}
if(keyIn.getPressed() == 87){
scene.setY(scene.getY()-1);
}
if(keyIn.getPressed() == 65){
scene.setX(scene.getX()-1);
}
if(keyIn.getPressed() == 83){
scene.setY(scene.getY()+1);
}
if(keyIn.getPressed() == 68){
scene.setX(scene.getX()+1);
}
if(keyIn.getPressed() == 69){
scene.setEnd(true);
}
jf.repaint();
}
jf.dispatchEvent(new WindowEvent(jf, WindowEvent.WINDOW_CLOSING));
}
}
I want the background to remain stationary and the character to move when one of the WASD keys is pressed. However, the background moves as well.

Related

How do I get mouse movements work properly for several different ImageIcons inside a JPanel?

I am currently trying to write my first very simple image manipulation program with Swing. It is supposed to be possible to browse for and add images as ImageIcons and move around these images on the screen. The photos should be layered on top of each other as they are added, and clicking an image should remove it.
The program runs but I am having the following functionality problems.
This is my code:
import javax.swing.*;
import java.awt.*;
import javax.swing.filechooser.FileNameExtensionFilter;
import java.awt.event.*;
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
class Image {
private int x = 80;
private int y = 80;
private String filepath;
private ImageIcon image;
public Image(int x, int y, String filepath){
this.x = x;
this.y = y;
this.filepath = filepath;
image = new ImageIcon(filepath);
}
public Image(String filepath){
this.filepath = filepath;
image = new ImageIcon(filepath);
}
public void draw(Graphics g){
g.drawImage(image.getImage(), x, y, null);
}
public void undraw (Graphics g, Color c ){
g.setColor(c);
g.fillRect(x,y,image.getIconWidth(), image.getIconHeight());
}
public boolean containsXY (int x, int y){
if ( this.x <= x && this.y <= y){
return true;
}
return false;
}
public void move (Graphics g, int x, int y) {
undraw(g, Color.WHITE);
this.x = x;
this.y = y;
draw(g);
}
}
class PaintSurface extends JPanel implements MouseListener, MouseMotionListener {
private int x, y;
private JButton browse;
private Collection <Image> images = new ArrayList<Image>();
private final JFileChooser fc = new JFileChooser();
private Image selected;
public PaintSurface(JButton b){
browse = b;
addMouseListener(this);
addMouseMotionListener(this);
browse.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
FileNameExtensionFilter filter = new FileNameExtensionFilter("JPG & GIF", "jpg", "gif");
fc.setFileFilter(filter);
fc.showOpenDialog(browse);
buttonPressed(fc);
}
});
}
public void paintComponent (Graphics g){
super.paintComponent(g);
for (Image i: images){
i.draw(g);
}
}
public void addImage(Image i){
images.add(i);
Graphics g = getGraphics();
i.draw(g);
}
public void buttonPressed(JFileChooser fc){
File selectedFile = fc.getSelectedFile();
Image i = new Image(x, y, selectedFile.getAbsolutePath());
addImage(i);
repaint();
}
public Image findImage(int x, int y){
for (Image i: images){
if (i.containsXY(this.x, this.y)){
return i;
}
}
return null;
}
public boolean removeImage (Image i){
Graphics g = getGraphics();
i.undraw(g, Color.WHITE);
return images.remove(i);
}
public void moveImage (Image i, int x, int y) { //
i.move(getGraphics(), x, y);
}
#Override
public void mouseClicked(MouseEvent e) {
x = e.getX();
y = e.getY();
Image i = findImage(x, y);
if (i != null) {
removeImage(i);
}
}
#Override
public void mousePressed(MouseEvent e) {
int x = e.getX();
int y = e.getY();
selected = findImage(x,y);
}
#Override
public void mouseDragged(MouseEvent e) {
int x = e.getX();
int y = e.getY();
if (selected != null) {
moveImage(selected,x,y);
}
}
#Override
public void mouseReleased(MouseEvent e) {
}
#Override
public void mouseEntered(MouseEvent e) {
}
#Override
public void mouseExited(MouseEvent e) {
}
#Override
public void mouseMoved(MouseEvent e) {
}
}
class GUI extends JFrame {
public GUI(){
super("ImageApp");
JLabel instruction = new JLabel("Clicking anywhere on the screen will set the location for the next added image.");
JButton browse = new JButton("Add image");
JPanel panel1 = new JPanel();
JPanel panel2 = new PaintSurface(browse);
panel1.setLayout(null);
panel2.setBackground(Color.WHITE);
instruction.setAlignmentX(CENTER_ALIGNMENT);
getContentPane().setBackground(Color.WHITE);
getContentPane().add("North", instruction );
getContentPane().add("South", browse);
add(panel1);
add(panel2);
setBounds(300,0,800,800);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setResizable(false);
setVisible(true);
}
}
public class PhotoApp extends GUI {
public static void main (String[] args){
GUI PhotoApplication = new GUI();
}
}
These are the problems:
When I have added several images, the mousefunctionality suddenly stops to work and I can't move any of the images. They get "stuck" somehow.
When I have added several images, I can only control (move) the latest added one.
When clicking to remove an image, it is removed even though I don't click inside the image but close to the image. It isn't removed if I click far away from the image (so it's sort of working). It is only supposed to be removed if clicking inside the image!
When clicking to add an image, if I press "Cancel" I get a bunch of errors
The pictures are supposed to be layered on top of each other, but when I move an image around now it "erases" the older images.
Can anyone help? I would be so thankful because I have been stuck a long time with this.
I have outlined the problematic code for some of your questions.
When I have added several images, I can only control (move) the latest added one.
You are only returning one: public Image findImage(int x, int y). And:
When clicking to remove an image, it is removed even though I don't click inside the image but close to the image. It isn't removed if I click far away from the image (so it's sort of working). It is only supposed to be removed if clicking inside the image!
Your containsXY() seems to be messed up here: if ( this.x <= x && this.y <= y). Hint: a 1 pixel square image with x = 0 and y = 0 does not contain x = 50, y = 50. This causes part of the first issue I addressed.
When clicking to add an image, if I press "Cancel" I get a bunch of errors
It will not return a File if you do not select one:
File selectedFile = fc.getSelectedFile();
The pictures are supposed to be layered on top of each other, but when I move an image around now it "erases" the older images.
You are undrawing it with WHITE:
g.fillRect(x,y,image.getIconWidth(), image.getIconHeight());

Images not showing up on JPanel?

I am having some trouble getting both the squares I created in the program, and the ImageIcon imported to show up on my JPanel. I have been at this for a while now, and still am unable to figure out what I can do to make them show up, and allows the player image to move. Here is the first piece of my code which is the Maze class:
public class Maze extends JPanel{
int[][][] mazeArray; //will be defined in the loop depending on how many rectangles are spawned, also for making sure the player can't walk over the walls (first is what number wall it is, second is the x coordiante of the wall, and third is the y coordinate of the wall)
//depending on whether or not the rctangle is vertical or horizontal it will use both values for its height and width (vertical would have sideX for the height, and sideY for the width; this would be the opposite for the horizontal rectangle)
int sideX = 50; //x side length
int sideY = 50; //y side length
int x;
int y;
//setters and getters for use later (for changing the rctangles location and size)
public void setSideX(int sideX){
this.sideX = sideX;
}
public int getSideX(){
return sideX;
}
public void setSideY(int sideY){
this.sideY = sideY;
}
public int getSideY(){
return sideY;
}
public void setCoordinates(int x, int y){
this.x = x;
this.y = y;
}
public void setX(int x){
this.x = x;
}
public int getX(){
return x;
}
public void setY(int y){
this.y = y;
}
public int getY(){
return y;
}
//end setters and getters
public void generateMaze(){
//the left side of the maze
for(int i = 0; i < 10; i++){ //ten blocks on the left side
setX(0); //x is always 0 for the left side
setY(getY() + 50); //adds 50 to the previous Y coordinate amount, m making it go down the whole left side
}
setY(0); //set y back to zero to be able to start the right column of blocks
//the right side of the maze
for(int i = 0; i < 10; i++){
setX(500); //x is always 500 for the right side
setY(getY() + 50); //does the same as it did on the left side, except on the right
}
setY(0); //set y to zero again
setX(50); //start x at 50 since there is no need to remake the corners
for(int i = 0; i < 8; i++){ //only goes up to 8 this this time because the corners of the maze can be ignored
setY(0); //just in case y changes back
setX(getX() + 50); //x increases by 50 each time
}
setY(500);
setX(50);
for(int i = 0; i < 8; i++){ //same as above except for the bottom
setY(500);
setX(getX() + 50);
}
//the maze walls are now generated
}
public void paintComponent(Graphics g){ //for painting the rectangles
super.paintComponent(g);
g.setColor(Color.BLACK);
g.fillRect(getX(), getY(), sideX, sideY); //uses x and y coordinates defined in the generateMaze loop, and the uses whatever current value for the two side, depending on what type of rectangle it is
}
}
This is what I am using to create the mazes walls. Now comes the Player class which deals with the player image, player coordinates, and the player's movement speed:
public class Player {
//Player starts in the top left corner
int playerX = 50;
int playerY = 50;
int moveSpeed = 5; //I can edit move speed here
Image character;
//getters and setters to utilize the player's location and image
public Player(){ //constructor for initial starting points
playerX = 50;
playerY = 50;
ImageIcon player = new ImageIcon("E://Workspace//Maze//images//Player.jpg");
character = player.getImage();
}
public void setPlayerX(int playerX){
this.playerX = playerX;
}
public int getPlayerX(){
return playerX;
}
public void setPlayerY(int playerY){
this.playerY = playerY;
}
public int getPlayerY(){
return playerY;
}
public void setMoveSpeed(int moveSpeed){
this.moveSpeed = moveSpeed;
}
public int getMoveSpeed(){
return moveSpeed;
}
public Image getPlayerImage(){
return character;
}
}
Next is where I think the problem is occurring for the player's image (for the maze I think it is something in the Maze class itself, although it could be a problem in the Layout class as well):
public class Layout extends JPanel implements ActionListener { //GUI with a non null FlowLayout
Maze m = new Maze();
Player p = new Player();
//500 x 500 seemed like a good size for the maze game
int x = 500;
int y = 500;
Image player;
JPanel panel;
public Layout() {
panel = new JPanel();
panel.setLayout(new FlowLayout()); //same as the JFrame
panel.addKeyListener(new Move(p));
panel.setFocusable(true);
panel.setBackground(Color.YELLOW); //background of the maze
m.generateMaze(); //create the maze
}
//for use in setting and getting the borders of the game
public void setX(int x){
this.x = x;
}
public int getX(){
return x;
}
public void setY(int y){
this.y = y;
}
public int getY(){
return y;
}
public JPanel getPanel(){
return panel;
}
#Override //so it can repaint as needed
protected void paintComponent(Graphics g){
super.paintComponent(g);
g.drawImage(p.getPlayerImage(), p.getPlayerX(), p.getPlayerY(), this);
}
public void actionPerformed(ActionEvent ae){
repaint();
}
}
class Move implements KeyListener { //for player movement
final Player p;
Move(Player p){
this.p = p;
}
public void keyPressed(KeyEvent press) { //for the movement in the game
//I used both keys so that if the player woukld like to use WASD or the arrow keys either will work
if(press.getKeyCode() == KeyEvent.VK_W || press.getKeyCode() == KeyEvent.VK_UP){
//move up
p.setPlayerY(p.getPlayerY() - p.getMoveSpeed());
}
else if(press.getKeyCode() == KeyEvent.VK_S || press.getKeyCode() == KeyEvent.VK_DOWN){
//move down
p.setPlayerY(p.getPlayerY() + p.getMoveSpeed());
}
else if(press.getKeyCode() == KeyEvent.VK_A || press.getKeyCode() == KeyEvent.VK_LEFT){
//move left
p.setPlayerX(p.getPlayerX() - p.getMoveSpeed());
}
else if(press.getKeyCode() == KeyEvent.VK_D || press.getKeyCode() == KeyEvent.VK_RIGHT){
//move right
p.setPlayerX(p.getPlayerX() + p.getMoveSpeed());
}
}
public void keyReleased(KeyEvent release) {
//nothing is needed here
}
public void keyTyped(KeyEvent e) {
//does nothing if a key is type (no need for it)
}
}
Lastly is the class that runs it, although I don't think there is any issue here, but just in case I will throw it in here anyway:
public class Play extends JPanel {
public static void main(String[]args) {
play();
}
public static void play() {
JFrame f = new JFrame();
Layout l = new Layout();
JPanel j = l.getPanel();
f.setTitle("Maze Game for final project");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(l.getX(), l.getY()); //size can be changed in layout
f.setVisible(true);
f.add(j); //adds the panel
}
}
I am trying to be able to have the player's image spawn at 50, 50 on start up, and then also have the walls spawn at start up as well. However currently the only thing that is showing up for the JPanel is the yellow background. Help would be greatly appreciated!
New updated code here:
public static void play() {
JFrame f = new JFrame();
Layout l = new Layout();
f.setTitle("Maze Game for final project");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(l.getX(), l.getY()); //size can be changed in layout
f.add(new Layout()); //adds the panel
f.setVisible(true);
}
and also for the Layout constructor
public Layout() {
setLayout(new FlowLayout());
addKeyListener(new Move(p));
setFocusable(true);
setBackground(Color.YELLOW);
m.generateMaze();
}
I can't say that I've gone through all of your code, but one thing did strike me:
Your Layout class extends JPanel and overrides paintComponet, but you never use this class as a JPanel. Instead you use some other JPanel variable within it called panel. Get rid of that variable and instead use the JPanel that is the Layout class itself, and at least some of your problems may be fixed.
e.g.,
public class Layout extends JPanel implements ActionListener {
Maze m = new Maze();
Player p = new Player();
int x = 500;
int y = 500;
Image player;
// JPanel panel;
public Layout() {
// panel = new JPanel();
// panel.setLayout(new FlowLayout()); //same as the JFrame
// panel.addKeyListener(new Move(p));
// panel.setFocusable(true);
// panel.setBackground(Color.YELLOW); //background of the maze
setLayout(new FlowLayout());
addKeyListener(new Move(p));
setFocusable(true);
setBackground(Color.YELLOW);
m.generateMaze();
}
public void setX(int x) {
this.x = x;
}
public int getX() {
return x;
}
public void setY(int y) {
this.y = y;
}
public int getY() {
return y;
}
// public JPanel getPanel() {
// return panel;
// }
#Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.drawImage(p.getPlayerImage(), p.getPlayerX(), p.getPlayerY(), this);
}
public void actionPerformed(ActionEvent ae) {
repaint();
}
}
Another problem is your use of KeyListeners since Key Bindings would be much preferable here, but I'll leave that for your next question.
Also, you're adding your JPanel to the JFrame after calling setVisible(true) on the JPanel -- don't do this. Call setVisible(true) only after adding all components.

Add moving objects to JFrame

I'm creating a java game. In the game there are a hero and a bubble. The hero is supposed to move when I press the arrow keys and the bubble is supposed to have continuous diagonal movement. When I add the hero or the bubble directly into to the JFrame separately I get the desired behavior, but when I add them both I just get a very small square! I tried to add them to the same JPanel and after add that JPanel to the JFrame but it is not working. Probably I have to define some type of layout to the JPanels.
What am I doing wrong?
Code:
public class Pang {
public static void main(String[] args) {
JFrame f=new JFrame();
JPanel gamePanel=new JPanel();
gamePanel.setPreferredSize(new Dimension(800, 600));
DrawHero d=new DrawHero();
DrawBubble bubble=new DrawBubble();
gamePanel.add(d);
gamePanel.add(bubble);
f.add(gamePanel);
f.setVisible(true);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(800, 600);
}
}
public class DrawHero extends JPanel implements ActionListener, KeyListener {
Timer myTimer = new Timer(5, this);
int x = 0, y = 0, dx = 0, dy = 0, step = 10;
private transient Image imageHero = null;
public DrawHero() {
myTimer.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
imageHero = getHeroImage();
g2.drawImage(imageHero, x, y, 40, 40, null);
}
public Image getHeroImage() {
Image image = null;
image = getImage("hero.png");
return image;
}
public Image getImage(String path) {
Image tempImage = null;
try {
URL heroiURL = DrawHero.class.getResource(path);
tempImage = Toolkit.getDefaultToolkit().getImage(heroiURL);
} catch (Exception e) {
System.out.println("Error loading hero image! - "
+ e.getMessage());
}
return tempImage;
}
public void actionPerformed(ActionEvent e) {
repaint();
}
public void moveUp() {
y = y - step;
}
public void moveDown() {
y = y + step;
}
public void moveLeft() {
x = x - step;
}
public void moveRight() {
x = x + step;
}
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (keyCode == KeyEvent.VK_UP) {
moveUp();
}
if (keyCode == KeyEvent.VK_DOWN) {
moveDown();
}
if (keyCode == KeyEvent.VK_LEFT) {
moveLeft();
}
if (keyCode == KeyEvent.VK_RIGHT) {
moveRight();
}
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
}
public class DrawBubble extends JPanel implements ActionListener, KeyListener {
Timer myTimer = new Timer(5, this);
int x = 100, y = 200, dx = 0, dy = 0, step = 10;
private transient Image imageHero = null;
public DrawBubble() {
myTimer.start();
addKeyListener(this);
setFocusable(true);
setFocusTraversalKeysEnabled(false);
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2 = (Graphics2D) g;
g2.fill(new Ellipse2D.Double(x, y, 40, 40));
}
public void actionPerformed(ActionEvent e) {
x=x+dx;
y=y+dy;
repaint();
}
public void moveBubble() {
dy=2;
dx=2;
}
public void keyPressed(KeyEvent e) {
moveBubble();
}
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
}
I recommend that neither the DrawHero nor DrawBubble (which should be called Hero nor Bubble respectively) should extend any JComponent. Instead each should simply know how to draw itself to a Graphics object passed to it, when requested to do so.
Then a single GameField or PlayingArea class should keep references to all the Bubble objects and the Hero and draw call the draw(Graphics) method of those objects.
Using this approach it is not necessary to worry about layouts within the GameField component (they become irrelevant).
That is the basic strategy I pursue for rendering the stationary objects in this answer to [Collision detection with complex shapes.
When I add the hero or the bubble directly into to the JFrame separately I get the desired behavior, but when I add them both i just get a very small square!
The default layout manager for a JFrame is a BorderLayout. When you use add(component) without a constraint the component goes to the CENTER. Only one component can be added to the CENTER, so only the last one added is displayed.
I tried to add them to the same JPanel and after add that JPanel to the JFrame but it is not working.
The default layout manager for a JPanel is the FlowLayout which respects the preferred size of component. The problem is you don't override the getPreferredSize() method so the size is (0, 0) and there is nothing to paint.
Probably I have to define some type of layout to the JPanels.
Actually since you want random motion you need to use a null layout on the panel and then use the setSize() and setLocation() method of your components to position the components.
Then when you do this the custom painting should always be done at (0, 0) instead of (x, y) since the location will control where the component is painted on the panel.

Adding JPanel after removing it from JFrame

I'm developing a Java Game. I'm stuck at a point,where I need to restart the whole game again after GameOver. Here is the skeleton of my program:
package projectflappy;
import java.awt.*;
public final class TheGame extends JFrame implements MouseListener{
JPanel jp;
//declaration of the varibles
int x_width = 500;
int y_height = 500;
int count = 5 ;
Ellipse2D Ball;
int x_ball;
int y_ball;
int cord_xup1,cord_xdown1;
int cord_xup2,cord_xdown2;
int cord_xup3,cord_xdown3;
int cord_xup4,cord_xdown4;
int cord_xup5,cord_xdown5;
Boolean flag = true;
RoundRectangle2D up1,down1,up2,down2,up3,down3,up4,down4;
Font font = new Font("Matura MT Script Capitals",Font.ROMAN_BASELINE,40);
Font font1 = new Font("Matura MT Script Capitals",Font.ROMAN_BASELINE,20);
Font font3 = new Font("Matura MT Script Capitals",Font.ROMAN_BASELINE,20);
float das[] = {10.0f};
BasicStroke color = new BasicStroke(10,BasicStroke.CAP_ROUND,BasicStroke.JOIN_BEVEL,20.0f,das,0.0f);
GradientPaint gp2 = new GradientPaint(20, 0,
Color.DARK_GRAY, 0, 10, Color.GRAY, true);
GradientPaint gp3 = new GradientPaint(30, 0,
Color.BLACK, 0, 20, Color.GREEN, true);
Toolkit kit = Toolkit.getDefaultToolkit();
//Getting the "background.jpg" image we have in the folder
Image background = kit.getImage("D:\\College\\Programs\\ProjectFLAPPY\\src\\projectflappy\\1.png");
JLabel a = new JLabel("Get Ready ! Click to Start.");
JLabel retry = new JLabel(new ImageIcon("D:\\College\\Programs\\ProjectFLAPPY\\src\\projectflappy\\unnamed.png"));
int score = 0;
//constructor
public TheGame() throws IOException
{
super("Simple Drawing");
setSize(x_width, y_height);
setDefaultCloseOperation(EXIT_ON_CLOSE);
setVisible(true);
jp = new DrawingPanel();
add(jp);
addMouseListener(this);
}
ActionListener action = new ActionListener() {
#Override
public void actionPerformed(ActionEvent ae) {
update();
repaint();
}
};
Timer t = new Timer(50,action);
public void init()
{
x_ball = 30;
y_ball = 200;
cord_xup1 = 175; cord_xdown1 = 175;
cord_xup2 = 320; cord_xdown2 = 320;
cord_xup3 = 460; cord_xdown3 = 460;
cord_xup4 = 585; cord_xdown4 = 585;
cord_xup5 = 700; cord_xdown5 = 700;
retry.setVisible(false);
retry.setBounds(175,260,46,46);
a.setForeground(Color.YELLOW);
a.setFont(font1);
a.setVisible(true);
a.setBounds(105,200,300,100);
}
#Override
public void mouseClicked(MouseEvent e) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
a.setVisible(false);
if( flag == false)
{
t.stop();
}
else
{
t.start();
}
y_ball = y_ball - 40;
count--;
}
#Override
public void mousePressed(MouseEvent e) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public void mouseReleased(MouseEvent e) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public void mouseEntered(MouseEvent e) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public void mouseExited(MouseEvent e) {
//throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
// for drawing on the panel
class DrawingPanel extends JPanel{
private static final long serialVersionUID = 1L;
public DrawingPanel() {
setPreferredSize(new Dimension(300, 300));
setLayout(null);
init();
add(a);
add(retry);
// addMouseListener(this);
}
#Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D d = (Graphics2D)g;
d.drawImage(background, -270,-30, this);
Ball = new Ellipse2D.Double(x_ball,y_ball,30,30);
d.setColor(Color.green);
d.setFont(font3);
up1 = new RoundRectangle2D.Double(cord_xup1,-5,30,175,20,20);
down1 = new RoundRectangle2D.Double(cord_xdown1,310,30,155,20,20);
up2 = new RoundRectangle2D.Double(cord_xup2,-5,30,200,20,20);
down2 = new RoundRectangle2D.Double(cord_xdown2,310,30,175,20,20);
up3 = new RoundRectangle2D.Double(cord_xup3,-5,30,230,20,20);
down3 = new RoundRectangle2D.Double(cord_xdown3,350,30,135,20,20);
up4 = new RoundRectangle2D.Double(cord_xup4,-5,30,115,20,20);
down4 = new RoundRectangle2D.Double(cord_xdown4,240,30,115,20,20);
d.setPaint(gp2);
d.setStroke(color);
d.fill(up1);
d.fill(down1);
d.fill(up2);
d.fill(down2);
d.fill(up3);
d.fill(down3);
d.fill(up4);
d.fill(down4);
d.setPaint(gp3);
d.setStroke(color);
d.fill(Ball);
d.setColor(Color.BLACK);
d.setFont(font1);
d.drawString(""+score ,200,50);
if( Ball.intersects(up1.getBounds()) || Ball.intersects(down1.getBounds()) || Ball.intersects(up2.getBounds()) || Ball.intersects(down2.getBounds()) || Ball.intersects(up3.getBounds()) || Ball.intersects(down3.getBounds()) || Ball.intersects(up4.getBounds()) || Ball.intersects(down4.getBounds()))
{
t.stop();
flag = false;
d.setColor(Color.red);
d.setFont(font);
d.drawString("Game Over : "+score ,100,250);
retry.setVisible(true);
}
retry.addMouseListener(new MouseListener() {
#Override
public void mouseClicked(MouseEvent event) {
init(); //reset properties
}
//...
#Override
public void mousePressed(MouseEvent e) {
// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public void mouseReleased(MouseEvent e) {
// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public void mouseEntered(MouseEvent e) {
// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
#Override
public void mouseExited(MouseEvent e) {
// throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
});
}
}
public void update()
{
cord_xdown1 -= 5;
cord_xup1 -= 5;
cord_xdown2 -= 5;
cord_xup2 -= 5;
cord_xdown3 -= 5;
cord_xup3 -= 5;
cord_xdown4 -= 5;
cord_xup4 -= 5;
cord_xdown5 -= 5;
cord_xup5 -= 5;
if( cord_xup1 <=-20)
{
cord_xup1 = 500;
cord_xdown1 = 500;
}
if( cord_xup2 <=-20)
{
cord_xup2 = 500;
cord_xdown2 = 500;
}
if( cord_xup3 <=-20)
{
cord_xup3 = 500;
cord_xdown3 = 500;
}
if( cord_xup4 <=-20)
{
cord_xup4 = 500;
cord_xdown4 = 500;
}
if( cord_xup5 <=-20)
{
cord_xup5 = 500;
cord_xdown5 = 500;
}
if(count >= 0)
{
y_ball = y_ball - 7;
count--;
if( y_ball == y_height)
{
t.stop();
}
}
else
{
y_ball = y_ball + 7;
if( y_ball == y_height-70)
{
t.stop();
}
}
if(cord_xdown1 == x_ball || cord_xdown2 == x_ball || cord_xdown3 == x_ball || cord_xdown4 == x_ball)
{
score = score+1;
}
}
public static void main(String[] args) throws IOException {
new TheGame();
}
}
here retry is a JLabel in which I'm using a MouseListener to do things.
When I run,the JPanel gets completely removed from the JFrame but the new JPanel really doesn't seem to work. But only one component i.e, a.setVisble(true) works.
This is the frame when the Players gets out.
This Frames when the Player clicks on the retry button.
The reason your new panel is not showing is due to the component hierarchy being invalid. You attempt to revalidate, but you did it before adding the panel. You need to do it AFTER you add a component to an already visible container. Check out invalidate():
This method is called automatically when any layout-related information changes (e.g. setting the bounds of the component, or adding the component to a container).
So you must validate after adding the component, not before. revalidate() invalidates then revalidates the component hierarchy.
The proper way to handle this would be to revert your game back to it's original form; just change everything back to how it was. No need to create a new panel.
You could create a method, init(), which sets your game to how it should be:
//Contains the properties that will change during gameplay
void init() {
retry.setVisible(false);
a.setForeground(Color.YELLOW);
//...
}
Which you can then call when you create the board (in the constructor) and when you press retry (in the listener):
public DrawingPanel() {
setPreferredSize(new Dimension(300, 300));
setPreferredSize(new Dimension(300, 300));
setLayout(null);
init(); //sets properties
a.setFont(font1);
a.setVisible(true);
a.setBounds(105,200,300,100);
add(a);
retry.setBounds(175,260,46,46);
retry.addMouseListener(new MouseListener() {
public void mouseClicked(MouseEvent event) {
init(); //reset properties
}
//...
});
add(retry);
}
You shouldn't add a listener to a component in your update() method, since update() will be called multiple times. Add it in your constructor.
If retry is a JButton, you should use an ActionListener. I wasn't sure, so I kept it as a mouse listener.
You should avoid using null layout (absolute positioning). Layout Managers position and size components using specific calculations to ensure your resulting GUI looks the same on all platforms. There are a few uses where absolute positioning is a viable option, as mentioned in the tutorials, but it's always best to prefer a Layout Manager. IMO, null layout is bad practice, and the only reason one would use it is if they didn't understand layout managers, which is a problem in itself.
To learn more about layout managers, check out the Visual Guide to Layout Managers trail. Not only does the JDK come bundled with layouts, but you can also create your own or use a third party layout, like MigLayout
EDIT:
Post Swing code to the Event Dispatch Thread. Swing event handlers (painting, listeners) are executed on the Event Dispatch Thread. To ensure the Swing code you write is in sync with the EDT, post any Swing code that isn't already being executed on the EDT to the EDT by using invokeLater or invokeAndWait.
Do not size your frame directly. Allow your frame to size based off the contents inside of it. Your DrawingPanel (the game canvas) should determine the size of the frame.
TheGame should not extend JFrame, since it's not a frame itself, rather than something contained within a frame. Having it extend JPanel would be a little easier on you (you won't be forced to create a new class to override the paint method). Although, TheGame shouldn't extend anything, it should HAVE these things (has-a relationship, not is-a). But since you're still a beginner, I don't wanna overwhelm you with a completely new design, so I considered TheGame to be the actual game canvas (where things will be draw; TheGame will extend JPanel), so you'll no longer need DrawingBoard.
As mentioned before, you should NOT add listeners (or do any task that is only needed once) in the paint method. Keep in mind that the paint method is for painting, not initializing or setting values. You should attempt to keep logic out of that method if possible.
Stay consistent. You use a JLabel for "Click to start!", yet you use drawString for "Game Over". Pick one or the other. This choice is really up to you. For this example, I chose to use drawString, since it's consistent with the rest of your rendering methods (how you paint the background, ball and obstacles)
DO NOT CREATE NEW OBJECTS IN YOUR PAINT METHOD. You're creating a ton of new objects every 50 milliseconds. This is NOT needed, and will harm performance critically. When you use the new keyword, you create a new object. Instead of creating a new object to change it (or revert it back), just change it's state.
Take advantage of Object Orientation. It'll help keep you organized, and allow you to easily manage and scale up your application. Don't shove a bunch of variables into one class to represent a ton of different things (cordx_up1, cordx_up2... it's definitely not scalable).
Look into some of the Adapter classes like MouseAdapter and KeyAdapter; they allow you to handle events without needing to declare methods you might not use.
Use access modifiers. If you aren't familiar with them, get to know them. It makes managing code a lot easier if you know where it can be used ahead of time.
Your paths point to a specific drive with a specific name. This should not be the case, since not everyone uses that drive and/or folder name. Package your images with your project, then refer to them locally.
With that said, you have a lot of studying to do.
What I did was create a Ball class and an Obstacle class, to get a little more organized. ball_x and ball_y are now inside the Ball class, as well as the gradient for it. The objects we create from this class will now have these properties (states). I create 1 ball object for your game.
Instead of creating new variables for each pole (cordx_up1), the Obstacle class has 2 RoundRectangle2D, top and bottom, which are the poles your ball is supposed to avoid. Each obstacle also has a gradient, which is used for both top and bottom. Now I can create 1 obstacle object for 2 aligned poles. You can change the starting x position of the obstacle (although I don't recommend allowing this; x should be set dynamically based on other obstacles' positions), as well as the size for top and bottom. I create 5 obstacle objects.
To keep your game labels organized (by color, message, location, font) while using drawString instead of JLabel, I created a GameLabel class.
I separated the main method into it's own class, named Launcher, which creates a JFrame and adds your game to it; all on the Event Dispatch Thread:
public class Launcher {
public static void main(String[] args) throws IOException {
EventQueue.invokeLater(new Runnable() {
public void run() {
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setResizable(false);
frame.add(new TheGame());
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
}
});
}
}
Your Game class now extends JPanel, so you can override the paint method to render the game. I created 1 Ball and a LinkedList for your obstacles. I chose a LinkedList since inserting/removing from front/end is guaranteed constant time, meaning it'll take the same amount of time to remove/insert no matter how many obstacles are in the list. When the ball passes an obstacle, I remove it from the front of the list and add it to the back. The first obstacle in the list is always the next obstacle.
I saw how some Strings were being re-used, so I created final variables for them, which you can easily change. There's also the currentlyPlaying and isAlive booleans. currentlyPlaying is set to true when the user first clicks (to start the game), and set to false once the user has clicked to restart the game (after he lost).
readyToJump is the flag I use to forward mouse events to your update() method (technically your updatePlayerPostion() method, but it's still "centeralized" within your update() method). It's best to keep all your logic in one place. readyToJump = true would have been the only statement in your listener's method if you weren't relying on calling timer.start() in it. Since update() can't be called unless the timer has started, and mouseEvent starts the timer, we must still handle starting the game in your listener's method.
#SuppressWarnings("serial")
public final class TheGame extends JPanel implements MouseListener, ActionListener {
public static final int WIDTH = 500, HEIGHT = 500;
private final String START_SCORE = "0",
START_MESSAGE = "Get Ready ! Click to Start.",
BACKGROUND_URL = "/res/flappy.png";
private boolean currentlyPlaying, readyToJump, isAlive = true;
private int score;
private Timer timer;
private Image background;
private GameLabel messageLabel, scoreLabel;
private Collection<Obstacle> obstaclesInOrder;
private LinkedList<Obstacle> obstacles;
private Ball ball;
public TheGame() {
setPreferredSize(new Dimension(WIDTH, HEIGHT));
addMouseListener(this);
timer = new Timer(50, this);
background = loadBackgroundImage();
messageLabel = new GameLabel(START_MESSAGE, 150, 240);
scoreLabel = new GameLabel(START_SCORE, 250, 60);
obstacles = new LinkedList<>();
obstacles.removeAll(obstacles);
obstaclesInOrder = Arrays.asList(new Obstacle(175, 20, 45), new Obstacle(320), new Obstacle(460), new Obstacle(585), new Obstacle(700));
obstacles.addAll(obstaclesInOrder);
ball = new Ball(30, 100);
}
#Override
public void mouseClicked(MouseEvent e) {
if (!currentlyPlaying) {
startGame();
} else if (!isAlive) {
reset();
}
readyToJump = true;
}
private void startGame() {
currentlyPlaying = true;
messageLabel.update("");
timer.start();
}
private void endGame() {
isAlive = false;
scoreLabel.update("");
messageLabel.update("Game Over. Your score was " + Integer.toString(score));
timer.stop();
}
private void reset() {
ball.reset();
for (Obstacle obstacle : obstacles)
obstacle.reset();
messageLabel.update(START_MESSAGE, 150, 240);
scoreLabel.update(START_SCORE, 250, 60);
obstacles.removeAll(obstacles);
obstacles.addAll(obstaclesInOrder);
score = 0;
isAlive = true;
currentlyPlaying = false;
repaint();
}
#Override
public void actionPerformed(ActionEvent ae) {
update();
repaint();
}
private void update() {
if (isAlive) {
updateBallPosition();
updateObstaclePositions();
if(ballOutOfBounds() || playerCollidedWithObstacle()) {
endGame();
} else if(ballPassedObstacle()) {
addToScore();
setupNextObstacle();
}
}
}
private void updateBallPosition() {
if (readyToJump) {
readyToJump = false;
ball.jump();
} else {
ball.fall();
}
}
private void updateObstaclePositions() {
for (Obstacle obstacle : obstacles) {
if (obstacle.getX() <= -obstacle.getWidth()) {
obstacle.moveToBack();
continue;
}
obstacle.moveForward();
}
}
private void addToScore() {
scoreLabel.update(Integer.toString(++score));
}
private void setupNextObstacle() {
obstacles.addLast(obstacles.removeFirst());
}
private boolean ballOutOfBounds() {
return ball.getY() >= HEIGHT || ball.getY() <= 0;
}
private boolean ballAtObstacle() {
Obstacle currentObstacle = obstacles.getFirst();
return ball.getX() + ball.getWidth() >= currentObstacle.getX() && ball.getX() <= currentObstacle.getX() + currentObstacle.getWidth();
}
private boolean ballPassedObstacle() {
Obstacle currentObstacle = obstacles.getFirst();
return ball.getX() >= (currentObstacle.getX() + currentObstacle.getWidth());
}
private boolean playerCollidedWithObstacle() {
boolean collided = false;
if(ballAtObstacle()) {
for (Obstacle obstacle : obstacles) {
RoundRectangle2D top = obstacle.getTop();
RoundRectangle2D bottom = obstacle.getBottom();
if (ball.intersects(top.getX(), top.getY(), top.getWidth(), top.getHeight()) || ball.intersects(bottom.getX(), bottom.getY(), bottom.getWidth(), bottom.getHeight())) {
collided = true;
}
}
}
return collided;
}
private Image loadBackgroundImage() {
Image background = null;
URL backgroundPath = getClass().getResource(BACKGROUND_URL);
if(backgroundPath == null) {
background = new BufferedImage(WIDTH, HEIGHT, BufferedImage.TYPE_INT_RGB);
} else {
try {
background = ImageIO.read(backgroundPath);
} catch (IOException e) {
e.printStackTrace();
}
}
return background;
}
#Override
public void paintComponent(Graphics graphics) {
super.paintComponent(graphics);
Graphics2D g = (Graphics2D) graphics;
g.drawImage(background, 0, 0, null);
ball.paint(g);
for (Obstacle obstacle : obstacles)
obstacle.paint(g);
scoreLabel.paint(g);
messageLabel.paint(g);
}
//...
}
loadBackgroundImage() loads and returns an image. If a problem occurs (image probably isn't there), it returns a black image.
(Most of) The game logic is in the update() method. Although it should all be in there, we can't due to a design flaw (from you using Timer which manages update(), and you start the timer in a listener, therefore we needed some logic in the listener). Your logic should be easy to read, and every execution step should be monitored and set by highest priority to lowest.
First, I check to make sure the ball hasn't collided with anything or gone out of bounds. If one of those things occur, I end the game.
If not, I check to see if the player has passed an obstacle. If the player passes an obstacle, I add to the score:
private void update() {
if (ballOutOfBounds() || playerCollidedWithObstacle()) {
endGame();
} else if (ballPassedObstacle()) {
addToScore();
setupNextObstacle();
}
updateBallPosition();
updateObstaclePositions();
}
I then finally update the positions.
To avoid constantly comparing the player's position and the obstacle's position (to see if the player has passed it), I created a boolean ballAtObstacle() method, which checks if the player is at an obstacle. Only then do I compare positions:
private boolean playerCollidedWithObstacle() {
boolean collided = false;
if (ballAtObstacle()) {
for (Obstacle obstacle : obstacles) {
RoundRectangle2D top = obstacle.getTop();
RoundRectangle2D bottom = obstacle.getBottom();
if (ball.intersects(top.getX(), top.getY(), top.getWidth(), top.getHeight()) || ball.intersects(bottom.getX(), bottom.getY(), bottom.getWidth(), bottom.getHeight())) {
collided = true;
}
}
}
return collided;
}
The ball.intersects method call is a bit messy. I did this so the shape didn't have to be specific, although you could declare the intersects method as boolean intersects(Shape shape).
Finally, I gave it a more flappy bird feel by increasing the fall speed as you fall. When you jump again, it goes back to normal. The longer it takes you to jump, the faster you'll fall. If you don't like this feature, and don't know how to remove it, let me know and I'll show you how.
The other classes involved:
GameLabel.java
public class GameLabel {
private String message;
private Font font;
private Color color;
private int x, y;
public GameLabel(String message, int x, int y, Color color, Font font) {
update(message, x, y, color, font);
}
public GameLabel(String message, int x, int y) {
this(message, x, y, Color.BLACK, new Font("Matura MT Script Capitals", Font.ROMAN_BASELINE, 20));
}
public GameLabel() {
this("", 0, 0);
}
public void setMessage(String message) {
this.message = message;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void setColor(Color color) {
this.color = color;
}
public void setFont(Font font) {
this.font = font;
}
public final void update(String message, int x, int y, Color color, Font font) {
this.message = message;
this.x = x;
this.y = y;
this.color = color;
this.font = font;
}
public void update(String message, int x, int y) {
update(message, x, y, color, font);
}
public void update(String message) {
update(message, x, y);
}
public void paint(Graphics2D g) {
g.setFont(font);
g.setColor(color);
g.drawString(message, x, y);
}
public Font getFont() {
return font;
}
public Color getColor() {
return color;
}
public String getMessage() {
return message;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
}
Obstacle.java
public class Obstacle {
public static final int DEFAULT_TOP_HEIGHT = 175;
public static final int DEFAULT_BOTTOM_HEIGHT = 175;
public static final int DEFAULT_WIDTH = 30;
public static final int DEFAULT_ARCH_WIDTH = 20;
public static final int DEFAULT_ARCH_HEIGHT = 20;
public static final int DEFAULT_TOP_INSET = -5;
public static final int DEFAULT_BOTTOM_INSET = TheGame.HEIGHT + 5;
private RoundRectangle2D top, bottom;
private BasicStroke stroke;
private GradientPaint gradient;
private int initialX, x, width;
public Obstacle(int x, int width, int topHeight, int bottomHeight) {
this.x = initialX = x;
this.width = width;
top = new RoundRectangle2D.Double(x, DEFAULT_TOP_INSET, width, topHeight, DEFAULT_ARCH_WIDTH, DEFAULT_ARCH_HEIGHT);
bottom = new RoundRectangle2D.Double(x, DEFAULT_BOTTOM_INSET-bottomHeight, width, bottomHeight, DEFAULT_ARCH_WIDTH, DEFAULT_ARCH_HEIGHT);
stroke = new BasicStroke(10, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL, 20.0f, new float[] { 10.0f }, 0.0f);
gradient = new GradientPaint(20, 0, Color.DARK_GRAY, 0, 10, Color.GRAY, true);
}
public Obstacle(int x, int topHeight, int bottomHeight) {
this(x, DEFAULT_WIDTH, topHeight, bottomHeight);
}
public void reset() {
x = initialX;
top.setRoundRect(initialX, top.getY(), top.getWidth(), top.getHeight(), top.getArcWidth(), top.getArcHeight());
bottom.setRoundRect(initialX, bottom.getY(), bottom.getWidth(), bottom.getHeight(), bottom.getArcWidth(), bottom.getArcHeight());
}
public Obstacle(int x, int width) {
this(x, width, DEFAULT_TOP_HEIGHT, DEFAULT_BOTTOM_HEIGHT);
}
public Obstacle(int x) {
this(x, DEFAULT_WIDTH);
}
public void moveToBack() {
x = 600;
}
public void moveForward() {
x -= 5;
top.setRoundRect(x, top.getY(), top.getWidth(), top.getHeight(), top.getArcWidth(), top.getArcHeight());
bottom.setRoundRect(x, bottom.getY(), bottom.getWidth(), bottom.getHeight(), bottom.getArcWidth(), bottom.getArcHeight());
}
public RoundRectangle2D getTop() {
return top;
}
public RoundRectangle2D getBottom() {
return bottom;
}
public int getX() {
return x;
}
public int getWidth() {
return width;
}
public void paint(Graphics2D g) {
g.setPaint(gradient);
g.setStroke(stroke);
g.fill(top);
g.fill(bottom);
}
}
Ball.java
public class Ball {
public static final int DEFAULT_DROP_SPEED = 7;
private Ellipse2D ball;
private GradientPaint gradient;
private int initialY, x, y, width = 30, height = 30, dropSpeed = DEFAULT_DROP_SPEED;
public Ball(int x, int y) {
this.x = x;
this.y = initialY = y;
width = height = 30;
ball = new Ellipse2D.Double(x, y, width, height);
gradient = new GradientPaint(30, 0, Color.BLACK, 0, 20, Color.GREEN, true);
}
public void reset() {
y = initialY;
updateBall();
}
public void jump() {
dropSpeed = DEFAULT_DROP_SPEED;
y -= 40;
updateBall();
}
public void fall() {
y += dropSpeed++;
updateBall();
}
private void updateBall() {
ball.setFrame(x, y, width, height);
}
public boolean intersects(double x, double y, double w, double h) {
return ball.intersects(x, y, w, h);
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public int getWidth() {
return width;
}
public int getHeight() {
return width;
}
public void paint(Graphics2D g) {
g.setPaint(gradient);
g.fill(ball);
}
public void moveForward() {
x += 7;
}
}
Reinitialize all the components by adding the initialization code to one method(resetAll) and call that method when u want to reinitailize
Below is an example:
import java.awt.*;
import java.awt.event.*;
public class ResetTest extends Frame{
Button b;
TextField tf;
Frame f;
Panel p;
public ResetTest(){
f=this; //intialize frame f to this to have access to our frame in event handler methods
resetAll(); //first time call to resetAll will initialize all the parameters of the frame
f.pack();
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent we){
System.exit(0);
}
});
this.setLayout(new FlowLayout(FlowLayout.CENTER,20,20));
this.setVisible(true);
}
/**
This method will be called on click of button to
reset all the parameters of the frame so that we
get fresh new frame, everything as it was before.
**/
public void resetAll(){
b=new Button("Reset");
p=new Panel(new FlowLayout(FlowLayout.CENTER,20,20));
p.add(b);
tf = new TextField("Edit And Reset");
p.add(tf);
b.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent ae){
remove(p); //remove the panel that contains all our components
resetAll(); // reset all the components
f.pack(); //refreshes the view of frame when everything is reset.
}
});
add(p);
}
}
class NewClass{
public static void main(String[] args) {
ResetTest fReset = new ResetTest();
}
}

Switch imageIcon in java?

I have many planes(threads) that move in window, and I want switch the ImageIcon according to the direction of the plane.
For example: if a plane goes to the right, the imageIcon of the plane is right and then plane goes to the left, exchange the imageIcon for the plane is left.
How can I do that in method paintComponent?
Sorry for my bad english.
If you're talking about swapping the ImageIcon displayed by a JLabel, then you should not switch ImageIcons in paintComponent but rather should do this in the non-paintComponent region of code, perhaps in a Swing Timer. Even if you're not talking about a JLabel, the paintComponent method should not be used for changing the state of an object.
Your question however leaves too much unsaid to allow us to be able to answer it completely and well. Consider telling and showing more.
If you are looking for a logic thingy, then a small example is here, though you might have to modify it for your needs.
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import java.util.Random;
import javax.swing.*;
public class FlyingAeroplane
{
private Animation animation;
private Timer timer;
private ActionListener timerAction = new ActionListener()
{
#Override
public void actionPerformed(ActionEvent ae)
{
animation.setValues();
}
};
private void displayGUI()
{
JFrame frame = new JFrame("Aeroplane Flying");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
animation = new Animation();
frame.setContentPane(animation);
frame.pack();
frame.setLocationByPlatform(true);
frame.setVisible(true);
timer = new Timer(100, timerAction);
timer.start();
}
public static void main(String... args)
{
SwingUtilities.invokeLater(new Runnable()
{
#Override
public void run()
{
new FlyingAeroplane().displayGUI();
}
});
}
}
class Animation extends JPanel
{
private final int HEIGHT = 150;
private final int WIDTH = 200;
private int x;
private int y;
private ImageIcon image;
private boolean flag;
private Random random;
public Animation()
{
x = 0;
y = 0;
image = new ImageIcon(getClass().getResource("/image/aeroplaneright.jpeg"));
flag = true;
random = new Random();
}
public void setValues()
{
x = getXOfImage();
y = random.nextInt(70);
repaint();
}
private int getXOfImage()
{
if (flag)
{
if ((x + image.getIconWidth()) == WIDTH)
{
flag = false;
x--;
return x;
}
x++;
image = new ImageIcon(getClass().getResource("/image/aeroplaneright.jpeg"));
}
else if (!flag)
{
if (x == 0)
{
flag = true;
x++;
return x;
}
x--;
image = new ImageIcon(getClass().getResource("/image/aeroplaneleft.jpeg"));
}
return x;
}
#Override
public Dimension getPreferredSize()
{
return (new Dimension(WIDTH, HEIGHT));
}
#Override
protected void paintComponent(Graphics g)
{
super.paintComponent(g);
g.drawImage(image.getImage(), x, y, this);
}
}
IMAGES USED :
On setting the direction you should set the image icon too, or have a getImageIcon(direction).
In the paintComponent no heavy logic should happen; it should be as fast as possible. You have no (total) control when and how often paintComponent is called.

Categories

Resources