Browse Source

更新了速度计算系统,减少了误差

SongZihuan 4 years ago
parent
commit
4ae330c87c
1 changed files with 122 additions and 36 deletions
  1. 122 36
      __main__.py

+ 122 - 36
__main__.py

@@ -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: