我正在做一個專案,我需要一個在橢圓(例如圓周)上移動的球的影片。目前,我JPanel通過重寫paintComponent()方法將它全部繪制在 a 上,移動效果來自以固定速率重新繪制它,并改變“球”的位置。
這一切都很好,除了球似乎以“梯形”方式移動,而且不順利。由于這是圖紙之間的問題,我想弄亂RenderingHints會無濟于事。
問題的 SSCCE(從測驗來看,它可能看起來不那么明顯,但是當你有超過 100 個球在移動時,它看起來真的很奇怪):
import javax.swing.*;
import java.awt.*;
public class SSCCE {
private static long dt;
private static JPanel animationPanel = createAnimationPanel();
private static JPanel createAnimationPanel() {
return new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int w = this.getWidth();
int h = this.getHeight();
Point center = new Point(w / 2, h / 2);
// Drawing circumference.
int radius = 80;
int x = center.x - radius;
int y = center.y - radius;
g2d.drawOval(x, y, radius * 2, radius * 2);
// Drawing ball.
g2d.setColor(Color.RED);
int ballWidth = 20;
double rad = Math.toRadians((dt / ((radius * 2) / 8.0)));
int xPos = (int) (center.x - (Math.cos(rad) * radius) - (ballWidth / 2));
int yPos = (int) (center.y - (Math.sin(rad) * radius) - (ballWidth / 2));
g2d.fillOval(xPos, yPos, ballWidth, ballWidth);
}
};
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Draw Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(animationPanel, BorderLayout.CENTER);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setEnabled(true);
frame.setVisible(true);
frame.requestFocus();
});
Thread updateThread = new Thread(() -> {
long lastTime = System.currentTimeMillis();
while (true) { // I don't actually use "while (true)", but it doesn't matter since it's a test.
dt = System.currentTimeMillis() - lastTime;
animationPanel.repaint();
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}, "Update Thread");
SwingUtilities.invokeLater(updateThread::start);
}
}
所以總而言之,我認為也許我可以將位置插入亞像素級別,并以某種方式在“像素之間”繪制球,類似于抗鋸齒效果的作業原理......這可能嗎?如果沒有,是否有任何解決方法?
uj5u.com熱心網友回復:
您的問題與將double值截斷有關int
int xPos = (int) (center.x - (Math.cos(rad) * radius) - (ballWidth / 2));
int yPos = (int) (center.y - (Math.sin(rad) * radius) - (ballWidth / 2));
相反,您應該使用這些double值。在這種情況下,您可以簡單地translate使用Graphics2DAPI,例如...
// Drawing ball.
g2d.setColor(Color.RED);
int ballWidth = 20;
double rad = Math.toRadians((dt / ((radius * 2) / 8.0)));
double xPos = (center.x - (Math.cos(rad) * radius) - (ballWidth / 2));
double yPos = (center.y - (Math.sin(rad) * radius) - (ballWidth / 2));
if (theActualDot == null) {
theActualDot = new Ellipse2D.Double(0, 0, ballWidth, ballWidth);
}
g2d.translate(xPos, yPos);
g2d.fill(theActualDot);
可運行示例
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
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.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class Main {
private static long dt;
private static JPanel animationPanel = createAnimationPanel();
private static JPanel createAnimationPanel() {
return new JPanel() {
private Shape theActualDot;
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
int w = this.getWidth();
int h = this.getHeight();
Point center = new Point(w / 2, h / 2);
// Drawing circumference.
int radius = 80;
int x = center.x - radius;
int y = center.y - radius;
g2d.drawOval(x, y, radius * 2, radius * 2);
// Drawing ball.
g2d.setColor(Color.RED);
int ballWidth = 20;
double rad = Math.toRadians((dt / ((radius * 2) / 8.0)));
double xPos = (center.x - (Math.cos(rad) * radius) - (ballWidth / 2));
double yPos = (center.y - (Math.sin(rad) * radius) - (ballWidth / 2));
if (theActualDot == null) {
theActualDot = new Ellipse2D.Double(0, 0, ballWidth, ballWidth);
}
g2d.translate(xPos, yPos);
g2d.fill(theActualDot);
g2d.dispose();
}
};
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame frame = new JFrame("Draw Test");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().setLayout(new BorderLayout());
frame.getContentPane().add(animationPanel, BorderLayout.CENTER);
frame.setSize(400, 400);
frame.setLocationRelativeTo(null);
frame.setEnabled(true);
frame.setVisible(true);
frame.requestFocus();
Timer timer = new Timer(5, new ActionListener() {
long lastTime = System.currentTimeMillis();
@Override
public void actionPerformed(ActionEvent e) {
dt = System.currentTimeMillis() - lastTime;
animationPanel.repaint();
}
});
timer.start();
});
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/435912.html
上一篇:從字串轉換日期格式
