流畅的动画效果在java中的快速移动的物体 [英] smooth animation in java for fast moving objects
问题描述
我创造球简单的动画在屏幕的一侧移动到另一不同速度。问题在于球的更高的速度,我可以看到球的明显抖动,实际上它是很难解释的,但像我看得出重绘时球的一部分仍然在previous一步。
我曾尝试一些事情,包括:
-
本机摇摆动画使用第一个线程/睡眠/ repain,然后转移到计时器
-
切换到JavaFX的画布/窗格秋千JFrame的内部。尝试都转换和AnimationTimer
-
与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< = 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:
native swing animation using first thread/sleep/repain, then moved to timers
switched to javafx canvas/pane inside swing jframe. Tried both transitions and AnimationTimer
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屋!