由于我是Java图形(以及一般的Java)的新手,我决定尝试一些例子。其中一个是太阳系,虽然我设法制造它,但我有一个问题 - 我不知道如何设定行星的速度,所以每个人都会有所不同。我尝试了不同的想法,并在网上阅读了很多,但现在我被卡住了。这是代码:
public class solarsystem {
public static void main(String[] args) {
System wnd = new System();
wnd.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
wnd.setSize(1000,1000);
wnd.setVisible(true);
}
}
class Planets extends JPanel implements ActionListener{
int r = 70;
int r2 = 5;
int r3 = 10;
int center_x, center_y;
double angle;
Timer timer;
Planets(){
super();
timer = new Timer(100, this);
timer.start();
setBackground(new Color(0,0,0));
}
public void actionPerformed(ActionEvent e) {
angle+=0.05;
if(angle > (2*Math.PI))
angle = 0.0;
repaint();
}
public void DrawSun(int a, int b, int r, Graphics g) {
g.fillOval(a, b, r, r);
}
public void DrawPlanet(int a, int b, int r, Graphics g) {
g.fillOval(a, b, r, r);
}
public int moveXParam(double number) {
int move_x = (int) (Math.cos(angle) * (getWidth()/number) + (getWidth()/2));
return move_x;
}
public int moveYParam(double number) {
int move_y = (int) (Math.sin(angle) * (getHeight()/ number) + (getHeight()/ 2));
return move_y;
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
center_x = getWidth()/2;
center_y = getHeight()/2;
Graphics2D g2d = (Graphics2D)g;
//drawin Sun
g2d.setColor(new Color(255,255,0));
DrawSun(center_x-(r/2), center_y-(r/2), r, g);
//Mercury
g2d.setColor(new Color(255, 0, 0));
DrawPlanet(moveXParam(9), moveYParam(9), r2, g);
//Venus
g2d.setColor(new Color(153, 76, 0));
DrawPlanet(moveXParam(8), moveYParam(8), r3, g);
}
}
class System extends JFrame{
public System() {
setContentPane(new Planets());
setTitle("Solar System");
}
}
问题是管理速度的代码部分在angle+=0.05;
方法中是actionPerformed
,无论我怎么试图绕过它(使用switch case,不同的方法等来输入不同的每个星球的角度变化)我一直在同一个地方结束,这个地方必须将参数传递给actionPerformed,我不能这样做。从我收集的内容来看,无论我改变什么,最终的角度变化将是将要应用的角度,因为repaint()
。现在,这是我第一次使用ActionListener
和类似的东西,所以我决定寻求帮助。
那么,有没有办法改变angle+=0.05
,以便例如它对Mercury来说就像那样,但对于Venus来说它是angle+=0.07
?或者我应该完全放弃actionPerformed
并尝试为此实现不同的方法?谢谢。 (另外,正如我所说,我是新手,所以如果我在标题中出现任何错误/代码中的明显错误/没有解释我的意思,请告诉我)。
答案 0 :(得分:2)
您似乎是面向对象编程的新手。你有许多不同的速度,角度,颜色和没有,但你尝试用一个变量来处理它们。我在我的解决方案中所做的是创建一个新的StellarObject
类,它包含所有这些变量。它还有一个update()
方法和一个draw()
方法,您可以调用它来更新所有与物理相关的变量,并将对象分别绘制到画布。它们都存储在List
中(如果你知道对象的数量不会改变,你可以使用数组)并迭代它们来调用它们的方法。
此外,虽然使Planets
实现ActionListener
没有错,但它确实是一种不常见的方式。在编写面向对象的代码时,请尝试考虑Planets
是否真正在监听操作。你可以说物理学中的一个滴答是一个动作,但那么绘制事件和其他东西也是如此。通常,您会为要通知的每个操作创建单独的ActionListener
。我们使用lambda表示法使new Timer(100, e -> update());
的所有内容更紧凑。这会在内部创建一个新的ActionListener
,它只调用update()
方法。当我们调用stellarObjects.forEach(StellarObject::update);
时,我们也会使用lambda表示法,它会迭代所有StellarObject
并调用他们的update()
方法。
public class Planets extends JPanel {
private List<StellarObject> stellarObjects = new LinkedList<>();
private Timer timer;
private StellarObject sun = new StellarObject(0, 0, new Color(255, 255, 0), 70);
private StellarObject mercury = new StellarObject(9, 0.07, new Color(255, 0, 0), 5);
private StellarObject venus = new StellarObject(8, 0.05, new Color(153, 76, 0), 10);
public Planets(){
super();
timer = new Timer(100, e -> update());
timer.start();
setBackground(Color.BLACK);
Collections.addAll(stellarObjects, sun, mercury, venus);
}
public void update() {
stellarObjects.forEach(StellarObject::update);
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
for (StellarObject stellarObject : stellarObjects) {
stellarObject.draw(g);
}
}
public class StellarObject {
private int distance;
private double angle;
private double angularVelocity;
private Color color;
private int radius;
public StellarObject(int distance, double angularVelocity, Color color, int radius) {
this.distance = distance;
this.angularVelocity = angularVelocity;
this.color = color;
this.radius = radius;
}
public void draw(Graphics g) {
g.setColor(color);
g.fillOval(xDelta() - radius / 2, yDelta() - radius / 2, radius, radius);
}
private void update() {
angle += angularVelocity;
angle %= 2 * Math.PI;
}
public int xDelta() {
return (int) ((distance == 0 ? 0 : Math.cos(angle) * (getWidth() / distance)) + (getWidth() / 2));
}
public int yDelta() {
return (int) ((distance == 0 ? 0 : Math.sin(angle) * (getHeight() / distance)) + (getHeight() / 2));
}
}
}
如果您希望进一步提高Java技能,可能需要熟悉特定于Java的约定:始终使字段private
只允许通过getter和setter访问它们。所有方法名称都应该是 c amelCase(称之为drawPlanet
,而不是DrawPlanet
)。类名应始终为 C amelCase(称之为SolarSystem
,而不是solarsystem
)。