Python 动态模拟二维天体运行 (2020年9月24日)


制作背景

大二刚刚开学不久,在一天星期一的下午,寝室里做的,这个模拟二维天体运动的程序之前一直都有尝试,但是由于公式计算不正确的原因一直没有成功过,这次才终于成功。

此程序的灵感来源于一个网站上的平面宇宙沙盒游戏,之前在看b站有关三体运动的视频的时候发现的。

之前想通过PIL库,把天梯的运行轨迹静态的刻画在一张矢量图片上,但是通过Python计算机二级考试的内容让我了解到了还有叫turtle,即“海龟绘图”这个内置库,可以动态的在屏幕上回值直线和曲线,于是这次我便使用了这种方式来展现出来。

效果截图

天体运动1

天体运动2

天体运动3

源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# -*- encoding: utf-8 -*-
"""
天体运行 二维平面模拟
2020年9月24日
by littlefean
"""
import turtle
from random import randint


def main():
# 普朗克时间(最小时间分度)
dt = 1
Earth = Planet("earth")
Sun = Planet("sun")
turtle.goto(Sun.loc)
turtle.pendown()
for i in range(10):
turtle.goto(Sun.loc[0] + randint(1, 5), Sun.loc[1] + randint(1, 5))
Earth.loc = (150, 0)

turtle.penup()
turtle.goto(Earth.loc)
turtle.pendown()

Earth.v = (0, 0.5) # up
Earth.m = 4

Sun.m = 5

while True:
# 更新地球的合外力
Earth.force = ((
f(Earth, Sun) * ((Sun.loc[0] - Earth.loc[0]) / r(Earth.loc, Sun.loc)),
f(Earth, Sun) * ((Sun.loc[1] - Earth.loc[1]) / r(Earth.loc, Sun.loc))
))

# 更新地球的加速度
Earth.a = ((
Earth.force[0] / Earth.m,
Earth.force[1] / Earth.m
))
# 更新地球的速度
Earth.v = ((
Earth.v[0] + Earth.a[0] * dt,
Earth.v[1] + Earth.a[1] * dt,
))
# 更新地球的位置
Earth.loc = ((
Earth.loc[0] + Earth.v[0] * dt,
Earth.loc[1] + Earth.v[1] * dt
))
turtle.goto(Earth.loc[0], Earth.loc[1])
# return


class Planet:
"""
星球类
默认位置,速度矢量,加速度矢量,均为 (0, 0)
"""

def __init__(self, name):
self.name = name
self.loc = (0, 0)
self.v = (0, 0)
self.a = (0, 0)
self.m = 5e10 # 默认为地球的质量
self.force = (0, 0) # 这里是合外力

def __str__(self):
return f"x:{self.loc[0]},y:{self.loc[1]}"

__repr__ = __str__


def r(locationA, locationB):
"""
计算两点之间的位置
:param locationA: A点的位置
:param locationB: B点的位置
:return: AB之间的距离
"""
x1, y1 = locationA
x2, y2 = locationB
distance = ((x1 - x2) ** 2 + (y1 - y2) ** 2) ** 0.5
return distance


def f(planetA, planetB):
"""
计算AB星球之间的万有引力,返回力的数值
:param planetA:
:param planetB:
:return:
"""
G = 9.8
force = G * planetA.m * planetB.m / r(planetA.loc, planetB.loc) ** 2
return force


if __name__ == '__main__':
main()

反思

还需要增强面向对象的意识,关于力的函数f,使用的是一个函数,返回力的大小,然后再将其转化成一个数组。不如加一个class叫vector,
直接写一个函数getForce返回一个vector。