Java太阳系行星运动模型

基本思路

首先,为了让行星运动看起来更加地逼真,采用斜二测画法计算行星的轨道,并将其绘制出来,再将无背景的PNG行星图片按照一定的大小比例绘制在对应的轨道上的某一点。同时,为了让行星运动起来,我们需要用一个循环,不停地计算行星的坐标,并将其绘制。在这之前,要将之前绘制的所有图片进行擦除,也就是清屏(这一操作放在循环当中)。在执行循环的过程中要在绘制图片和清屏之前加上一个时间间隔,这样才能让我们看到图片。这样呈现出的效果就是每个行星在其对应的轨道上运动。这个过程采用一个线程来执行。

此程序的核心算法

计算轨道的方程和计算行星的坐标在原理上是一致的,绘制轨道就是把行星在轨道上的每一点的坐标计算出来,并画上一个点,为了让效果更加明显,我采用了绘制一个半径为2个像素点的圆形的办法。

接下来我们考虑如何来计算轨道上每个点的坐标。因为考虑到行星运动近似圆周运动,因此我们采用将极坐标转化为直角坐标系的办法,即确定了轨道半径和角度,便可以计算出该坐标了。

数学公式如下:
y=√2/4 × r × sin(θ)
x=r × cos(θ)+y

在程序中定义的角度angle是一般的角度,要将它转换成弧度制,于是前面的θ应该写成(angle/180)*π。具体的实现方法如下:

/**
	 * 
	 * @param r 半径
	 * @param angle 角度
	 * @return 行星相对运动中心的Y坐标
	 */
	public int setY(double r,double angle) {
   
	//由于屏幕中的原点是在左上角,因此y坐标添加一个负号
		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;
	}

计算出的这些坐标需要加上屏幕中心点的坐标(让轨道移动到屏幕中间)。

遇到的问题和解决办法

在绘制行星的过程中要考虑哪个行星先画,原则上y坐标较小的先画(在屏幕上y坐标更小意味着它距离观测点更远)。这样,当行星图片重叠时,相对观测点更近的图片后画便可以覆盖更远的那张图片,可以呈现更加真实的效果。当考虑多个行星的重叠问题时,它的情况变得十分复杂,目前只能对处于中央的太阳、水星、金星做了相应的处理,对于其他的行星通过控制他们间的距离避免图像重叠问题。但这种方法使得离太阳的距离比例不够协调(虽然本来比例就无法真实还原,因为太阳相对地球等行星,它的半径过于大,并且木星与太阳的距离是地球与太阳的距离的29倍之多)。

除了行星间的图片重叠问题,还有轨道绘制问题,一般情况下,轨道最先画,确保轨道不会挡住行星,但考虑到中央的太阳会将水星与金星的一部分轨道覆盖,所以这部分的轨道绘制也要做特殊处理。

还有一个小问题,轨道是具有宽度的,要让行星的中心位于轨道的中心就要做相应的调整。具体实现如下:

for (int i = 0; i < 2700; 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;
}
if (y[1] > 0) {
   // 水星在太阳前
	if (y[2] > 0) {
   // 金星在太阳前
		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 {
   // 金星在太阳后
		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 {
   //水星在太阳后
	if (y[2] > 0) {
   //金星在太阳前
		g.drawImage
  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值