This question already has answers here:
Create a Trailing line of blood behind a player
(2个答案)
3年前关闭。
我有一个程序可以获取太空中两个行星/物体的信息,并对它们彼此之间的轨道进行逼真的动画处理。它可以工作,尽管当我重新粉刷时,它每次都会清除屏幕并且不会留下痕迹。
我的问题是我想留下一条线索,尽管我在网上找到的任何答案都只能说明如何摆脱一条道路。但是,我没有那个问题。
在其他计算机上,我可以在我的paint方法中忽略super.paintComponent(),这会使它留下痕迹,但是在这台计算机上,它没有执行此操作,似乎会自动清除屏幕。那么,我如何才能有效地在绕行轨道的行星后面绘制一条轨迹?我的代码如下。
JPanel类的第一个:
身体类别:
主班:
(2个答案)
3年前关闭。
我有一个程序可以获取太空中两个行星/物体的信息,并对它们彼此之间的轨道进行逼真的动画处理。它可以工作,尽管当我重新粉刷时,它每次都会清除屏幕并且不会留下痕迹。
我的问题是我想留下一条线索,尽管我在网上找到的任何答案都只能说明如何摆脱一条道路。但是,我没有那个问题。
在其他计算机上,我可以在我的paint方法中忽略super.paintComponent(),这会使它留下痕迹,但是在这台计算机上,它没有执行此操作,似乎会自动清除屏幕。那么,我如何才能有效地在绕行轨道的行星后面绘制一条轨迹?我的代码如下。
JPanel类的第一个:
import javax.swing.*;
import java.awt.*;
/**
* Created by chris on 3/2/16.
*/
public class SpacePanel2 extends JPanel{
private Body2[] planets;
public static final Dimension SCREENSIZE = Toolkit.getDefaultToolkit().getScreenSize();
public static double scale = 5e6; //m/p
public static Color[] colors = {Color.black, Color.red};
public SpacePanel2(Body2[] planets) {
this.planets = planets;
this.setPreferredSize(SCREENSIZE);
}
@Override
public void paint(Graphics g){
for (int i = 0; i < planets.length; i++) {
g.setColor(colors[i]);
int r = planets[i].getPixelRadius()/2;
int x = planets[i].getPixelX();
int y = planets[i].getPixelY();
g.fillOval(x, y, r, r);
}
}
}
身体类别:
/**
* Created by chris on 3/2/16.
*/
public class Body2 {
private double mass; //in kilograms
private double radius; //in meters
private static final double GRAVITATIONAL_CONSTANT = 6.67408e-11;
private static final double AVERAGE_DENSITY = 5515; //kg/m^3
/**
* Movement variables
*/
private double dx; //in m/s
private double dy; //in m/s
private double x; //in m
private double y; //in m
public Body2() {
radius = 1;
mass = AVERAGE_DENSITY;
x = 0;
y = 0;
dx = 0;
dy = 0;
}
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getMass() {
return mass;
}
public double getRadius() {
return radius;
}
public int getPixelX() {
return (int)((this.x-radius)/SpacePanel2.scale);
}
public int getPixelY() {
return (int)((this.y-radius)/SpacePanel2.scale);
}
public int getPixelRadius(){
return (int)(this.radius/SpacePanel2.scale);
}
public void setMass(double mass) {
this.mass = mass;
}
public void setRadius(double radius) {
this.radius = radius;
}
public void setDx(double dx) {
this.dx = dx;
}
public void setDy(double dy) {
this.dy = dy;
}
public void setX(double x) {
this.x = x;
}
public void setY(double y) {
this.y = y;
}
public void exertForce2(double diffY, double diffX, double F){
double dist = Math.sqrt(diffY*diffY + diffX*diffX);
double ratio = F / dist;
this.dy = this.dy + ratio*diffY/this.mass;
this.dx = this.dx + ratio*diffX/this.mass;
}
public void tick(double timeScale) {
x+=(dx/1000.0)*timeScale;
y+=(dy/1000.0)*timeScale;
}
public static double getForce(Body2 a, Body2 b){
double dX = a.getX() - b.getX();
double dY = a.getY() - b.getY();
double distance = Math.sqrt(Math.pow(dX,2)+Math.pow(dY,2));
return (a.getMass()*b.getMass()*GRAVITATIONAL_CONSTANT)/(distance*distance);
}
public static double getStandardMass(double radius){
return (4.0/3.0)*Math.pow(radius, 3) * Math.PI;
}
public double getDy() {
return dy;
}
public double getDx() {
return dx;
}
public static double predictCentripetalForce(Body2 sun, Body2 planet){
return Math.sqrt(getForce(planet, sun)*(sun.getY()-planet.getY())/planet.mass);
}
}
主班:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
/**
* Created by chris on 3/2/16.
*/
public class MainSpace2 {
static JFrame frame;
static SpacePanel2 panel;
static int fps = 60;
static boolean getLarger = false;
static boolean getSmaller = false;
static Dimension size = Toolkit.getDefaultToolkit().getScreenSize();
public static void main(String[] args) {
Body2[] test = new Body2[2];
Body2 sun = new Body2();
sun.setRadius(696300000);
sun.setMass(1.989e30);
sun.setX(getScope('x') / 2);
sun.setY(getScope('y') / 2);
sun.setDx(0);
sun.setDy(0);
test[0] = sun;
int literalSizeSun = (int)(sun.getRadius()/SpacePanel2.scale);
Body2 mercury = new Body2();
mercury.setRadius(24400000);
mercury.setMass(Body2.getStandardMass(mercury.getRadius()));
mercury.setDx(Body2.predictCentripetalForce(sun, mercury)*2);
mercury.setDy(0);
mercury.setX(sun.getX());
mercury.setY(sun.getY() + 2 * sun.getRadius());
test[1] = mercury;
int literalSizeMercury = (int)(mercury.getRadius()/SpacePanel2.scale);
frame = new JFrame();
frame.setPreferredSize(size);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
panel = new SpacePanel2(test);
frame.addKeyListener(new KeyListener() {
@Override
public void keyTyped(KeyEvent e) {
}
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyChar()) {
case '-':
getSmaller = true;
getLarger = false;
break;
case '=':
getLarger = true;
getSmaller = false;
break;
}
}
@Override
public void keyReleased(KeyEvent e) {
switch (e.getKeyChar()) {
case '-':
getSmaller = false;
break;
case '=':
getLarger = false;
break;
}
}
});
double timeScale = 60*24;
Timer time = new Timer((int) (1000.0 / fps), new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
double F = Body2.getForce(test[0], test[1]);
double dY = test[1].getY() - test[0].getY();
double dX = test[1].getX() - test[0].getX();
test[0].exertForce2(dY, dX, F);
test[1].exertForce2(-dY, -dX, F);
for (int j = 0; j < test.length; j++) {
test[j].tick(timeScale);
}
panel.repaint(sun.getPixelX(), sun.getPixelY(), literalSizeSun, literalSizeSun);
panel.repaint(mercury.getPixelX(), mercury.getPixelY(), literalSizeMercury, literalSizeMercury);
}
});
frame.add(panel);
frame.pack();
frame.setVisible(true);
time.start();
}
public static double getScope(char k) {
switch (k) {
case 'x':
return size.width * SpacePanel2.scale;
case 'y':
return size.height * SpacePanel2.scale;
default:
return 0;
}
}
}
最佳答案
通过覆盖paintComponent()
方法而不是paint()来完成自定义绘制。
如果您留下连续的轨迹,则进行360度旋转后,您将不再看到动画,因此,我认为您最终需要清除屏幕。
如果要留下痕迹,可以保留要绘制的对象的ArrayList
。然后,在paintComponent()
方法中,可以遍历List
。这将允许您从列表中添加/删除对象,以便您可以控制要绘制每个动画的对象的数量。
查看Custom Painting Approaches中的DrawOnComponent
示例以获取此方法的示例。因此,您的动画逻辑基本上会在列表中添加一个新的Object(一旦达到某个限制,就可能删除一个Object?)。然后,您只需在面板上调用repaint()即可绘制所有对象。
您已经有List可以绘制每个星球。因此,每个动画都需要将每个行星的新位置添加到列表中。
或者,该链接显示了如何绘制到BufferedImage。但是这种方法不允许您在完成绘画后删除它。因此,这取决于您使用哪种方法的确切要求。
09-11 20:43