平滑Java绘制动画

时间:2013-03-10 23:42:16

标签: java multithreading repaint

我想让我的应用程序绘制移动图像比当前绘制它们的图像更平滑。我不知道该怎么办。

这就是我的主要游戏Thread的样子:

@Override
public void run(){
    int delay = 500; //milliseconds
    ActionListener taskPerformer = new ActionListener(){
        @Override
        public void actionPerformed(ActionEvent evt){
            Car car = new Car();
            int speed = (int)(3 + Math.floor(Math.random() * (6 - 3)));
            car.setSpeed(speed);
            MainLoop.this.gameObjects.vehicles.add(car.create("/Media/Graphics/blueCar.png", width - 20, 78));
            car.driveTo(0, 78);
        }
    };
    new Timer(delay, taskPerformer).start();
    try{
        while(true){
            this.repaint();
            for(GameObject go : this.gameObjects.vehicles){
                // loops through objects to move them
                Vehicle vh = (Vehicle) go;
                this.moveVehicle(vh);
                if(vh.getX() <= vh.getDestX()){
                    vh.markForDeletion(true);
                }
            }
            this.gameObjects.destroyVehicles();
            Thread.sleep(1);
        }
    }catch(Exception e){
        e.printStackTrace();
    }
}

这是一种计算下一个x / y位置项目的方法

protected void moveVehicle(Vehicle vh){
    int cx = vh.getX();
    int dx = vh.getDestX();
    int cy = vh.getY();
    int dy = vh.getDestY();
    // move along x axis
    // getMaxSpeed() = Number between 3 and 6
    if(cx > dx && vh.movingX() == -1){
        vh.setX(cx - vh.getMaxSpeed());
    }else if(cx < dx && vh.movingX() == 1){
        vh.setX(cx + vh.getMaxSpeed());
    }else{
        vh.setX(dx);
    }

    // move along y axis
    // getMaxSpeed() = Number between 3 and 6
    if(cy > dy && vh.movingY() == -1){
        vh.setY(cy - vh.getMaxSpeed());
    }else if(cy < dy && vh.movingY() == 1){
        vh.setY(cy + vh.getMaxSpeed());
    }else{
        vh.setY(dy);
    }
}

这是我的绘画方法:

@Override
public void paintComponent(Graphics graphics){
    super.paintComponent(graphics);
    Graphics2D g = (Graphics2D) graphics;

    for(GameObject go : gameObjects.vehicles){
        g.drawImage(go.getSprite(), go.getX(), go.getY(), this);
    }
}

这可能比需要更多信息,但我想知道,我应该怎么做才能让项目尽可能顺利地从left -> right top -> bottom移动,而不会造成太多性能损失?< / p>

编辑:请求的sscce:

package sscce;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Sscce extends JPanel implements Runnable{

    ArrayList<Square> squares = new ArrayList<>();

    public Sscce(){
        JFrame frame = new JFrame();
        frame.setSize(500, 500);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setVisible(true);
        frame.add(this);
        Thread t = new Thread(this);
        t.start();
    }

    public static void main(String[] args){
        new Sscce();
    }

    @Override
    public void run(){
        int delay = 500; //milliseconds
        ActionListener taskPerformer = new ActionListener(){
            @Override
            public void actionPerformed(ActionEvent evt){
                Square squ = new Square();
                Sscce.this.squares.add(squ);
                squ.moveTo(0);
            }
        };
        new Timer(delay, taskPerformer).start();
        while(true){
            try{
                for(Square s : this.squares){
                    int objX = s.getX();
                    int desX = s.getDestX();
                    if(objX <= desX){
                        System.out.println("removing");
                        this.squares.remove(s);
                    }else{
                        s.setX(s.getX() - 10);
                    }
                }
                this.repaint();
                Thread.sleep(30);
            }catch(Exception e){
            }
        }
    }

    @Override
    public void paintComponent(Graphics g){
        super.paintComponent(g);
        for(Square s : squares){
            g.setColor(Color.blue);
            g.fillRect(s.getX(), s.getY(), 50, 50);
        }
    }
}

class Square{

    public int x = 0, y = 0, destX = 0;

    public Square(){
        this.x = 400;
        this.y = 100;
    }

    public void moveTo(int destX){
        this.destX = destX;
    }

    public int getX(){
        return this.x;
    }
    public int getDestX(){
        return this.destX;
    }

    public void setX(int x){
        this.x = x;
    }

    public int getY(){
        return this.y;
    }
}

1 个答案:

答案 0 :(得分:1)

首先请注意,由于某种原因,我在{(1}}在MacOS下运行JPanel时遇到问题 - 我不知道为什么,但这就是我将其移出的原因。

你的Runnable有可能在用于绘制哪个会导致异常时进行更新(同样,在你迭代时从列表中删除元素也不是一个好主意; ))

相反,我有两个清单。我有一个模型,列表可以修改,然后是squares方法可以使用的绘制列表。这允许线程修改模型,同时正在进行绘制过程。

为了防止任何冲突,我添加了一个锁,这可以防止一个线程修改/访问绘制列表,而另一个线程将其锁定。

现在。直到真正的问题。您遇到的主要问题不是更新之间的时间量,而是您移动的距离。减少距离(使其变慢)并使更新标准化。

大多数人都不会注意到超过25fps的任何东西,所以尝试做更多的事情只是浪费CPU周期并使重绘管理器挨饿,阻止它实际更新屏幕。

这是一个平衡的行为,以确保......

paint