平滑Java绘制动画

平滑Java绘制动画,java,multithreading,repaint,Java,Multithreading,Repaint,我想让我的应用程序绘制的运动图像比它当前绘制的运动图像更平滑一点。我不知道该怎么做 这是我的主要游戏线索的样子: @Override public void run(){ int delay = 500; //milliseconds ActionListener taskPerformer = new ActionListener(){ @Override public void actionPerformed(ActionEvent evt){

我想让我的应用程序绘制的运动图像比它当前绘制的运动图像更平滑一点。我不知道该怎么做

这是我的主要游戏线索的样子:

@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();
    }
}
这可能比需要的信息要多,但我想知道,我应该怎么做才能使项目从
左->右
上->下
尽可能平稳地移动,而不会造成太多性能损失

编辑:请求的SSCE:

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;
    }
}
封装sscce;
导入java.awt.Color;
导入java.awt.Graphics;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.util.ArrayList;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.Timer;
公共类Sscce扩展JPanel实现可运行{
ArrayList squares=新的ArrayList();
公共服务{
JFrame=新JFrame();
框架。设置尺寸(500500);
frame.setLocationRelativeTo(空);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
框架。添加(此);
螺纹t=新螺纹(此);
t、 start();
}
公共静态void main(字符串[]args){
新Sscce();
}
@凌驾
公开募捐{
int delay=500;//毫秒
ActionListener taskPerformer=新建ActionListener(){
@凌驾
已执行的公共无效操作(操作事件evt){
Square squ=新的Square();
Sscce.this.squares.add(squ);
squ.moveTo(0);
}
};
新计时器(延迟,taskPerformer).start();
while(true){
试一试{
对于(正方形s:这个。正方形){
int objX=s.getX();
int desX=s.getDestX();

如果(objX第一个注意事项,出于某种原因,我在MacOS下运行时遇到了
JPanel
实现
Runnable
的问题-我不知道为什么,但这就是我将其移出的原因

您的
方块在用于绘制时可能会被更新,这将导致异常(此外,在迭代时从列表中删除元素也不是一个好主意;)

相反,我有两个列表。我有一个模型,列表可以修改它,然后是绘制列表,方法可以使用
paint
。这允许线程在绘制过程中修改模型

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

现在,回到真正的问题。你面临的主要问题不是更新之间的时间长度,而是移动的距离。缩短距离(使其变慢)并停止更新

大多数人不会注意到任何超过25fps的事情,因此尝试做更多的事情只会浪费CPU周期,使重绘管理器处于饥饿状态,阻止它实际更新屏幕

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

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestAnimation11 extends JPanel {

    private ArrayList<Square> squares = new ArrayList<>();
    private ReentrantLock lock;

    public TestAnimation11() {
        lock = new ReentrantLock();
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }
                JFrame frame = new JFrame();
                frame.setSize(500, 500);
                frame.setLocationRelativeTo(null);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
                frame.add(TestAnimation11.this);
                Thread t = new Thread(new UpdateEngine());
                t.start();
            }
        });
    }

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

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Square[] paint = null;
        lock.lock();
        try {
            paint = squares.toArray(new Square[squares.size()]);
        } finally {
            lock.unlock();
        }
        for (Square s : paint) {
            g.setColor(Color.blue);
            g.fillRect(s.getX(), s.getY(), 50, 50);
        }
    }

    public class UpdateEngine implements Runnable {

        private List<Square> model = new ArrayList<>(squares);

        @Override
        public void run() {
            int ticks = 0;
            List<Square> dispose = new ArrayList<>(25);
            while (true) {
                ticks++;
                dispose.clear();
                for (Square s : model) {
                    int objX = s.getX();
                    int desX = s.getDestX();
                    if (objX <= desX) {
                        dispose.add(s);
                    } else {
                        s.setX(s.getX() - 2);
                    }
                }
                model.removeAll(dispose);
                if (ticks == 11) {
                    Square sqr = new Square();
                    sqr.moveTo(0);
                    model.add(sqr);
                } else if (ticks >= 25) {
                    ticks = 0;
                }
                lock.lock();
                try {
                    squares.clear();
                    squares.addAll(model);
                } finally {
                    lock.unlock();
                }
                repaint();
                try {
                    Thread.sleep(40);
                } catch (Exception e) {
                }
            }
        }
    }

    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;
        }
    }
}
导入java.awt.Color;
导入java.awt.EventQueue;
导入java.awt.Graphics;
导入java.util.ArrayList;
导入java.util.List;
导入java.util.concurrent.locks.ReentrantLock;
导入javax.swing.JFrame;
导入javax.swing.JPanel;
导入javax.swing.UIManager;
导入javax.swing.UnsupportedLookAndFeelException;
公共类TestAnimation11扩展了JPanel{
私有ArrayList squares=新ArrayList();
私有重入锁;
公开测试11(){
锁=新的可重入锁();
invokeLater(新的Runnable(){
@凌驾
公开募捐{
试一试{
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}catch(ClassNotFoundException |实例化Exception | IllegalacessException |不支持ookandfeelException ex){
}
JFrame=新JFrame();
框架。设置尺寸(500500);
frame.setLocationRelativeTo(空);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
框架。添加(测试11.本);
线程t=新线程(new UpdateEngine());
t、 start();
}
});
}
公共静态void main(字符串[]args){
新约11();
}
@凌驾
公共组件(图形g){
超级组件(g);
正方形[]油漆=空;
lock.lock();
试一试{
paint=squares.toArray(新的squares[squares.size()]);
}最后{
lock.unlock();
}
用于(方形s:油漆){
g、 setColor(Color.blue);
g、 fillRect(s.getX(),s.getY(),50,50);
}
}
公共类UpdateEngine实现Runnable{
私有列表模型=新的ArrayList(正方形);
@凌驾
公开募捐{
int ticks=0;
List dispose=新阵列列表(25);
while(true){
ticks++;
dispose.clear();
适用于(方形s:模型){
int objX=s.getX();
int desX=s.getDestX();
如果(objX=25){
滴答声=0;
}
lock.lock();
试一试{
正方形。清除();
squares.addAll(模型);
}最后{
lock.unlock();
}
重新油漆();
试一试{
睡眠(40);
}捕获(例外e){
}
}
}
}
阶级广场{
公共整数x=0,y=0,destX=0;
公众广场(){
这个.x=400;
这个y=100;
}
公共无效移动到(int destX){
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;
    }
}
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TestAnimation11 extends JPanel {

    private ArrayList<Square> squares = new ArrayList<>();
    private ReentrantLock lock;

    public TestAnimation11() {
        lock = new ReentrantLock();
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }
                JFrame frame = new JFrame();
                frame.setSize(500, 500);
                frame.setLocationRelativeTo(null);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
                frame.add(TestAnimation11.this);
                Thread t = new Thread(new UpdateEngine());
                t.start();
            }
        });
    }

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

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Square[] paint = null;
        lock.lock();
        try {
            paint = squares.toArray(new Square[squares.size()]);
        } finally {
            lock.unlock();
        }
        for (Square s : paint) {
            g.setColor(Color.blue);
            g.fillRect(s.getX(), s.getY(), 50, 50);
        }
    }

    public class UpdateEngine implements Runnable {

        private List<Square> model = new ArrayList<>(squares);

        @Override
        public void run() {
            int ticks = 0;
            List<Square> dispose = new ArrayList<>(25);
            while (true) {
                ticks++;
                dispose.clear();
                for (Square s : model) {
                    int objX = s.getX();
                    int desX = s.getDestX();
                    if (objX <= desX) {
                        dispose.add(s);
                    } else {
                        s.setX(s.getX() - 2);
                    }
                }
                model.removeAll(dispose);
                if (ticks == 11) {
                    Square sqr = new Square();
                    sqr.moveTo(0);
                    model.add(sqr);
                } else if (ticks >= 25) {
                    ticks = 0;
                }
                lock.lock();
                try {
                    squares.clear();
                    squares.addAll(model);
                } finally {
                    lock.unlock();
                }
                repaint();
                try {
                    Thread.sleep(40);
                } catch (Exception e) {
                }
            }
        }
    }

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