Java太阳系行星运动模型
太陽(yáng)系行星運(yùn)動(dòng)模型
- 基本思路
- 此程序的核心算法
- 遇到的問(wèn)題和解決辦法
- 完整代碼和運(yùn)行效果
基本思路
首先,為了讓行星運(yùn)動(dòng)看起來(lái)更加地逼真,采用斜二測(cè)畫法計(jì)算行星的軌道,并將其繪制出來(lái),再將無(wú)背景的PNG行星圖片按照一定的大小比例繪制在對(duì)應(yīng)的軌道上的某一點(diǎn)。同時(shí),為了讓行星運(yùn)動(dòng)起來(lái),我們需要用一個(gè)循環(huán),不停地計(jì)算行星的坐標(biāo),并將其繪制。在這之前,要將之前繪制的所有圖片進(jìn)行擦除,也就是清屏(這一操作放在循環(huán)當(dāng)中)。在執(zhí)行循環(huán)的過(guò)程中要在繪制圖片和清屏之前加上一個(gè)時(shí)間間隔,這樣才能讓我們看到圖片。這樣呈現(xiàn)出的效果就是每個(gè)行星在其對(duì)應(yīng)的軌道上運(yùn)動(dòng)。這個(gè)過(guò)程采用一個(gè)線程來(lái)執(zhí)行。
此程序的核心算法
計(jì)算軌道的方程和計(jì)算行星的坐標(biāo)在原理上是一致的,繪制軌道就是把行星在軌道上的每一點(diǎn)的坐標(biāo)計(jì)算出來(lái),并畫上一個(gè)點(diǎn),為了讓效果更加明顯,我采用了繪制一個(gè)半徑為2個(gè)像素點(diǎn)的圓形的辦法。
接下來(lái)我們考慮如何來(lái)計(jì)算軌道上每個(gè)點(diǎn)的坐標(biāo)。因?yàn)榭紤]到行星運(yùn)動(dòng)近似圓周運(yùn)動(dòng),因此我們采用將極坐標(biāo)轉(zhuǎn)化為直角坐標(biāo)系的辦法,即確定了軌道半徑和角度,便可以計(jì)算出該坐標(biāo)了。
數(shù)學(xué)公式如下:
y=√2/4 × r × sin(θ)
x=r × cos(θ)+y
在程序中定義的角度angle是一般的角度,要將它轉(zhuǎn)換成弧度制,于是前面的θ應(yīng)該寫成(angle/180)*π。具體的實(shí)現(xiàn)方法如下:
/*** * @param r 半徑* @param angle 角度* @return 行星相對(duì)運(yùn)動(dòng)中心的Y坐標(biāo)*/public int setY(double r,double angle) {//由于屏幕中的原點(diǎn)是在左上角,因此y坐標(biāo)添加一個(gè)負(fù)號(hào)return -(int)(r*Math.sin((angle/180)*Math.PI)*Math.sqrt(2)/4);}public int setX(double r,double angle,int y) {return (int)(r*Math.cos((angle/180)*Math.PI))-y;}計(jì)算出的這些坐標(biāo)需要加上屏幕中心點(diǎn)的坐標(biāo)(讓軌道移動(dòng)到屏幕中間)。
遇到的問(wèn)題和解決辦法
在繪制行星的過(guò)程中要考慮哪個(gè)行星先畫,原則上y坐標(biāo)較小的先畫(在屏幕上y坐標(biāo)更小意味著它距離觀測(cè)點(diǎn)更遠(yuǎn))。這樣,當(dāng)行星圖片重疊時(shí),相對(duì)觀測(cè)點(diǎn)更近的圖片后畫便可以覆蓋更遠(yuǎn)的那張圖片,可以呈現(xiàn)更加真實(shí)的效果。當(dāng)考慮多個(gè)行星的重疊問(wèn)題時(shí),它的情況變得十分復(fù)雜,目前只能對(duì)處于中央的太陽(yáng)、水星、金星做了相應(yīng)的處理,對(duì)于其他的行星通過(guò)控制他們間的距離避免圖像重疊問(wèn)題。但這種方法使得離太陽(yáng)的距離比例不夠協(xié)調(diào)(雖然本來(lái)比例就無(wú)法真實(shí)還原,因?yàn)樘?yáng)相對(duì)地球等行星,它的半徑過(guò)于大,并且木星與太陽(yáng)的距離是地球與太陽(yáng)的距離的29倍之多)。
除了行星間的圖片重疊問(wèn)題,還有軌道繪制問(wèn)題,一般情況下,軌道最先畫,確保軌道不會(huì)擋住行星,但考慮到中央的太陽(yáng)會(huì)將水星與金星的一部分軌道覆蓋,所以這部分的軌道繪制也要做特殊處理。
還有一個(gè)小問(wèn)題,軌道是具有寬度的,要讓行星的中心位于軌道的中心就要做相應(yīng)的調(diào)整。具體實(shí)現(xiàn)如下:
for (int i = 0; i < 2700; i++) { //中間會(huì)發(fā)生重疊的軌道分為兩部分分開畫int y1 = setY(r[1], line_angle-20);int x1 = setX(r[1], line_angle-20, y1);g.fillOval(x1 + CENTRAL_X - 2, y1 + CENTRAL_Y - 2, 4, 4);int y2 = setY(r[2], line_angle-20);int x2 = setX(r[2], line_angle-20, y2);g.fillOval(x2 + CENTRAL_X - 2, y2 + CENTRAL_Y - 2, 4, 4);line_angle += 0.1; } if (y[1] > 0) {// 水星在太陽(yáng)前if (y[2] > 0) {// 金星在太陽(yáng)前g.drawImage(Sun.getImage(), CENTRAL_X - size[0] / 2, CENTRAL_Y - size[0] / 2, size[0], size[0],null);for (int i = 0; i < 900; i++) {//另一半軌道int y1 = setY(r[1], line_angle-20);int x1 = setX(r[1], line_angle-20, y1);g.fillOval(x1 + CENTRAL_X - 2, y1 + CENTRAL_Y - 2, 4, 4);int y2 = setY(r[2], line_angle-20);int x2 = setX(r[2], line_angle-20, y2);g.fillOval(x2 + CENTRAL_X - 2, y2 + CENTRAL_Y - 2, 4, 4);line_angle += 0.1;}g.drawImage(Mercury.getImage(), x[1] + CENTRAL_X - size[1] / 2, y[1] + CENTRAL_Y - size[1] / 2,size[1], size[1], null);g.drawImage(Venus.getImage(), x[2] + CENTRAL_X - size[2] / 2, y[2] + CENTRAL_Y - size[2] / 2,size[2], size[2], null);} else {// 金星在太陽(yáng)后g.drawImage(Venus.getImage(), x[2] + CENTRAL_X - size[2] / 2, y[2] + CENTRAL_Y - size[2] / 2,size[2], size[2], null);g.drawImage(Sun.getImage(), CENTRAL_X - size[0] / 2, CENTRAL_Y - size[0] / 2, size[0], size[0],null);for (int i = 0; i < 900; i++) {//另一半軌道int y1 = setY(r[1], line_angle-20);int x1 = setX(r[1], line_angle-20, y1);g.fillOval(x1 + CENTRAL_X - 2, y1 + CENTRAL_Y - 2, 4, 4);int y2 = setY(r[2], line_angle-20);int x2 = setX(r[2], line_angle-20, y2);g.fillOval(x2 + CENTRAL_X - 2, y2 + CENTRAL_Y - 2, 4, 4);line_angle += 0.1;}g.drawImage(Mercury.getImage(), x[1] + CENTRAL_X - size[1] / 2, y[1] + CENTRAL_Y - size[1] / 2,size[1], size[1], null);} } else {//水星在太陽(yáng)后if (y[2] > 0) {//金星在太陽(yáng)前g.drawImage(Mercury.getImage(), x[1] + CENTRAL_X - size[1] / 2, y[1] + CENTRAL_Y - size[1] / 2,size[1], size[1], null);g.drawImage(Sun.getImage(), CENTRAL_X - size[0] / 2, CENTRAL_Y - size[0] / 2, size[0], size[0],null);for (int i = 0; i < 900; i++) {//另一半軌道int y1 = setY(r[1], line_angle-20);int x1 = setX(r[1], line_angle-20, y1);g.fillOval(x1 + CENTRAL_X - 2, y1 + CENTRAL_Y - 2, 4, 4);int y2 = setY(r[2], line_angle-20);int x2 = setX(r[2], line_angle-20, y2);g.fillOval(x2 + CENTRAL_X - 2, y2 + CENTRAL_Y - 2, 4, 4);line_angle += 0.1;}g.drawImage(Venus.getImage(), x[2] + CENTRAL_X - size[2] / 2, y[2] + CENTRAL_Y - size[2] / 2,size[2], size[2], null);} else {//金星在太陽(yáng)后g.drawImage(Venus.getImage(), x[2] + CENTRAL_X - size[2] / 2, y[2] + CENTRAL_Y - size[2] / 2,size[2], size[2], null);g.drawImage(Mercury.getImage(), x[1] + CENTRAL_X - size[1] / 2, y[1] + CENTRAL_Y - size[1] / 2,size[1], size[1], null);g.drawImage(Sun.getImage(), CENTRAL_X - size[0] / 2, CENTRAL_Y - size[0] / 2, size[0], size[0],null);for (int i = 0; i < 900; i++) {//另一半軌道int y1 = setY(r[1], line_angle-20);int x1 = setX(r[1], line_angle-20, y1);g.fillOval(x1 + CENTRAL_X - 2, y1 + CENTRAL_Y - 2, 4, 4);int y2 = setY(r[2], line_angle-20);int x2 = setX(r[2], line_angle-20, y2);g.fillOval(x2 + CENTRAL_X - 2, y2 + CENTRAL_Y - 2, 4, 4);line_angle += 0.1;}} }完整代碼和運(yùn)行效果
由于屏幕大小有限,天王星和海王星沒(méi)有繪制。
(點(diǎn)開視頻前請(qǐng)將音量調(diào)小一點(diǎn),該視頻聲音略大)
Java模擬太陽(yáng)系行星運(yùn)動(dòng)模型
package com.Solar201028;import java.awt.BorderLayout; import java.awt.Color; import java.awt.Graphics; import java.awt.image.BufferedImage;import javax.swing.ImageIcon; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JWindow;public class SunSystem extends JFrame{public static void main(String[] agrs) {SunSystem sun=new SunSystem();sun.mysun();}public void mysun() {this.setTitle("太陽(yáng)系行星運(yùn)動(dòng)模型");this.setSize(1900,1020);this.setLocationRelativeTo(null);this.setDefaultCloseOperation(3);JPanel mainjp=new JPanel();this.add(mainjp);//主面板Listener move=new Listener();mainjp.addMouseListener(move);this.setVisible(true);Graphics g=mainjp.getGraphics();move.setG(g);}} package com.Solar201028;import java.awt.Graphics; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseEvent; import java.awt.event.MouseListener;import javax.swing.JButton;public class Listener implements MouseListener{private int begin=0;private Planet planet=new Planet();public void setG(Graphics g) {planet.setG(g);}@Overridepublic void mouseClicked(MouseEvent e) {}@Overridepublic void mousePressed(MouseEvent e) {}@Overridepublic void mouseReleased(MouseEvent e) {if(begin==0) {begin++;planet.start();}planet.turn();//控制開始與暫停}@Overridepublic void mouseEntered(MouseEvent e) {}@Overridepublic void mouseExited(MouseEvent e) {}} package com.Solar201028;import java.applet.Applet; import java.applet.AudioClip; import java.awt.Color; import java.awt.Graphics; import java.awt.image.BufferedImage; import java.io.File; import java.net.MalformedURLException; import java.net.URI; import java.net.URL; import java.util.Random;import javax.swing.ImageIcon;public class Planet extends Thread{private static final int CENTRAL_X=942;//中心X坐標(biāo)private static final int CENTRAL_Y=490;//中心Y坐標(biāo)private static final int LINE_SIZE=4;//軌道寬度//依次為太陽(yáng),水星,金星,地球,月球,火星,木星,土星,天王星,海王星的尺寸private int[] size= {200,15,30,36,12,25,80,100,70,70};//依次為,水星,金星,地球,月球,火星,木星,土星,天王星,海王星的軌道半徑,第一位0空出,使數(shù)組與size對(duì)應(yīng)private double[] r= {0,90,160,300,60,450,600,820,900,1000};private int[] x=new int[9];//行星的X坐標(biāo)private int[] y=new int[9];//行星的Y坐標(biāo)private double[] angle=new double[9]; //繪制行星所需角度private double line_angle=0;//繪制軌道時(shí)所需的角度private URI uri;private URL url;private AudioClip ac; private boolean turn=false;private Graphics G; //面板畫布public void setG(Graphics g) {this.G=g;}public void turn() {this.turn=!this.turn;}/*** * @param r 半徑* @param angle 角度* @return 行星相對(duì)運(yùn)動(dòng)中心的Y坐標(biāo)*/public int setY(double r,double angle) {return -(int)(r*Math.sin((angle/180)*Math.PI)*Math.sqrt(2)/4);}public int setX(double r,double angle,int y) {return (int)(r*Math.cos((angle/180)*Math.PI))-y;}public void run() {for(int i =0;i<angle.length;i++) {angle[i]=new Random().nextInt(360); //讓行星從軌道上隨機(jī)的一個(gè)位置出發(fā)}//創(chuàng)建緩沖圖片BufferedImage buff=new BufferedImage(1900,1000,BufferedImage.TYPE_INT_ARGB);Graphics g=buff.getGraphics();ImageIcon background=new ImageIcon("image/cosmos.jpg");ImageIcon Sun =new ImageIcon("image/太陽(yáng).png");ImageIcon Mercury =new ImageIcon("image/水星.png");ImageIcon Venus =new ImageIcon("image/金星.png");ImageIcon Earth =new ImageIcon("image/地球.png");ImageIcon Moon = new ImageIcon("image/月球.png");ImageIcon Mars = new ImageIcon("image/火星.png");ImageIcon Jupiter = new ImageIcon("image/木星.png");ImageIcon Saturn = new ImageIcon("image/土星.png"); // ImageIcon Uranus = new ImageIcon("image/天王星.png"); // ImageIcon Neptune = new ImageIcon("image/海王星.png");//添加背景音樂(lè)File f1 = new File("music/Cornfield Chase.wav");try {uri = f1.toURI();url = uri.toURL();} catch (MalformedURLException e1) {// TODO Auto-generated catch blocke1.printStackTrace();}ac = Applet.newAudioClip(url);ac.loop();while (true) {try {Thread.sleep(42);} catch (InterruptedException e) {// TODO Auto-generated catch blocke.printStackTrace();}if (turn) {g.drawImage(background.getImage(), 0, 0, buff.getWidth(), buff.getHeight(), null);for (int i = 1; i < 8; i++) {y[i] = setY(r[i], angle[i]);x[i] = setX(r[i], angle[i], y[i]);}g.setColor(Color.BLACK);for (int i = 0; i < 3600; i++) {//軌道for (int j = 3; j < 8; j++) {if (j == 4) {int y0 = setY(r[j], line_angle);int x0 = setX(r[j], line_angle, y0);g.fillOval(x0 + x[3] + CENTRAL_X - 2, y0 + y[3] + CENTRAL_Y - 2, 4, 4); //月球軌道} else {int y0 = setY(r[j], line_angle);int x0 = setX(r[j], line_angle, y0);g.fillOval(x0 + CENTRAL_X - 2, y0 + CENTRAL_Y - 2, 4, 4);}}line_angle += 0.1;}for (int i = 0; i < 2700; i++) { //中間會(huì)發(fā)生重疊的軌道分為兩部分分開畫int y1 = setY(r[1], line_angle-20);int x1 = setX(r[1], line_angle-20, y1);g.fillOval(x1 + CENTRAL_X - 2, y1 + CENTRAL_Y - 2, 4, 4);int y2 = setY(r[2], line_angle-20);int x2 = setX(r[2], line_angle-20, y2);g.fillOval(x2 + CENTRAL_X - 2, y2 + CENTRAL_Y - 2, 4, 4);line_angle += 0.1;}if (y[1] > 0) {// 水星在太陽(yáng)前if (y[2] > 0) {// 金星在太陽(yáng)前g.drawImage(Sun.getImage(), CENTRAL_X - size[0] / 2, CENTRAL_Y - size[0] / 2, size[0], size[0],null);for (int i = 0; i < 900; i++) {int y1 = setY(r[1], line_angle-20);int x1 = setX(r[1], line_angle-20, y1);g.fillOval(x1 + CENTRAL_X - 2, y1 + CENTRAL_Y - 2, 4, 4);int y2 = setY(r[2], line_angle-20);int x2 = setX(r[2], line_angle-20, y2);g.fillOval(x2 + CENTRAL_X - 2, y2 + CENTRAL_Y - 2, 4, 4);line_angle += 0.1;}g.drawImage(Mercury.getImage(), x[1] + CENTRAL_X - size[1] / 2, y[1] + CENTRAL_Y - size[1] / 2,size[1], size[1], null);g.drawImage(Venus.getImage(), x[2] + CENTRAL_X - size[2] / 2, y[2] + CENTRAL_Y - size[2] / 2,size[2], size[2], null);} else {// 金星在太陽(yáng)后g.drawImage(Venus.getImage(), x[2] + CENTRAL_X - size[2] / 2, y[2] + CENTRAL_Y - size[2] / 2,size[2], size[2], null);g.drawImage(Sun.getImage(), CENTRAL_X - size[0] / 2, CENTRAL_Y - size[0] / 2, size[0], size[0],null);for (int i = 0; i < 900; i++) {int y1 = setY(r[1], line_angle-20);int x1 = setX(r[1], line_angle-20, y1);g.fillOval(x1 + CENTRAL_X - 2, y1 + CENTRAL_Y - 2, 4, 4);int y2 = setY(r[2], line_angle-20);int x2 = setX(r[2], line_angle-20, y2);g.fillOval(x2 + CENTRAL_X - 2, y2 + CENTRAL_Y - 2, 4, 4);line_angle += 0.1;}g.drawImage(Mercury.getImage(), x[1] + CENTRAL_X - size[1] / 2, y[1] + CENTRAL_Y - size[1] / 2,size[1], size[1], null);}} else {//水星在太陽(yáng)后if (y[2] > 0) {//金星在太陽(yáng)前g.drawImage(Mercury.getImage(), x[1] + CENTRAL_X - size[1] / 2, y[1] + CENTRAL_Y - size[1] / 2,size[1], size[1], null);g.drawImage(Sun.getImage(), CENTRAL_X - size[0] / 2, CENTRAL_Y - size[0] / 2, size[0], size[0],null);for (int i = 0; i < 900; i++) {int y1 = setY(r[1], line_angle-20);int x1 = setX(r[1], line_angle-20, y1);g.fillOval(x1 + CENTRAL_X - 2, y1 + CENTRAL_Y - 2, 4, 4);int y2 = setY(r[2], line_angle-20);int x2 = setX(r[2], line_angle-20, y2);g.fillOval(x2 + CENTRAL_X - 2, y2 + CENTRAL_Y - 2, 4, 4);line_angle += 0.1;}g.drawImage(Venus.getImage(), x[2] + CENTRAL_X - size[2] / 2, y[2] + CENTRAL_Y - size[2] / 2,size[2], size[2], null);} else {//金星在太陽(yáng)后g.drawImage(Venus.getImage(), x[2] + CENTRAL_X - size[2] / 2, y[2] + CENTRAL_Y - size[2] / 2,size[2], size[2], null);g.drawImage(Mercury.getImage(), x[1] + CENTRAL_X - size[1] / 2, y[1] + CENTRAL_Y - size[1] / 2,size[1], size[1], null);g.drawImage(Sun.getImage(), CENTRAL_X - size[0] / 2, CENTRAL_Y - size[0] / 2, size[0], size[0],null);for (int i = 0; i < 900; i++) {int y1 = setY(r[1], line_angle-20);int x1 = setX(r[1], line_angle-20, y1);g.fillOval(x1 + CENTRAL_X - 2, y1 + CENTRAL_Y - 2, 4, 4);int y2 = setY(r[2], line_angle-20);int x2 = setX(r[2], line_angle-20, y2);g.fillOval(x2 + CENTRAL_X - 2, y2 + CENTRAL_Y - 2, 4, 4);line_angle += 0.1;}}}g.drawImage(Earth.getImage(), x[3] + CENTRAL_X - size[3] / 2, y[3] + CENTRAL_Y - size[3] / 2, size[3],size[3], null);g.drawImage(Moon.getImage(), x[4] + x[3] + CENTRAL_X - size[4] / 2,y[4] + y[3] + CENTRAL_Y - size[4] / 2, size[4], size[4], null);g.drawImage(Mars.getImage(), x[5] + CENTRAL_X - size[5] / 2, y[5] + CENTRAL_Y - size[5] / 2, size[5],size[5], null);g.drawImage(Jupiter.getImage(), x[6] + CENTRAL_X - size[6] / 2, y[6] + CENTRAL_Y - size[6] / 2, size[6],size[6], null);g.drawImage(Saturn.getImage(), x[7] + CENTRAL_X - size[7] / 2, y[7] + CENTRAL_Y - size[7] / 2, size[7],size[7], null);// 將緩沖圖片畫到面板上G.drawImage(buff, 0, 0, null);// 運(yùn)動(dòng)速度angle[1] += 4;angle[2] += 1.5;angle[3] += 1;angle[4] += 12;angle[5] += 0.5;angle[6] += 0.1;angle[7] += 0.06;}}} }背景音樂(lè)和圖片就不提供了,有興趣的讀者可以自行尋找圖片和背景音樂(lè)。
總結(jié)
以上是生活随笔為你收集整理的Java太阳系行星运动模型的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java——IO流整理(一)
- 下一篇: 处理分页 上一页 下一页首页 末页问题