簡體   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