# -*- coding:utf-8 -*- # title :太阳系中消失的行星 # description :太阳系中消失的行星 # author :Python超人 # date :2023-12-05 # link :https://gitcode.net/pythoncr/ # python_version :3.9 # ============================================================================== import time from bodies import Sun, Mercury, Venus, Earth, Mars, Moon, Ceres, Jupiter, Saturn, Uranus, Neptune, Pluto, Asteroids from common.consts import SECONDS_PER_WEEK, SECONDS_PER_DAY, SECONDS_PER_MONTH, SECONDS_PER_YEAR, AU from sim_scenes.func import mayavi_run, ursina_run, create_sphere_sky from sim_scenes.universe_sim_scenes import UniverseSimScenes from simulators.func import ext_fun_for_method from simulators.ursina.ursina_event import UrsinaEvent class TheLostPlanetSim(UniverseSimScenes): def __init__(self): self.sun = Sun(size_scale=5e2).set_resolution(60) # 太阳放大 500 倍 self.sun.glows = (30, 1.005, 0.03) # self.asteroids = Asteroids(size_scale=1.08e2, parent=self.sun) # 小行星模拟(仅 ursina 模拟器支持) # 环状星群带(inner_radius, outer_radius, subdivisions) # inner_radius:内圆半径 outer_radius:外圆半径,subdivisions:细分数,控制圆环的细节和精度 # self.asteroids.torus_zone = 4.7, 5.5, 64 self.moon = Moon(size_scale=3e3, init_position=[0, 0, (0.4 + 2.4) * AU], distance_scale=1.76) # ceres = Ceres(size_scale=3e3, distance_scale=1.7) self.earth = Earth(size_scale=3e3, distance_scale=3.8) self.mars = Mars(size_scale=3e3, distance_scale=2.9) self.jupiter = Jupiter(size_scale=0.68e3, distance_scale=1.12) self.saturn = Saturn(size_scale=0.68e3, distance_scale=0.74) self.bodies = [ self.sun, Mercury(size_scale=3e3, distance_scale=7.3), # 水星放大 4000 倍 Venus(size_scale=3e3, distance_scale=4.5), # 金星放大 4000 倍 self.earth, # 地球放大 4000 倍 self.mars, # 火星放大 4000 倍 # asteroids, self.moon, # ceres, # Earth(size_scale=3e3, init_position=[0, 0, (2.17) * AU]), # 地球放大 4000 倍 # Earth(size_scale=3e3, init_position=[0, 0, (3.64) * AU]), # 地球放大 4000 倍 self.jupiter, # 木星放大 680 倍 self.saturn, # 土星放大 680 倍 Uranus(size_scale=0.8e3, distance_scale=0.42), # 天王星放大 800 倍 Neptune(size_scale=1e3, distance_scale=0.3), # 海王星放大 1000 倍 ] # 水星 0.4AU # 金星 0.4+0.3 AU # 地球 0.4+0.6 AU # 火星 0.4+1.2 AU # 木星 0.4+4.8 AU # 土星 0.4+9.6 AU # 天王星 0.4+19.2 AU # d = (n+4)/10 # an = 0.4+0.3×(2n-2) planet_no = -1 for idx, body in enumerate(self.bodies): if isinstance(body, Asteroids): continue body.rotation_speed = 0 planet_no += 1 # body.init_velocity = [0, 0, 0] # an = 0.4 + 0.3 * pow(2,idx) # an = (idx+4)/10 # 其中k=0,1,2,4,8,16,32,64,128 (0以后数字为2的2次方) # 行星 公式推得值 实测值 # 金星 0.7 0.72 # 地球 1 1 # 火星 1.6 1.52 # 谷神星 2.8 2.9 [1] # 木星 5.2 5.2 # 土星 10 9.54 # 天王星 19.6 19.18 # 海王星 38.8 30.06 # 冥王星 77.2 39.44 # 提丢斯-波得定则 # https://baike.baidu.com/item/%E6%8F%90%E4%B8%A2%E6%96%AF-%E6%B3%A2%E5%BE%97%E5%AE%9A%E5%88%99/859407 # 小行星 2.17-3.64天文单位 if planet_no == 0: continue elif planet_no == 1: an = 0.4 else: an = 0.4 + 0.3 * pow(2, planet_no - 2) print(body.name, an, body.position[2] / AU) def on_ready(self): """ 事件绑定后,模拟器运行前会触发 @return: """ from ursina import camera, Vec3 # 创建天空 create_sphere_sky(scale=20000, rotation_x=0, rotation_y=80) camera.clip_plane_near = 0.1 camera.clip_plane_far = 1000000 camera.look_at(self.jupiter.planet) # camera.look_at(sun.planet) camera.rotation_z -= 90 # for i in range(10): # time.sleep(0.1) # create_asteroid() # UniverseSimScenes.show_grid_axises() # self.asteroids.planet.enabled = False self.moon.planet.enabled = False # ceres.planet.enabled = False def set_alpha_animation(self, body, begin_alpha, end_alpha, interval, is_destroy=False): from ursina import destroy if hasattr(body, "planet"): planet = body.planet else: planet = body planet.alpha = begin_alpha if begin_alpha > end_alpha: interval = -abs(interval) else: interval = abs(interval) origin_update = planet.update def alpha_animation(): from ursina import camera, Vec4 origin_update() alpha = planet.alpha alpha += interval if (interval > 0 and alpha >= end_alpha) or (interval < 0 and alpha <= end_alpha): alpha = end_alpha planet.update = origin_update planet.enabled = (alpha > 0) planet.alpha = alpha if is_destroy and not planet.enabled: destroy(planet) # planet.color = Vec4(planet.color[0], planet.color[1], planet.color[2], alpha) # print(planet.alpha) planet.update = alpha_animation # ext_fun_for_method(planet, after_run_fun=alpha_animation) def create_asteroid(self, init_angle=89.5): from ursina import Entity, color, Vec3 import math import random pos = self.moon.planet.position # + Vec3() radius = self.moon.planet.position[2] + 40 * random.random() - 20 # * moon.distance_scale asteroid = Entity(model='sphere', position=pos, color=color.white, scale=1.5) asteroid.s_angle = init_angle y = 10 * random.random() - 5 def rotation(): x = self.sun.planet.x + radius * math.cos(asteroid.s_angle) z = self.sun.planet.z + radius * math.sin(asteroid.s_angle) asteroid.position = (x, y, z) speed = random.random() / 50 asteroid.s_angle += speed asteroid.update = rotation return asteroid def create_asteroids(self): self.asteroids = [] for i in range(500): self.asteroids.append(self.create_asteroid(i)) # def clear_asteroids(self): # for a in self.asteroids: # a.enabled = False def asteroid_fade_in(self): """ 小行星群渐渐显示 @return: """ self.create_asteroids() for a in self.asteroids: self.set_alpha_animation(a, 0.0, 1.0, 0.01) def asteroid_fade_out(self): """ 小行星群渐渐消失 @return: """ for a in self.asteroids: self.set_alpha_animation(a, 1.0, 0.0, 0.01, is_destroy=True) def moon_fade_in(self): """ 月球渐渐显示 @return: """ self.moon.planet.look_at(self.mars.planet) self.moon.planet.update = lambda: None self.set_alpha_animation(self.moon, 0.0, 1.0, 0.005) def moon_renovation(self): """ 月球改造中 @return: """ if not hasattr(self, "moon_redesign_last_time"): self.moon_redesign_last_time = time.time() c_time = time.time() # set_alpha_animation(asteroids, 0.0, 1.0, 0.01) if c_time - self.moon_redesign_last_time > 0.02: self.moon_redesign_last_time = c_time self.create_asteroid() def moon_move_to_target_and_rotation(self, target, rotation_radius, end_angle, end_tag, forward=0.1, angle_val=0.08): from ursina import camera, Vec3, distance import math if hasattr(target, "planet"): target_planet = target.planet.main_entity else: target_planet = target.main_entity self.moon.planet.look_at(target_planet) d = distance(self.moon.planet, target_planet) if d > rotation_radius: self.moon.planet.position += self.moon.planet.forward * forward else: if not hasattr(target_planet, "moon_angle"): setattr(target_planet, "moon_angle", 90) moon_angle = getattr(target_planet, "moon_angle") x = target_planet.x + rotation_radius * math.cos(moon_angle) z = target_planet.z + rotation_radius * math.sin(moon_angle) self.moon.planet.position = (x, 0, z) setattr(target_planet, "moon_angle", moon_angle + angle_val) if moon_angle >= end_angle: setattr(self, end_tag, True) # print("moon_angle", moon_angle) def on_timer_changed(self, time_data): from ursina import camera, Vec3, distance import math if time_data.years > 1 and not hasattr(self, "step_01"): # 小行星群渐渐显示,运行一次 self.asteroid_fade_in() setattr(self, "step_01", True) # 控制运行一次 elif time_data.years > 6 and not hasattr(self, "step_02"): # 小行星群渐渐消失,运行一次 self.asteroid_fade_out() setattr(self, "step_02", True) # 控制运行一次 elif time_data.years > 8 and not hasattr(self.moon, "step_03"): # 月球渐渐显示,运行一次 self.moon_fade_in() setattr(self.moon, "step_03", True) # 控制运行一次 elif time_data.years > 10 and not hasattr(self, "step_04"): # 月球改造中,运行多次 self.moon_renovation() if time_data.years > 25 and not hasattr(self, "moon_around_mars"): setattr(self, "step_04", True) self.moon_move_to_target_and_rotation(target=self.mars, rotation_radius=12, end_angle=110, end_tag="moon_around_mars", forward=0.03, angle_val=0.05) # self.moon.planet.look_at(self.mars.planet) # radius = 12 # d = distance(self.moon.planet, self.mars.planet.position) # if d > 12: # self.moon.planet.position += self.moon.planet.forward * 0.1 # else: # if not hasattr(self.mars, "moon_angle"): # setattr(self.mars, "moon_angle", 90) # # moon_angle = getattr(self.mars, "moon_angle") # x = self.mars.planet.x + radius * math.cos(moon_angle) # z = self.mars.planet.z + radius * math.sin(moon_angle) # self.moon.planet.position = (x, 0, z) # # setattr(self.mars, "moon_angle", moon_angle + 0.08) # # if moon_angle >= 110: # setattr(self.moon, "mars_rotation", True) # print("moon_angle", moon_angle) elif hasattr(self, "moon_around_mars") and not hasattr(self, "moon_around_earth"): self.moon_move_to_target_and_rotation(target=self.earth, rotation_radius=15, end_angle=360, end_tag="moon_around_earth", forward=0.03, angle_val=0.05) # earth_target = self.earth.planet.main_entity # self.moon.planet.look_at(earth_target) # radius = 15 # d = distance(self.moon.planet.position, earth_target.position) # if d > 15: # self.moon.planet.position += self.moon.planet.forward * 0.1 # else: # if not hasattr(self.earth, "moon_angle"): # setattr(self.earth, "moon_angle", 90) # # moon_angle = getattr(self.earth, "moon_angle") # x = earth_target.x + radius * math.cos(moon_angle) # z = earth_target.z + radius * math.sin(moon_angle) # self.moon.planet.position = (x, 0, z) # # setattr(self.earth, "moon_angle", moon_angle + 0.08) # if moon_angle >= 360 * 2 + 90: # setattr(moon, "earth_rotation", True) # print("moon_angle", moon_angle) # moon.planet.world_rotation_z = 90 # moon.planet.position += moon.planet.right * 0.1 # setattr(moon, "years_8", True) # elif time_data.years > 15 and not hasattr(moon, "years_15"): # set_alpha_animation(moon, 1.0, 0.0, 0.05) # setattr(moon, "years_15", True) if __name__ == '__main__': sim = TheLostPlanetSim() # UniverseSimScenes.set_window_size((1920, 1079), False) # 运行前会触发 on_ready UrsinaEvent.on_ready_subscription(sim.on_ready) # UrsinaEvent.after_ready_subscription(after_ready) UrsinaEvent.on_timer_changed_subscription(sim.on_timer_changed) # 使用 ursina 查看的运行效果 # 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹 # position = 左-右+、上+下-、前+后- ursina_run(sim.bodies, SECONDS_PER_YEAR, gravity_works=False, show_exit_button=False, show_control_info=False, show_camera_info=False, # position=(0, 2 * AU, -11 * AU), # position=(0, 20 * AU, 10 * AU), position=(5.5 * AU, AU, 5 * AU), timer_enabled=True, show_timer=True, cosmic_bg='', show_grid=False)