|
@@ -22,6 +22,8 @@ class Planet(metaclass=abc.ABCMeta):
|
|
|
self.center: Planet = None
|
|
|
self.x = 0
|
|
|
self.y = 0
|
|
|
+ self.dx = 0 # 每次run的时候,增加的x
|
|
|
+ self.dy = 0
|
|
|
|
|
|
self.r = 0 # 星球半径
|
|
|
self.center_r = 0 # 距离中心天体的半径
|
|
@@ -41,12 +43,15 @@ class Planet(metaclass=abc.ABCMeta):
|
|
|
self.color = color
|
|
|
|
|
|
@abc.abstractmethod
|
|
|
- def draw(self, dx, dy, max_x, max_y): # dx和dy是偏移量
|
|
|
+ def draw(self, dx, dy, max_x, max_y, is_center=True): # dx和dy是偏移量
|
|
|
pass
|
|
|
|
|
|
def get_xy(self): # dx和dy是偏移量
|
|
|
return self.x, self.y
|
|
|
|
|
|
+ def get_dxy(self): # dx和dy是偏移量
|
|
|
+ return self.dx, self.dy
|
|
|
+
|
|
|
def set_name(self, name) -> None: # dx和dy是偏移量
|
|
|
self.name = name
|
|
|
|
|
@@ -72,10 +77,10 @@ class Sun(Planet):
|
|
|
self.set_name("Sun")
|
|
|
self.color = (255, 0, 0)
|
|
|
|
|
|
- def draw(self, dx, dy, max_x, max_y): # dx和dy是偏移量
|
|
|
- dx = int(dx)
|
|
|
- dy = int(dy)
|
|
|
- if dx >= 0 and dy >= 0 and dx < max_x and dy < max_y:
|
|
|
+ def draw(self, dx, dy, max_x, max_y, is_center=True): # dx和dy是偏移量
|
|
|
+ dx = int(dx / on_m)
|
|
|
+ dy = int(dy / on_m)
|
|
|
+ if (0 <= dx < max_x and 0 <= dy < max_y) or is_center:
|
|
|
self.draw_name(dx, dy)
|
|
|
r = int(self.r / on_m)
|
|
|
pygame.draw.circle(screen, self.color, (dx, dy), r, 0)
|
|
@@ -85,15 +90,23 @@ class RunPlanet(Planet):
|
|
|
def __init__(self):
|
|
|
super(RunPlanet, self).__init__()
|
|
|
self.sita = 0 # 与中心天体的角度
|
|
|
+ self.last_sita = 0
|
|
|
self.v = 0 # 线速度
|
|
|
self.v_type = 1 # 0-角速度,1-线速度
|
|
|
|
|
|
- def setting(self, center, m, r, color, center_r):
|
|
|
+ def setting(self, center, m, r, color, center_r, first=True):
|
|
|
self.set_center(center)
|
|
|
self.set_color(color)
|
|
|
self.set_r(r)
|
|
|
self.set_m(m)
|
|
|
self.set_center_r(center_r)
|
|
|
+ if first:
|
|
|
+ cx, cy = center.get_xy()
|
|
|
+ self.y = cy
|
|
|
+ self.x = cx + self.center_r
|
|
|
+ self.r_to_v()
|
|
|
+
|
|
|
+ def r_to_v(self):
|
|
|
v = math.sqrt(G * self.center.m / self.center_r)
|
|
|
self.set_v(v, 1)
|
|
|
|
|
@@ -101,35 +114,84 @@ class RunPlanet(Planet):
|
|
|
self.v = v
|
|
|
self.v_type = v_type
|
|
|
|
|
|
- def draw(self, dx=0, dy=0, max_x=0, max_y=0): # dx和dy是偏移量
|
|
|
+ def draw(self, dx, dy, max_x, max_y, is_center=True): # dx和dy是偏移量
|
|
|
self.run()
|
|
|
- x = int(self.x / on_m + dx)
|
|
|
- y = int(self.y / on_m + dy)
|
|
|
- if x >= 0 and y >= 0 and x < max_x and y < max_y:
|
|
|
+ if is_center:
|
|
|
+ dx += -self.x
|
|
|
+ dy += -self.y
|
|
|
+ x = int((self.x + dx) / on_m)
|
|
|
+ y = int((self.y + dy) / on_m)
|
|
|
+ if 0 <= x < max_x and 0 <= y < max_y:
|
|
|
self.draw_name(dx, dy)
|
|
|
r = int(self.r / on_m)
|
|
|
pygame.draw.circle(screen, self.color, (x, y), r, 0)
|
|
|
|
|
|
def run(self):
|
|
|
- cx, cy = self.get_center_xy()
|
|
|
- self.x = math.sin(self.sita) * self.center_r + cx
|
|
|
- self.y = math.cos(self.sita) * self.center_r + cy
|
|
|
- self.set_sita(self.get_dsita())
|
|
|
- super(RunPlanet, self).run()
|
|
|
+ cx, cy = self.center.get_xy()
|
|
|
+ # 保持与地球相对静止
|
|
|
+ self.dx, self.dy = self.center.get_dxy()
|
|
|
+ sx, sy = self.get_xy()
|
|
|
+ sx += self.dx
|
|
|
+ sy += self.dy
|
|
|
|
|
|
- def get_w(self): # 获取角速度
|
|
|
- if self.v_type == 1:
|
|
|
- return self.v / self.center_r
|
|
|
- else:
|
|
|
- return self.v
|
|
|
+ dx, dy = sx - cx, sy - cy # 两者距离
|
|
|
|
|
|
- def get_dsita(self):
|
|
|
- return self.get_w() * on_time
|
|
|
+ # self.set_center_r(math.sqrt(dx ** 2 + dy ** 2))
|
|
|
+ # self.r_to_v()
|
|
|
|
|
|
- def set_sita(self, new_sita):
|
|
|
- self.sita += new_sita
|
|
|
- if self.sita >= 2 * math.pi:
|
|
|
- self.sita = 0
|
|
|
+ if dx == 0: # 同一竖直线上
|
|
|
+ if dy > 0: # plant在center下面
|
|
|
+ vx = self.v
|
|
|
+ else:
|
|
|
+ vx = -self.v
|
|
|
+ vy = 0
|
|
|
+ elif dy == 0: # 同一竖直线上
|
|
|
+ if dx > 0: # plant在center下面
|
|
|
+ vy = -self.v
|
|
|
+ else:
|
|
|
+ vy = self.v
|
|
|
+ vx = 0
|
|
|
+ else:
|
|
|
+ new_sita = self.get_sita(dx, dy)
|
|
|
+ center_sita = (new_sita - self.sita) / 2 # 取得前进的一半
|
|
|
+ if self.sita > 0 and new_sita < 0: # 跨越了180度界限
|
|
|
+ center_sita = math.pi - center_sita
|
|
|
+
|
|
|
+ vx = math.cos(new_sita + center_sita) * self.v # new_sita向前一半(保证r不会慢慢变大)
|
|
|
+ vy = -math.sin(new_sita + center_sita) * self.v
|
|
|
+ self.last_sita = self.sita
|
|
|
+ self.sita = new_sita
|
|
|
+ self.dx += vx * on_time
|
|
|
+ self.dy += vy * on_time
|
|
|
+ self.x += self.dx
|
|
|
+ self.y += self.dy
|
|
|
+ super(RunPlanet, self).run()
|
|
|
+
|
|
|
+ @staticmethod
|
|
|
+ def get_sita(dx, dy):
|
|
|
+ if dx > 0 and dy > 0: # 右下
|
|
|
+ tan_sita = dx / dy
|
|
|
+ sita = math.atan(tan_sita)
|
|
|
+ elif dx > 0 and dy < 0: # 右上
|
|
|
+ tan_sita = -dy / dx
|
|
|
+ sita = math.atan(tan_sita) + 0.5 * math.pi # +90度
|
|
|
+ elif dx < 0 and dy > 0: # 左下
|
|
|
+ tan_sita = -dx / dy
|
|
|
+ sita = -math.atan(tan_sita)
|
|
|
+ else: # 左上
|
|
|
+ tan_sita = -dy / -dx
|
|
|
+ sita = -math.atan(tan_sita) - 0.5 * math.pi # +90度
|
|
|
+ return sita
|
|
|
+
|
|
|
+ def set_sita(self):
|
|
|
+ cx, cy = self.center.get_xy()
|
|
|
+ sx, sy = self.get_xy()
|
|
|
+ dx, dy = sx - cx, sy - cy
|
|
|
+ sin_sita = dx / dy
|
|
|
+ self.sita = math.asin(sin_sita)
|
|
|
+ # self.sita += new_sita
|
|
|
+ # if self.sita >= 2 * math.pi:
|
|
|
+ # self.sita = 0
|
|
|
|
|
|
|
|
|
class WorldControl:
|
|
@@ -138,7 +200,10 @@ class WorldControl:
|
|
|
"Sun": None,
|
|
|
"Earth": ("Sun", 5.965 * (10 ** 24), 3185696.5, (0, 255, 255), UA),
|
|
|
"Mercury": ("Sun", 3.3 * (10 ** 23), 244 * 10 ** 4, (0, 255, 255), 0.387 * UA),
|
|
|
+ "Mars": ("Sun", 6.4219 * (10 ** 23), 3397 * 10 ** 3, (0, 255, 255), 0.62 * UA),
|
|
|
+ "Venus": ("Sun", 4.869 * (10 ** 24), 6051.8 * 10 ** 3, (0, 255, 255), 0.72 * UA),
|
|
|
"Moon": ("Earth", 7.349 * (10 ** 22), 1738140, (0, 255, 0), 3844 * 10 ** 5),
|
|
|
+ # 质量 半径 颜色 距中心天体半径
|
|
|
}
|
|
|
self.plant_list = []
|
|
|
for name in self.plant:
|
|
@@ -151,14 +216,15 @@ class WorldControl:
|
|
|
else:
|
|
|
tmp = RunPlanet()
|
|
|
tmp.setting(self.plant[self.plant[name][0]], *(self.plant[name][1:]))
|
|
|
+ tmp.set_name(name)
|
|
|
self.plant_list.append(tmp)
|
|
|
self.plant[name] = tmp
|
|
|
|
|
|
self.is_move = False
|
|
|
|
|
|
- self.dx, self.dy = dx, dy
|
|
|
+ self.dx, self.dy = dx * on_m, dy * on_m # 化成沙盒尺寸
|
|
|
self.mx, self.my = dx * 2, dx * 2
|
|
|
- self.dbx, self.dby = dx, dy
|
|
|
+ self.dbx, self.dby = self.dx, self.dy
|
|
|
|
|
|
self.pos = None # 上一次pos
|
|
|
self.dm = UA / 3500
|
|
@@ -169,17 +235,32 @@ class WorldControl:
|
|
|
def draw(self) -> None:
|
|
|
while True:
|
|
|
screen.fill((0, 0, 0))
|
|
|
- x, y = self.plant_list[self.center].get_xy()
|
|
|
- for p in self.plant_list:
|
|
|
- p.draw(self.dx - x / on_m, self.dy - y / on_m, self.mx, self.my)
|
|
|
+ self.plant_list[self.center].draw(self.dx, self.dy, self.mx, self.my, is_center=True) # 先画参考对象
|
|
|
+ x, y = self.plant_list[self.center].get_xy() # 获取偏移
|
|
|
+ for p in self.plant_list[::-1]:
|
|
|
+ if p == self.plant_list[self.center]: # 不绘制参考对象(已经绘制过了)
|
|
|
+ continue
|
|
|
+ p.draw(self.dx - x, self.dy - y, self.mx, self.my, is_center=False)
|
|
|
display.update()
|
|
|
self.event(pygame.event.get())
|
|
|
time.sleep(world_time)
|
|
|
|
|
|
+ def new_on_m(self, old, new):
|
|
|
+ dx = self.dx / old
|
|
|
+ dy = self.dy / old
|
|
|
+ dbx = self.dbx / old
|
|
|
+ dby = self.dby / old
|
|
|
+
|
|
|
+ self.dx = dx * new
|
|
|
+ self.dy = dy * new
|
|
|
+ self.dbx = dbx * new
|
|
|
+ self.dby = dby * new
|
|
|
+
|
|
|
def event(self, event_list: list):
|
|
|
+ global on_m
|
|
|
for event in event_list:
|
|
|
if event.type == pygame.QUIT:
|
|
|
- exit()
|
|
|
+ exit(0)
|
|
|
|
|
|
# 鼠标按下,让状态变成可以移动
|
|
|
elif event.type == pygame.MOUSEBUTTONDOWN:
|
|
@@ -188,9 +269,9 @@ class WorldControl:
|
|
|
|
|
|
# 鼠标弹起,让状态变成不可以移动
|
|
|
elif event.type == pygame.MOUSEBUTTONUP:
|
|
|
- global on_m
|
|
|
if event.button == 4:
|
|
|
self.is_move = False
|
|
|
+ old = on_m
|
|
|
while self.dm >= 1:
|
|
|
on_m -= self.dm
|
|
|
if on_m <= 0:
|
|
@@ -198,11 +279,16 @@ class WorldControl:
|
|
|
self.dm /= 2
|
|
|
else:
|
|
|
break
|
|
|
+ # 调整(dx, dbx等均是沙盒距离)
|
|
|
+ self.new_on_m(old, on_m)
|
|
|
elif event.button == 5:
|
|
|
self.is_move = False
|
|
|
+ old = on_m
|
|
|
on_m += self.dm
|
|
|
if self.dm < self.base_dm:
|
|
|
self.dm *= 2
|
|
|
+ # 调整(dx, dbx等均是沙盒距离)
|
|
|
+ self.new_on_m(old, on_m)
|
|
|
else:
|
|
|
self.is_move = False
|
|
|
self.pos = None
|
|
@@ -210,11 +296,11 @@ class WorldControl:
|
|
|
# 鼠标移动事件
|
|
|
elif event.type == pygame.MOUSEMOTION:
|
|
|
if self.is_move:
|
|
|
- screen.fill((255,255,255))
|
|
|
+ screen.fill((255, 255, 255))
|
|
|
x, y = event.pos
|
|
|
if self.pos:
|
|
|
- self.dx += x - self.pos[0]
|
|
|
- self.dy += y - self.pos[1]
|
|
|
+ self.dx += (x - self.pos[0]) * on_m
|
|
|
+ self.dy += (y - self.pos[1]) * on_m
|
|
|
self.pos = event.pos
|
|
|
|
|
|
elif event.type == pygame.KEYDOWN:
|