使用Java

时间:2017-11-03 21:32:36

标签: java swing

由于我是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并尝试为此实现不同的方法?谢谢。 (另外,正如我所说,我是新手,所以如果我在标题中出现任何错误/代码中的明显错误/没有解释我的意思,请告诉我)。

1 个答案:

答案 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)。