0

I have 2 jcomponents, animation and gardenpanel. I have them in a jlayeredpane but the animation class is a character that always keeps moving. Whenver I call repaint in the main method It is very choppy and slow. So I made a new class called Update which would implement runnable and start a new thread only calling animation.repaint(). but it is still clow and choppy. any help?

public class Driver {

    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run(){

                 JFrame frame = new JFrame();
                    JLayeredPane pane = new JLayeredPane();
                    Animation animation = new Animation();

                GardenPanel gPanel = new GardenPanel(6,4,600,800);



                frame.setSize(800,600);
                frame.add(pane);
                // establish transparent background
                //Color transparent = new Color(0,0,0,0);

                // Initilize jcomponents
                //Garden garden = new Garden(6,4); 

                //making jcomponents visible
                animation.setSize(frame.getSize());
                gPanel.setSize(frame.getSize());


                animation.setOpaque(true);
                pane.add(animation);
                pane.add(gPanel);
                 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setVisible(true);


            }

        });

-------Animation Class-------

package view;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;



  public class Animation extends JComponent implements MouseMotionListener, MouseListener{
    final int frameCount = 10;
    int picNum = 0;
    BufferedImage[][] pics;
    int xloc = 0;
    int yloc = 0;
    final int xIncr = 8;
    final int yIncr = 2;
    final static int frameWidth = 900;
    final static int frameHeight = 600;
    final static int imgWidth = 165;
    final static int imgHeight = 165;
    //basic info about the orc
    Color c = new Color(0, 0, 0, 0);

    BufferedImage seedImage; 
    int mouseX;
    int mouseY;
    int seedX = xloc+imgWidth/2;
    int seedY = yloc+imgHeight/2;
    int shootX;
    int shootY;
    boolean seedShooting = false;
    boolean mouseholding;
    boolean moving = false;
    int power;
    public enum stage {
        MOVE, POWER
    }
    stage s;
    int seedPower;
    long pSeedTime;
    long cSeedTime;
    double seedPowerRatio = 0.75;

    //Override this JPanel's paint method to cycle through picture array and draw images
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        picNum = (picNum + 1) % frameCount;
        if(mouseholding && (s == s.POWER)){
            System.out.println(power++);
        }
        if(seedShooting){
            cSeedTime = System.currentTimeMillis();

            seedX = (int) ( seedPowerRatio * 1*seedPower*1.5*(cSeedTime - pSeedTime)/50 + shootX ); // calculate x-coor of seed
            seedY = (int) ( seedPowerRatio * (-1)*seedPower*1.5*((int)(cSeedTime - pSeedTime))/50 + 0.5*0.02*(cSeedTime - pSeedTime)*(cSeedTime - pSeedTime)/(50^2) +shootY);   
            //calculate y-coor of seed
        }
        if(seedY>shootY+imgWidth/4){
            seedShooting = false;
            seedX = xloc+imgWidth/2;
            seedY = yloc+imgHeight/2;
        }
        g.drawImage(pics[1][picNum], xloc, yloc, c, this);
        g.drawImage(seedImage, seedX, seedY, imgWidth/8, imgHeight/8, this);
    }



    //Constructor: get image, segment and store in array
    public Animation(){
        seedImage = createImage(); ;
        BufferedImage[] img = createAnimation();
        pics = new BufferedImage[img.length][10];
        for(int j = 0; j < img.length; j++){
            for(int i = 0; i < frameCount; i++)
                pics[j][i] = img[j].getSubimage(imgWidth*i, 0, imgWidth, imgHeight);
        }
        addMouseMotionListener(this);
        addMouseListener(this);

        Thread background = new Thread(new Background());
        //background.setDaemon(true);
        background.start();

    }  

    //Read image from file and return
    private BufferedImage[] createAnimation(){
        BufferedImage[] bufferedImage = new BufferedImage[4];
        try {
            bufferedImage[0] = ImageIO.read(new File("images/orc_forward_southeast.png"));
            bufferedImage[1] = ImageIO.read(new File("images/orc_forward_southwest.png"));
            bufferedImage[2] = ImageIO.read(new File("images/orc_forward_northeast.png"));
            bufferedImage[3] = ImageIO.read(new File("images/orc_forward_northwest.png"));
            return bufferedImage;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    private BufferedImage createImage(){
        BufferedImage bufferedImage;
        try {
            bufferedImage = ImageIO.read(new File("images/seed.png"));
            return bufferedImage;
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;

        // TODO: Change this method so you can load other orc animation bitmaps
    }

    // implement the method in mouseListener and mouseMotionListener interface
    @Override
    public void mouseDragged(MouseEvent event) {
        mouseX = event.getX();
        mouseY = event.getY();
        if( ( xloc<mouseX ) && (xloc+imgWidth >mouseX) && (yloc<mouseY) && (yloc+imgHeight>mouseY) && (s==stage.MOVE) ){
            //System.out.println("Imagecoor:("+xloc+", "+yloc+")"+" mousecoor:("+mouseX+","+mouseY+")"); 
            // you can print the coordinate if you want     
            //xloc = mouseX-imgWidth/2;
            yloc = mouseY-imgHeight/2;
            seedX = xloc + imgWidth/2;
            seedY = yloc + imgHeight/2;
        }   
    } // draging the image
    @Override
    public void mouseMoved(MouseEvent arg0) {
    }
    @Override
    public void mouseClicked(MouseEvent e) {
    }
    @Override
    public void mouseEntered(MouseEvent e) {    
    }
    @Override
    public void mouseExited(MouseEvent e) { 
    }

    // for increasing the power.
    @Override
    public void mousePressed(MouseEvent event) { 
        mouseholding = true;
        mouseX = event.getX();
        mouseY = event.getY();
        if((xloc+imgWidth/2+1> mouseX) && (xloc-imgWidth/2-1< mouseX)&&(yloc+imgHeight/2+1 > mouseY)&&(yloc-imgHeight/2-1 < mouseY)  ){     
            s = stage.POWER;
        }
    }
    @Override
    public void mouseReleased(MouseEvent event) {
        mouseholding = false;
        if(s == stage.POWER){
            pSeedTime = System.currentTimeMillis();
            seedPower = power;
            shootX = seedX;
            shootY = seedY;
            seedShooting = true;
        }
        s = stage.MOVE;
        power = 0;
    }

    protected class Background implements Runnable{

        @Override
        public void run() {
            while(true){

                repaint();


            }
        }


    }
user2510809
  • 235
  • 1
  • 13
  • 1
    You're showing us code, but not code that has bearing on the quality of your animation. Consider showing the pertinent code for this. – Hovercraft Full Of Eels Nov 03 '13 at 23:41
  • 1
    Also, if your Update class works without passing references into it, then that suggests that you've got some things static that should not be static. Also note that all Swing calls should be made on the event thread. – Hovercraft Full Of Eels Nov 03 '13 at 23:42
  • How often are you updating? Are they regular intervals? How far are you moving between intervals? Are they regular movements? – MadProgrammer Nov 03 '13 at 23:43
  • 1
    You could take a look at [this example](http://stackoverflow.com/questions/12642852/the-images-are-not-loading/12648265#12648265) and [this example](http://stackoverflow.com/questions/13022754/java-bouncing-ball/13022788#13022788) and [this example](http://stackoverflow.com/questions/14886232/swing-animation-running-extremely-slow/14902184#14902184) which all deal with animation of a large number of objects... – MadProgrammer Nov 03 '13 at 23:44
  • 1
    Swing components are made transparent through the use `setOpaque` not there background colors. This will cause issues with paint system – MadProgrammer Nov 04 '13 at 00:00
  • I included the animation class. I implemented runnable in the animation class and cause it to repaint but now it draws the character on top of each other. is this because of jlayeredpane? – user2510809 Nov 04 '13 at 00:38
  • 1
    Overriding `paint` is a really bad idea, not calling `super.paint` is even worse. `JComponent` is transparent by default, failing to call `super.paint` is going to screw up Swing's ability to ensure that the content beneath this component is rendered properly take a look at [Performing Custom Painting](http://docs.oracle.com/javase/tutorial/uiswing/painting/) for more details about painting in Swing – MadProgrammer Nov 04 '13 at 00:54
  • It is never okay to call a Swing API function from anything except the UI thread. It is not a thread safe library. You must use `SwingUtilities.invokeLater` to repaint from another thread. If that other thread is changing data structures needed for painting, you must synchronize access between the two. Swing timers are the most portable way to do smooth animation. – Gene Nov 04 '13 at 00:58
  • @Gene While certainly good advice, there are few safe methods, `repaint` happens to be one. `repaint` pushes a `paint` event onto the event queue, which means the actual event is processed by and on the EDT... – MadProgrammer Nov 04 '13 at 01:01
  • @MadProgrammer: I'm not sure if repaint is safe. It certainly *was* safe in past iterations, but with the current version, I'm not so sure. – Hovercraft Full Of Eels Nov 04 '13 at 01:13
  • @HovercraftFullOfEels Thanks for throwing me completely into a state of confusion...just when I thought I had a grip on this :P – MadProgrammer Nov 04 '13 at 01:15
  • I included super.repaint in all my components but the animation is still really slow. the character is walking but very slow. if overriding paint is a bad idea then how else would you go about it? – user2510809 Nov 04 '13 at 01:17
  • 1
    @HovercraftFullOfEels Based on the source I have available from Java 7, it appears that `repaint` basically calls `Toolkit.getEventQueue().postEvent(e);` This doesn't change the fact that Java 8 might change this...yea for me :P – MadProgrammer Nov 04 '13 at 01:18
  • @user2510809 If you read through the linked tutorial, you will see that `paintComponent` is the preferred method for performing custom painting – MadProgrammer Nov 04 '13 at 01:19
  • I made the Necessary changes to the Animation class. I implemented a thread in the animation class and used thread safe practices in the main. but now the character is getting painted on top of himself really fast. i don't understand why it is doing this. any suggestions? – user2510809 Nov 04 '13 at 01:57
  • @MadProgrammer That's okay if you trust the implementation. I've had enough troubles to distrust it. Others agree. For example see https://www.java.net//node/670386 – Gene Nov 04 '13 at 03:55
  • @Gene I for way, just do EVERYTHING UI related in the EDT - to tired to try and really figure what is and isn't thread safe ;) – MadProgrammer Nov 04 '13 at 04:02
  • Here's the problem. We can't run your code. Unless you can provide a runnable example, it's going to be next to impossible to work it out... – MadProgrammer Nov 04 '13 at 04:03

1 Answers1

1
Thread background = new Thread(new Background());
    //background.setDaemon(true);
    background.start();

And Your Background() runnable code:

protected class Background implements Runnable{

        @Override
        public void run() {
            while(true){ <-- it is true, true and true, who is changing it?

                repaint();


            }
        }

Calling repaint() request forever, no ending, no sleep control. How many cycle is going to happen in the processor ? When will your processor have some rest to talk with other computation unit?

Sage
  • 14,688
  • 3
  • 28
  • 34
  • I just inserted thread.sleep into my code like i did in your example. My problem is that the character is moving fine but he keeps getting repainted on top of itself so there are multiple images of him that keep multiplying. I thought when I called repaint it would repaint the character, not paint another one on top of the old one. any help? – user2510809 Nov 04 '13 at 04:42
  • @user2510809. yes we want to help. But If you don't respond to given answer in your previous post, no comment no thanks not even accepting the answers, many people will start avoiding to answer your question. Please, don't get me wrong but this is the way this site works- `responding upon help from each other` – Sage Nov 04 '13 at 05:42