资源素材
现在太阳系只有8颗行星,连太阳一起,总共有9张照片。如果没有朋友,可以在文末下载地址下载。
defopenSolor(solar): defloadImg(name): str1=os.path.join(basePath,name+'.png') img=Image.open(str1) solar[name]=img basePath=r'D:\太阳系\素材' # loadImg('sun') loadImg('venus') loadImg('jupiter') loadImg('earth') loadImg('mars') loadImg('mercury') loadImg('neptune') loadImg('pluto') loadImg('uranus') loadImg('saturn')
基本运动原理
每颗行星的运动轨迹都是椭圆形的,我们用一个参数方程来计算坐标:
x=cos(arc)*a
y=sin(arc)*b
其中,a,b 长轴和短轴为椭圆形,arc为操作角,x,y是水平面坐标。
先上一张静态效果图!
参数的设置
为了好看,实际参数不可能是真实的。但至少应该满足几个关键条件。首先,不要弄错行星顺序。行星轨道之间的间距不是等距的,而是逐渐增加的。
其次,火星和木星直接有一个小行星带,所以最好在这两颗行星的轨道之间留下一个间隙。外圈越多,绕行速度就越慢。
definitSolar(posList): defgetNumber(): returnrandom.randint(0,35)*10 posList['sun']={'pos':(0,360)'rate':2,'scale':1,'radx':1,'layer':360} posList['mercury']={'rate':0.15,'radx':500,'arc':getNumber(),'rady':200,'speed':15} posList['venus']={'rate':0.2,'radx':550,'arc':getNumber(),'rady':250,'speed':10} posList['earth']={'rate':0.2,'radx':630,'arc':getNumber(),'rady':320,'speed':8} posList['mars']={'rate':0.2,'radx':740,'arc':getNumber(),'rady':410,'speed':6} posList['jupiter']={'rate':0.7,'radx':1050,'arc':getNumber(),'rady':650,'speed':4} posList['saturn']={'rate':1,'radx':1250,'arc':getNumber(),'rady':800,'speed':3} posList['uranus']={'rate':0.3,'radx':1480,'arc':getNumber(),'rady':970,'speed':2} posList['neptune']={'rate':0.3,'radx':1740,'arc':getNumber(),'rady':1160,'speed':2}
投影
一般效果是将太阳周围的行星转向一个水平面,然后投影到垂直屏幕上。投影算法并不难。
x=math.sin(math.radians(a))*radx+x0 y=math.cos(math.radians(a))*rady+y0 showX=x showY=midY-H/(D+y)*y
其中,x,y是公转平面坐标,showX,showy是投影到垂直平面的坐标。H是平面的高度,D是从屏幕到太阳系的距离。
从数据的角度来看,我们的太阳系模型是一个非常小的模型,或者计算机屏幕非常大。因为两者实际上是相似的,所以从观察者的角度来看,可以有一个非常明显的近距离效果。从这个效果中,我们可以知道数据和真实值之间的差异非常大。
近大远小的效果只与y有关。
data['scale']=(y0+D)/(y+D)
遮挡效果
要有现实感,行星之间、行星与轨道之间、轨道与太阳之间等的遮挡效果至关重要。
我们的做法是先画后半区,再画太阳,再画前半区。后半部分,远日行星先画;前半部分,近期行星先画。为了保证正确的遮挡效果。
drawOrb(img,solar,posList,0,90,True) pasteSolor(img,solar,posList) drawOrb(img,solar,posList,90,180,False)
更复杂的是行星和它自己的轨道之间的屏蔽关系。必须达到一线球的效果才能看起来很好。球的位置并不是固定的。在这里,我们根据行星的不同角度将轨道分成两半。
一部分轨道被行星挡住,另一部分轨道挡住了行星,但为了达到更自然的穿球效果,留出了一些空间。
drawArc(arc1,arc) rate=posList[name]['rate']*posList[name]['scale'] pic=solarImg[name].resize(effect.tupleRound(effect.tupleMul(solarImg[name].size,rate)),Image.ANTIALIAS) pos=effect.tupleRound(effect.tupleAdd(posList[name]['pos'],effect.tupleMul(pic.size,-0.5))) r,g,b,alpha=pic.split() img.paste(pic,pos,mask=alpha) #穿球点因arc而异 #在中心穿球90度, #越接近0或180度,越接近球的边缘 #根据这一性质,使用cos进行模拟 darc=abs(round(math.cos(math.radians(arc))*solarImg[name].size[1]*rate/50)) #darc=abs(round(math.cos(math.radians(arc))*5)) #print(name,arc,darc) drawArc(arc+darc,arc2)
素材链接:https://pan.baidu.com/s/18ELL4al-jHbIbIacMpVbjA
提取码:5bjj
更多Python知识,请关注Python视频教程!!