views:

942

answers:

5

hello , my final goal for this application is to animate several items in the same JPanel at a different speed using a thread for each item.the first part is done however the items move at the same speed and i have no idea on how to fix this problem.

package javagamestutos;



import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Toolkit;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JPanel;


public class Board extends JPanel implements Runnable {


    private Star star;
    private Thread animator;
    ArrayList<Star> items=new ArrayList<Star>();


    public Board() {
        setBackground(Color.BLACK);
        setDoubleBuffered(true);
        star=new Star(25,0,0);
        Star star2=new Star(50,20,25);
        items.add(star2);
        items.add(star);
    }

    public void addNotify() {
        super.addNotify();
        animator = new Thread(this);
        animator.start();
    }

    public void paint(Graphics g) {
        super.paint(g);

        Graphics2D g2d = (Graphics2D)g;



        for (Star s : this.items) {
            g2d.drawImage(s.starImage, s.x, s.y, this);
        }


        Toolkit.getDefaultToolkit().sync();
        g.dispose();
    }

    public void run() {

        while(true){
            try {
                for (Star s : this.items) {
                    s.move();
                }
                repaint();

                Thread.sleep(star.delay);
            } catch (InterruptedException ex) {
                Logger.getLogger(Board.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }


}

here is the star class wich is the moving item.

package javagamestutos;

import java.awt.Image;
import javax.swing.ImageIcon;

/**
 *
 * @author fenec
 */
public class Star {
    Image starImage;
    int x,y;
    int destinationX=200,destinationY=226;
    boolean lockY=true;
    int delay;


    public Star(int delay,int initialX,int initialY){
        ImageIcon ii = new ImageIcon(this.getClass().getResource("star.png"));
        starImage = ii.getImage();
        x=initialX;
        y=initialY;
        this.delay=delay;
    }


    void moveToX(int destX){
        this.x += 1;
    }


    boolean validDestinatonX(){
        if(this.x==this.destinationX){
                this.lockY=false;
                return true;
            }
        else
            return false;
    }

    void moveToY(int destY){
        this.y += 1;
    }


    boolean validDestinatonY(){
        if(this.y==this.destinationY)
            return true;
        else
            return false;
    }

    void move(){

        if(!this.validDestinatonX() )
            x+=1;
        if(!this.validDestinatonY() && !this.lockY)
            y+=1;

        /*if(!this.validDestinatonY())
            y+=1;
        */
    }


}

and here is the skeleton of the animation that extends a JFrame :

package javagamestutos;
import javax.swing.JFrame;

public class Skeleton extends JFrame {

public Skeleton() {
        add(new Board());
        setTitle("Stars");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setSize(300, 280);
        setLocationRelativeTo(null);
        setVisible(true);
        setResizable(false);
    }
    public static void main(String[] args) {
        new Skeleton();
    }
}

do you have any idea how to achieve my goals?am i using threads proprely? thank you in advance.

A: 

You should be painting in the AWTDispatchThread. To do that you will want to use something like SwingUtilities.invokeLater(Runnable); This applies not only to your animation, but to the creation and setting visible of your JFrame as well. Failing to do this could result in deadlocks with the painting thread. Also, when moving your painting operations into the SwingUtilites methods, you will not want to include any while(true) loops, as that will commandeer your painting thread.

akf
"your Board is not a Runnable, so your animator = new Thread(this) shouldn't compile."er... yes it is. `public class Board extends JPanel implements Runnable`
R. Bemrose
Yes, I edited as you were typing your comment. I saw it once you reformatted. Too bad we can upvote post edits.
akf
A: 

if you are sure you want to paint in the threads, you can use :

update(getGraphics());

instead of repaint. this is generally considered bad practice, as you normally paint stuff in the AWT thread.

Omry
@You are right about that, but that's not the reason why they move at the same speed.
OscarRyz
right.I think you problem is that you sleep a constant time for each iteration.what you want is to move your object a variable distance (you can pass dx and dy in the ctor) and sleep a constant time (say 40ms for 25 fps).
Omry
A: 

Generally Swing components should be used from the AWT Event Dispatch Thread (EDT). repaint is one of the methods that is supposedly okay to use off EDT. However, your Star is not and should not be thread-safe.

The easiest approach is to go for EDT-only (at least to start with). Instead of using Thread use javax.swing.Timer which fires on the EDT.

Misc comments: There should be no need for your paint method to dispose of the graphics object sent to it, or for it to sync using Toolkit. The component need not be set to double-buffered, but should be set opaque (JPanel is not guaranteed to be opaque). You should just extend JComponent instead of JPanel, as this is not a panel. It's generally not a great idea for outer classes to implement Runnable. Prefer private variables.

Tom Hawtin - tackline
+1  A: 
OscarRyz
+1 for answering the question. :) Could use the a single thread, but use, say a priority queue to find the next star to move, or some other random algorithm (like calculating position from time, rather than storing position).
Tom Hawtin - tackline
+1  A: 

I would suggest you take a look at the open source library trident which does just that, its author, Kirill Grouchnikov is well-known in the Swing world (he is the author of the famous Substance look & feel).

Trident should help you solve the problem of having different objects move at different speeds, without having to create one thread per object (which is a problem in the end).

jfpoilpret