繁体   English   中英

使用java swing进行多线程处理以获得简单的2D动画

[英]multithreading with java swing for a simple 2d animation

我对这个应用程序的最终目标是使用每个项目的线程以不同的速度为同一JPanel中的几个项目制作动画。第一部分完成但是项目以相同的速度移动,我不知道如何解决这个问题。

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);
            }
        }
    }


}

这里是星级,它是移动物品。

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;
        */
    }


}

这是扩展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();
    }
}

你知道如何实现我的目标吗?我是否真的使用线程? 先感谢您。

那是因为你以第一个“开始”延迟指定的固定速率调用“移动”方法

  Thread.sleep(star.delay);

因此,如果你每隔“n”毫秒移动一下它们,它们似乎会在同样的平静中移动。

如果你想让它们以不同的速度移动,你必须在不同的线程中移动它们(你现在只使用一个)请记住omry的注释,

编辑

我最近做了类似的事

我有两个不同的东西,所以动画,所以我有两个定时器(定时器使用下面的线程,但他们可以每个固定的速率重复执行代码)。

第一个将文本应用于JLabel每秒(1000毫秒)

    final Timer timer = new Timer();
    timer.scheduleAtFixedRate( new TimerTask() {
        public void run(){      
            setText();
        }
    }, 0, 1000 );

其他每隔10秒(10,000毫秒)更改显示图像

    final Timer imageTimer = new Timer();
    imageTimer.scheduleAtFixedRate( new TimerTask() {
        public void run() {
            setImage();
        }
    }, 0, 10000 );

我在这里有一个结果视频:

在此输入图像描述

对于更高级(和更好)的时间管理,您必须查看“时序框架”项目,该项目为计时器增加了额外的功能。

你应该在AWTDispatchThread中绘画。 要做到这一点,你会想要使用像SwingUtilities.invokeLater(Runnable); 这不仅适用于您的动画,也适用于JFrame的创建和设置。 如果不这样做可能会导致绘制线程出现死锁。 此外,在将绘制操作移动到SwingUtilites方法中时,您不希望包含任何while(true)循环,因为这将占用您的绘制线程。

通常,应使用AWT事件调度线程(EDT)中的Swing组件。 repaint是可以在EDT上使用的方法之一。 但是,您的Star不是也不应该是线程安全的。

最简单的方法是仅限EDT(至少从一开始)。 而不是使用Thread使用在EDT上触发的javax.swing.Timer

其他评论:您的paint方法不需要处理发送给它的图形对象,也不需要使用Toolkit进行同步。 组件不需要设置为双缓冲,但应设置为不透明( JPanel不保证不透明)。 您应该只扩展JComponent而不是JPanel ,因为这不是一个面板。 外部类实现Runnable通常不是一个好主意。 首选私有变量。

我建议你看一下开源库三叉戟就是这样,它的作者Kirill Grouchnikov在Swing世界中很有名(他是着名的Substance外观和感觉的作者)。

Trident应该帮助您解决让不同对象以不同速度移动的问题,而不必为每个对象创建一个线程(这最终是一个问题)。

如果您确定要在线程中绘画,可以使用:

update(getGraphics());

而不是重画。 这通常被认为是不好的做法,因为你通常在AWT线程中绘制东西。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM