流畅的动画效果在java中的快速移动的物体 [英] smooth animation in java for fast moving objects

查看:2377
本文介绍了流畅的动画效果在java中的快速移动的物体的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创造球简单的动画在屏幕的一侧移动到另一不同速度。问题在于球的更高的速度,我可以看到球的明显抖动,实际上它是很难解释的,但像我看得出重绘时球的一部分仍然在previous一步。

我曾尝试一些事情,包括:


  1. 本机摇摆动画使用第一个线程/睡眠/ repain,然后转移到计时器


  2. 切换到JavaFX的画布/窗格秋千JFrame的内部。尝试都转换和AnimationTimer


  3. 与CreateBufferStrategy修修补补,对于1,2,3 - 说实话还没有看到任何区别(也许我做错了什么......)


我的问题我怎么能提高平滑度和我想要实现是否​​有可能与本地Java或者最好是使用一些外部库?如果这样你可以推荐一下吗?

下面显示我的例子code为第二/第三尝试。

 进口java.awt.Dimension中;
进口java.awt.GraphicsDevice中;
进口java.awt.GraphicsEnvironment;进口javafx.animation.Interpolator;
进口javafx.animation.Timeline;
进口javafx.animation.TranslateTransition;
进口javafx.application.Platform;
进口javafx.embed.swing.JFXPanel;
进口javafx.scene.Group;
进口javafx.scene.Scene;
进口javafx.scene.canvas.Canvas;
进口javafx.scene.paint.Color;
进口javafx.scene.shape.Circle;
进口javafx.util.Duration;
进口javax.swing.JFrame中;公共类FXTrackerPanel扩展的JFrame {    / **
     *
     * /
    私有静态最后的serialVersionUID长1L =;
    公众诠释crSize = 30;
    公共双XPOS = crSize;
    公共双yPos = 100;
    公众诠释xSize = 100;
    公众诠释ySize = 100;
    公共圆R;
    INT DIR = 1;    公共无效updateScreenSize(){
        INT屏幕= 0;
        GraphicsEnvironment中GE = GraphicsEnvironment中
            .getLocalGraphicsEnvironment();
        GraphicsDevice的[] GS = ge.getScreenDevices();
        如果(屏幕-1个和放大器;&安培;屏幕< gs.length)
        {
            xSize = GS [画面] .getDisplayMode()的getWidth()。
            ySize = GS [画面] .getDisplayMode()的getHeight()。
        }
        否则如果(gs.length大于0)
        {
            xSize = GS [0] .getDisplayMode()的getWidth();
            ySize = GS [0] .getDisplayMode()的getHeight();
        }
        其他
        {
            抛出新的RuntimeException(没有找到屏幕);
        }        yPos = ySize / 2;
    }    私人无效initFXPanel(JFXPanel fxPanel){
        updateScreenSize();
        XPOS = crSize;        组root =新集团();        双速= 5;        INT重复= Timeline.INDEFINITE;        R =新javafx.scene.shape.Circle(XPOS,yPos,crSize / 2,Color.RED);
        TranslateTransition TT =新TranslateTransition(Duration.seconds(速度),R);
        tt.setFromX(XPOS);
        tt.setToX(xSize - crSize * 3);
        tt.setCycleCount(重复);
        tt.setAutoReverse(真);
        tt.setInterpolator(Interpolator.EASE_BOTH);
        tt.play();        。root.getChildren()加(R);//新AnimationTimer(){
//
// @覆盖
//公共无效手柄(长今){
//双速= 20;
//尝试{
//速度= Double.valueOf(TETSimple.mp.speedSinus.getText());
//}
//赶上(例外前){
//速度= 20;
//}
//双xMov =(速度* 4 * Math.sin(XPOS * Math.PI / xSize));
//如果(xMov< = 0){
// xMov = 1;
//}
//如果(DIR == 1){
//如果(XPOS> = xSize - crSize)
// DIR = 0;
// XPOS + = xMov;
//}其他{
//如果(XPOS&L​​T; = 1)
// DIR = 1;
// XPOS - = xMov;
//}
//
// r.setTranslateX(XPOS);
//}
//}。开始();        fxPanel.setScene(新场景(根));
    }    公共FXTrackerPanel(){
        updateScreenSize();
        this.setSize(新尺寸(xSize,ySize));
        this.set preferredSize(新尺寸(xSize,ySize));
        this.setVisible(真);
        this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        JFXPanel fxPanel =新JFXPanel();
        this.add(fxPanel);
        this.createBufferStrategy(3);        Platform.runLater(新的Runnable(){            @覆盖
            公共无效的run(){
                initFXPanel(fxPanel);
            }
        });
    }    公共静态无效的主要(字串[] args)
    {
        新FXTrackerPanel();
    }
}

在这里,比如挥杆code:

 进口java.awt.Color中;
进口java.awt.Dimension中;
进口java.awt.Graphics;
进口java.awt.Graphics2D中;
进口java.awt.GraphicsDevice中;
进口java.awt.GraphicsEnvironment;
进口java.awt.RenderingHints中;
进口java.awt.Shape中;
进口java.awt.event.ActionEvent中;
进口java.awt.event.ActionListener;
进口java.awt.geom.Ellipse2D;进口javax.swing.JPanel中;
进口javax.swing.Timer中;进口java.lang.Math中;
进口了java.util.Random;公共类TrackerPanel继承JPanel实现的ActionListener {
    / **
     *
     * /
    私有静态最后的serialVersionUID长1L =;
    CR形状;
    颜色为c;
    公众诠释crSize = 30;
    公共双XPOS = crSize;
    公共双yPos = 100;
    公共双XPOS preV = crSize;
    公共双yPos preV = 100;
    公众诠释xSize = 100;
    公众诠释ySize = 100;
    INT DIR = 1; // 剩下
    INT定时器= 50; // 50 - 罪,1500 - 线性
    INT方法= 1; // 1 - 跳,2 - 窦
    INT timeToChange = 1000;
    INT通行证= 0;
    定时器TT;
    布尔clickedClose = FALSE;
    私人INT重复= 0;    //笔 - 计时器的时间间隔,米 - 球的运动方法:​​1 - 跳,2 - 窦
    公共TrackerPanel(INT T,INT M){
        this.set preferredSize(新尺寸(300,200));
        this.timer = T;
        this.method =米;
        C = Color.red;
        重绘();
        this.updateScreenSize();
        TT =新的Timer(T,NULL);
        tt.addActionListener(本);
        tt.start();
    }    公共无效updateScreenSize(){
        INT屏幕= TETSimple.suppMonitor;
        GraphicsEnvironment中GE = GraphicsEnvironment中
                .getLocalGraphicsEnvironment();
        GraphicsDevice的[] GS = ge.getScreenDevices();
        如果(屏幕-1个和放大器;&安培;屏幕< gs.length){
            xSize = GS [画面] .getDisplayMode()的getWidth()。
            ySize = GS [画面] .getDisplayMode()的getHeight()。
        }否则如果(gs.length大于0){
            xSize = GS [0] .getDisplayMode()的getWidth();
            ySize = GS [0] .getDisplayMode()的getHeight();
        }其他{
            抛出新的RuntimeException(没有找到屏幕);
        }        yPos = ySize / 2;
        yPos preV = ySize / 2;
    }    公共无效的actionPerformed(ActionEvent的为arg0){
        如果(方法== 1)
            lineMovement();
        其他
            sinusMovement();
        重绘(0,ySize / 2,xSize,crSize);
    }    私人双parseText2Int(字符串文字){
        尝试{
            返回Double.valueOf(字面);
        }赶上(例外前){
            ex.printStackTrace();
        }
        返回10.0;
    }    私人无效checkFinishCondition(){
        如果(传球+ 1>重复和放大器;&安培;!=重复0){
            如果(!clickedClose){
                TETSimple.mp.bStop.doClick();
                clickedClose = TRUE;
            }
            返回;
        }
    }    私人无效sinusMovement(){
        this.updateScreenSize();
        。this.repeats = parseText2Int(TETSimple.mp.repeatsCount.getText())的intValue();
        checkFinishCondition();        倍速= parseText2Int(TETSimple.mp.speedSinus.getText());
        双xMov =(速度* Math.sin(XPOS * Math.PI / xSize));
        如果(xMov&下; = 0){
            xMov = 1;
        }
        如果(DIR == 1){
            如果(XPOS> = xSize - crSize)
                DIR = 0;
            XPOS preV = XPOS;
            XPOS + = xMov;
        }其他{
            如果(XPOS&下; = 1 + crSize){
                DIR = 1;
                通行证++;
            }
            XPOS preV = XPOS;
            XPOS - = xMov;
        }
    }    私人无效lineMovement(){
        。this.repeats = parseText2Int(TETSimple.mp.repeatsCount.getText())的intValue();
        checkFinishCondition();        双左= crSize;
        双中心= xSize / 2 - crSize * 1.5;
        双右= xSize - crSize * 2;
        随机R =新的随机();        如果(timeToChange&下; = 0){
            通行证++;
            如果(XPOS == ||左XPOS ==右){
                timeToChange = 300 + r.nextInt(12)* 100;
                XPOS =中心;
            }否则如果(XPOS ==中心){
                timeToChange = 300 + r.nextInt(7)* 100;
                如果(r.nextBoolean())
                    XPOS =左;
                其他
                    XPOS =权利;
            }
        }其他{
            timeToChange - = 100;
        }
    }    公共无效的paintComponent(图形G){
        super.paintComponent方法(G);
        Graphics2D的G2D =(Graphics2D的)g.create();
        g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_DITHERING,RenderingHints.VALUE_DITHER_ENABLE);
        g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,RenderingHints.VALUE_STROKE_PURE);
        g2d.setColor(Color.green);
        g2d.fill(新Ellipse2D.Double(XPOS,yPos,crSize,crSize));
        g2d.dispose();
    }
}


解决方案

这是很难知道没有一个可运行的例子究竟什么可能会出错,但我想,在这里就可以了,切忌混JavaFX和摇摆,因为他们有不同的渲染机制。

下面是一个非常简单的例子,它只是增加球的速度通过​​简单地改变由它们每次更新移动的量被动画...

 进口java.awt.BorderLayout中;
进口java.awt.Color中;
进口java.awt.Dimension中;
进口java.awt.EventQueue中;
进口java.awt.Graphics;
进口java.awt.Graphics2D中;
进口java.awt.GridBagConstraints中;
进口java.awt.GridBagLayout中;
进口java.awt.RenderingHints中;
进口java.awt.event.ActionEvent中;
进口java.awt.event.ActionListener;
进口的java.util.ArrayList;
进口的java.util.List;
进口javax.swing.JFrame中;
进口javax.swing.JLabel中;
进口javax.swing.JPanel中;
进口javax.swing.JSlider中;
进口javax.swing.Timer中;
进口javax.swing.UIManager中;
进口javax.swing.UnsupportedLookAndFeelException;
进口javax.swing.event.ChangeEvent;
进口javax.swing.event.ChangeListener;公共类BouncyBall {    公共静态无效的主要(字串[] args){
        新BouncyBall();
    }    公共BouncyBall(){
        EventQueue.invokeLater(新的Runnable(){
            @覆盖
            公共无效的run(){
                尝试{
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                }赶上(ClassNotFoundException的| InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException前){
                    ex.printStackTrace();
                }                JFrame的帧=新的JFrame(测试);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(新ControlPane());
                frame.pack();
                frame.setLocationRelativeTo(NULL);
                frame.setVisible(真);
            }
        });
    }    公共类ControlPane继承JPanel {        私人JSlider的速度;
        JSlider的私人控管数量;        私人BallPitPane ballPitPane;        公共ControlPane(){
            的setLayout(新的BorderLayout());
            ballPitPane =新BallPitPane();
            加(ballPitPane);            JPanel的控制=新JPanel(新的GridBagLayout());
            GridBagConstraints的GBC =新的GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.anchor = GridBagConstraints.WEST;            速度=新JSlider的(1,100,4);
            控管数量=新JSlider的(1,100,1);            Controls.Add被(新的JLabel(速度),GBC);
            gbc.gridy ++;
            Controls.Add被(新的JLabel(控管数量),GBC);            gbc.gridx ++;
            gbc.gridy = 0;
            gbc.weightx = 1;
            gbc.fill = GridBagConstraints.HORIZONTAL;            Controls.Add被(速度,GBC);
            gbc.gridy ++;
            Controls.Add被(控管数量,GBC);
            添加(对照组,BorderLayout.SOUTH);            speed.addChangeListener(新的ChangeListener(){
                @覆盖
                公共无效stateChanged(的ChangeEvent发送){
                    ballPitPane.setSpeed​​(speed.getValue());
                }
            });            quanity.addChangeListener(新的ChangeListener(){
                @覆盖
                公共无效stateChanged(的ChangeEvent发送){
                    ballPitPane.setQuanity(quanity.getValue());
                }
            });
        }    }    公共类BallPitPane继承JPanel {        私人列表<&球GT;球;
        私人诠释速度;        公共BallPitPane(){
            球=新的ArrayList<>(25);
            (2)setSpeed​​;
            setQuanity(1);            定时器定时器=新定时器(40,新的ActionListener(){
                @覆盖
                公共无效的actionPerformed(ActionEvent的五){
                    对于(球球:球){
                        ball.update(的getWidth(),速度);
                    }
                    重绘();
                }
            });
            timer.start();
        }        公共无效setSpeed​​(INT速度){
            this.speed =速度;
        }        公共无效setQuanity(INT控管数量){            而(balls.size()>售后服务第一!){
                balls.remove(0);
            }
            而(balls.size()<控管数量){
                INT半径= 4 +(INT)(的Math.random()* 48);
                球球=新球(
                        randomColor(),
                        (INT)Math.abs(的Math.random()*的getWidth() - 半径),
                        (INT)Math.abs(的Math.random()*的getHeight() - 半径),
                        半径
                );
                balls.add(球);
            }        }        保护彩色randomColor(){            INT红色=(INT)Math.abs(的Math.random()* 255);
            INT绿色=(INT)Math.abs(的Math.random()* 255);
            INT蓝=(INT)Math.abs(的Math.random()* 255);            返回新的颜色(红,绿,蓝);        }        @覆盖
        公共尺寸的get preferredSize(){
            返回新尺寸(400,200);
        }        @覆盖
        保护无效paintComponent(图形G){
            super.paintComponent方法(G);
            Graphics2D的G2D =(Graphics2D的)g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION,RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING,RenderingHints.VALUE_COLOR_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_DITHERING,RenderingHints.VALUE_DITHER_ENABLE);
            g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS,RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING,RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL,RenderingHints.VALUE_STROKE_PURE);
            对于(球球:球){
                ball.paint(G2D);
            }
            g2d.dispose();
        }        公共类球{            私人色彩的颜色;
            私人诠释X;
            私人诠释Ÿ;
            私人诠释半径;
            私人诠释三角洲;            公共球(色色,诠释的x,INT Y,INT半径){
                this.color =颜色;
                this.x = X;
                this.y = Y;
                this.radius =半径;
                增量=的Math.random()> 0.5? 1:-1;
            }            公共无效更新(INT宽度,诠释速度){
                X + =速度*三角洲;
                如果(X +半径大于=宽度){
                    X =宽度 - 半径;
                    增量* = -1;
                }否则如果(X℃,){
                    X = 0;
                    增量* = -1;
                }
            }            公共无效漆(图形G){
                g.setColor(颜色);
                g.fillOval(X,Y,半径,半径);
            }        }    }}

本例Swing的绘画过程的范围内,如果你需要更多的控制在绘画过程中,你将需要使用 BufferStrategy使用(将摆动内工作)

I am creating simple animation of ball moving from one side of the screen to the other with different speed. The problem is that with higher speeds of the ball I can see noticeable flickering of the ball, actually it is hard to explain but something like I could see repaints when part of ball is still in previous step.

I have tried number of things including:

  1. native swing animation using first thread/sleep/repain, then moved to timers

  2. switched to javafx canvas/pane inside swing jframe. Tried both transitions and AnimationTimer

  3. tinkering with CreateBufferStrategy, for 1,2,3 - to be honest haven't seen any difference (maybe I was doing something wrong...)

My question how can I improve smoothness and whether what I want to achieve is possible with native java or maybe it is better to use some external libraries ? and if so could you recommend something ?

below shown my example code for 2nd/3rd attempt.

import java.awt.Dimension;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;

import javafx.animation.Interpolator;
import javafx.animation.Timeline;
import javafx.animation.TranslateTransition;
import javafx.application.Platform;
import javafx.embed.swing.JFXPanel;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.util.Duration;
import javax.swing.JFrame;

public class FXTrackerPanel extends JFrame {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public int crSize = 30;
    public double xPos = crSize;
    public double yPos = 100;
    public int xSize = 100;
    public int ySize = 100;
    public Circle r;
    int dir = 1;

    public void updateScreenSize() {
        int screen = 0;
        GraphicsEnvironment ge = GraphicsEnvironment
            .getLocalGraphicsEnvironment();
        GraphicsDevice[] gs = ge.getScreenDevices();
        if( screen > -1 && screen < gs.length )
        {           
            xSize = gs[screen].getDisplayMode().getWidth();
            ySize = gs[screen].getDisplayMode().getHeight();
        }
        else if( gs.length > 0 )
        {
            xSize = gs[0].getDisplayMode().getWidth();
            ySize = gs[0].getDisplayMode().getHeight();
        }
        else
        {
            throw new RuntimeException( "No Screens Found" );
        }

        yPos = ySize / 2;
    }

    private void initFXPanel(JFXPanel fxPanel) {
        updateScreenSize();
        xPos = crSize;

        Group root = new Group();

        double speed = 5;

        int repeats = Timeline.INDEFINITE;

        r = new javafx.scene.shape.Circle(xPos, yPos, crSize / 2, Color.RED);
        TranslateTransition tt = new TranslateTransition(Duration.seconds(speed), r);
        tt.setFromX(xPos);
        tt.setToX(xSize - crSize * 3);
        tt.setCycleCount(repeats);
        tt.setAutoReverse(true);
        tt.setInterpolator(Interpolator.EASE_BOTH);
        tt.play();

        root.getChildren().add(r);

//      new AnimationTimer() {
//          
//          @Override
//          public void handle(long now) {
//              double speed = 20;
//              try {
//                  speed = Double.valueOf(TETSimple.mp.speedSinus.getText());
//              }
//              catch (Exception ex) {
//                  speed = 20;
//              }
//              double xMov = (speed * 4 * Math.sin( xPos * Math.PI / xSize ) );
//              if (xMov <= 0) {
//                  xMov = 1;
//              }
//              if (dir == 1) {
//                  if (xPos >= xSize - crSize)
//                      dir = 0;
//                  xPos += xMov;
//              } else {
//                  if (xPos <= 1)
//                      dir = 1;
//                  xPos -= xMov;
//              }
//              
//              r.setTranslateX(xPos);              
//          }
//      }.start();

        fxPanel.setScene(new Scene(root));
    }

    public FXTrackerPanel() {
        updateScreenSize();
        this.setSize(new Dimension(xSize, ySize));
        this.setPreferredSize(new Dimension(xSize, ySize));
        this.setVisible(true);
        this.setDefaultCloseOperation(DISPOSE_ON_CLOSE);
        JFXPanel fxPanel = new JFXPanel();
        this.add(fxPanel);
        this.createBufferStrategy(3);

        Platform.runLater(new Runnable() {

            @Override
            public void run() {
                initFXPanel(fxPanel);               
            }
        });
    }

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

And here example for swing code:

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;

import javax.swing.JPanel;
import javax.swing.Timer;

import java.lang.Math;
import java.util.Random;

public class TrackerPanel extends JPanel implements ActionListener {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    Shape cr;
    Color c;
    public int crSize = 30;
    public double xPos = crSize;
    public double yPos = 100;
    public double xPosPrev = crSize;
    public double yPosPrev = 100;
    public int xSize = 100;
    public int ySize = 100;
    int dir = 1; // left
    int timer = 50; // 50 - sins, 1500 - linear
    int method = 1; // 1 - jump, 2 - sinus
    int timeToChange = 1000;
    int passes = 0;
    Timer tt;
    boolean clickedClose = false;
    private int repeats = 0;

    // t - timer interval, m - method of ball movement: 1 - jump, 2 - sinus
    public TrackerPanel(int t, int m) {
        this.setPreferredSize(new Dimension(300, 200));
        this.timer = t;
        this.method = m;
        c = Color.red;
        repaint();
        this.updateScreenSize();
        tt = new Timer(t, null);
        tt.addActionListener(this);
        tt.start();
    }

    public void updateScreenSize() {
        int screen = TETSimple.suppMonitor;
        GraphicsEnvironment ge = GraphicsEnvironment
                .getLocalGraphicsEnvironment();
        GraphicsDevice[] gs = ge.getScreenDevices();
        if (screen > -1 && screen < gs.length) {
            xSize = gs[screen].getDisplayMode().getWidth();
            ySize = gs[screen].getDisplayMode().getHeight();
        } else if (gs.length > 0) {
            xSize = gs[0].getDisplayMode().getWidth();
            ySize = gs[0].getDisplayMode().getHeight();
        } else {
            throw new RuntimeException("No Screens Found");
        }

        yPos = ySize / 2;
        yPosPrev = ySize / 2;
    }

    public void actionPerformed(ActionEvent arg0) {
        if (method == 1)
            lineMovement();
        else
            sinusMovement();
        repaint(0, ySize / 2, xSize, crSize);
    }

    private Double parseText2Int(String literal) {
        try {
            return Double.valueOf(literal);
        } catch (Exception ex) {
            ex.printStackTrace();           
        }
        return 10.0;
    }

    private void checkFinishCondition() {
        if (passes + 1 > repeats && repeats != 0) {
            if (!clickedClose) {
                TETSimple.mp.bStop.doClick();
                clickedClose = true;
            }
            return;
        }
    }

    private void sinusMovement() {
        this.updateScreenSize();
        this.repeats = parseText2Int(TETSimple.mp.repeatsCount.getText()).intValue();
        checkFinishCondition();

        double speed = parseText2Int(TETSimple.mp.speedSinus.getText());
        double xMov = (speed * Math.sin(xPos * Math.PI / xSize));
        if (xMov <= 0) {
            xMov = 1;
        }
        if (dir == 1) {
            if (xPos >= xSize - crSize)
                dir = 0;
            xPosPrev = xPos;
            xPos += xMov;
        } else {
            if (xPos <= 1 + crSize) {
                dir = 1;
                passes++;
            }
            xPosPrev = xPos;
            xPos -= xMov;
        }
    }

    private void lineMovement() {
        this.repeats = parseText2Int(TETSimple.mp.repeatsCount.getText()).intValue();
        checkFinishCondition();

        double left = crSize;
        double center = xSize / 2 - crSize * 1.5;
        double right = xSize - crSize * 2;
        Random r = new Random();

        if (timeToChange <= 0) {
            passes++;
            if (xPos == left || xPos == right) {
                timeToChange = 300 + r.nextInt(12) * 100;
                xPos = center;
            } else if (xPos == center) {
                timeToChange = 300 + r.nextInt(7) * 100;
                if (r.nextBoolean())
                    xPos = left;
                else
                    xPos = right;
            }
        } else {
            timeToChange -= 100;
        }
    }

    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        Graphics2D g2d = (Graphics2D) g.create();
        g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
        g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
        g2d.setColor(Color.green);
        g2d.fill(new Ellipse2D.Double(xPos, yPos, crSize, crSize));
        g2d.dispose();
    }
}

解决方案

It's difficult to know exactly what might be going wrong without a runnable example, but I would, where you can, avoid mixing JavaFX and Swing, as they have different rendering mechanisms.

The following is a VERY simple example, which simply increases the speed of the balls been animated by simply changing the amount by which they are moved on each update...

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.List;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

public class BouncyBall {

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

    public BouncyBall() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new ControlPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class ControlPane extends JPanel {

        private JSlider speed;
        private JSlider quanity;

        private BallPitPane ballPitPane;

        public ControlPane() {
            setLayout(new BorderLayout());
            ballPitPane = new BallPitPane();
            add(ballPitPane);

            JPanel controls = new JPanel(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.anchor = GridBagConstraints.WEST;

            speed = new JSlider(1, 100, 4);
            quanity = new JSlider(1, 100, 1);

            controls.add(new JLabel("Speed:"), gbc);
            gbc.gridy++;
            controls.add(new JLabel("Quanity:"), gbc);

            gbc.gridx++;
            gbc.gridy = 0;
            gbc.weightx = 1;
            gbc.fill = GridBagConstraints.HORIZONTAL;

            controls.add(speed, gbc);
            gbc.gridy++;
            controls.add(quanity, gbc);
            add(controls, BorderLayout.SOUTH);

            speed.addChangeListener(new ChangeListener() {
                @Override
                public void stateChanged(ChangeEvent e) {
                    ballPitPane.setSpeed(speed.getValue());
                }
            });

            quanity.addChangeListener(new ChangeListener() {
                @Override
                public void stateChanged(ChangeEvent e) {
                    ballPitPane.setQuanity(quanity.getValue());
                }
            });
        }

    }

    public class BallPitPane extends JPanel {

        private List<Ball> balls;
        private int speed;

        public BallPitPane() {
            balls = new ArrayList<>(25);
            setSpeed(2);
            setQuanity(1);

            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    for (Ball ball : balls) {
                        ball.update(getWidth(), speed);
                    }
                    repaint();
                }
            });
            timer.start();
        }

        public void setSpeed(int speed) {
            this.speed = speed;
        }

        public void setQuanity(int quanity) {

            while (balls.size() > quanity) {
                balls.remove(0);
            }
            while (balls.size() < quanity) {
                int radius = 4 + (int) (Math.random() * 48);
                Ball ball = new Ball(
                        randomColor(),
                        (int) Math.abs(Math.random() * getWidth() - radius),
                        (int) Math.abs(Math.random() * getHeight() - radius),
                        radius
                );
                balls.add(ball);
            }

        }

        protected Color randomColor() {

            int red = (int) Math.abs(Math.random() * 255);
            int green = (int) Math.abs(Math.random() * 255);
            int blue = (int) Math.abs(Math.random() * 255);

            return new Color(red, green, blue);

        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(400, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
            g2d.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
            g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
            g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
            g2d.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
            for (Ball ball : balls) {
                ball.paint(g2d);
            }
            g2d.dispose();
        }

        public class Ball {

            private Color color;
            private int x;
            private int y;
            private int radius;
            private int delta;

            public Ball(Color color, int x, int y, int radius) {
                this.color = color;
                this.x = x;
                this.y = y;
                this.radius = radius;
                delta = Math.random() > 0.5 ? 1 : -1;
            }

            public void update(int width, int speed) {
                x += speed * delta;
                if (x + radius >= width) {
                    x = width - radius;
                    delta *= -1;
                } else if (x < 0) {
                    x = 0;
                    delta *= -1;
                }
            }

            public void paint(Graphics g) {
                g.setColor(color);
                g.fillOval(x, y, radius, radius);
            }

        }

    }

}

This example works within the confines of Swing's painting process, if you need more control over the painting process you will need to use a BufferStrategy (to work within Swing)

这篇关于流畅的动画效果在java中的快速移动的物体的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆