# -*- coding:utf-8 -*- # title :太阳地球月球场景模拟 # description :太阳地球月球场景模拟(月球始终一面朝向地球、月球对地球的扰动) # author :Python超人 # date :2024-03-14 # link :https://gitcode.net/pythoncr/ # python_version :3.9 # ============================================================================== from bodies import Sun, Earth, Moon from common.celestial_data_service import init_bodies_reality_pos_vels, set_solar_system_celestial_position, \ get_reality_orbit_points from objs import CoreValagaClas, SciFiBomber, WaterDrop from common.consts import AU, SECONDS_PER_DAY, SECONDS_PER_WEEK, SECONDS_PER_MONTH from sim_scenes.func import ursina_run, camera_look_at, create_text_panel, create_sphere_sky from sim_scenes.universe_sim_scenes import UniverseSimScenes from simulators.ursina.entities.body_timer import TimeData from simulators.ursina.entities.entity_utils import create_directional_light from simulators.ursina.ui.control_ui import ControlUI from simulators.ursina.ursina_config import UrsinaConfig from simulators.ursina.ursina_event import UrsinaEvent from simulators.ursina.ursina_mesh import create_orbit_by_points class SunEarthMoonSim(UniverseSimScenes): def __init__(self): self.sun = None self.moon = None self.earth = None self.earth_start = None self.bodies = None self.orbit_lines = [] self.run_finished = False def build_bodies(self): # region 构建太阳系 self.sun = Sun(size_scale=6e1, texture="sun_light.jpg") self.moon = Moon(size_scale=18e2) self.earth = Earth(size_scale=9e2, show_trail=False) self.earth_start = Earth(size_scale=9e2, show_trail=False, rotation_speed=0) self.bodies = [self.sun, self.earth, self.moon, self.earth_start] for body in self.bodies: body.init_velocity = [0, 0, 0] def set_bodies_position(self, time_data: TimeData): """ 设置天体的位置(包含速度和加速度的信息) @param time_data: @return: """ t = self.start_time + time_data.total_days set_solar_system_celestial_position(self.bodies, t, True) if len(self.bodies) == 4: self.bodies = self.bodies[0:3] def on_timer_changed(self, time_data): """ @param time_data: @return: """ if self.run_finished: return dt = time_data.get_datetime(self.start_time) if dt.year == 2025: self.run_finished = True self.earth.rotation_speed = 0 return if dt.month < 11: UrsinaConfig.run_speed_factor = 200 elif UrsinaConfig.run_speed_factor > 20: UrsinaConfig.run_speed_factor = 20 if dt.month >= 12 and dt.day >= 31: UrsinaConfig.run_speed_factor -= 0.1 elif dt.month >= 12 and dt.day >= 28 and UrsinaConfig.run_speed_factor >= 1.1: UrsinaConfig.run_speed_factor -= 0.8 # elif dt.month >= 12 :#and dt.day > 20: # UrsinaConfig.run_speed_factor -= 1 if UrsinaConfig.run_speed_factor < 0.1: UrsinaConfig.run_speed_factor = 0.1 UrsinaConfig.run_speed_factor = round(UrsinaConfig.run_speed_factor, 2) self.set_bodies_position(time_data) self.update_text_panel(dt) def create_orbit_line(self, center_body, body, start_time, alpha=0.2): import math if not hasattr(body, "orbital_days"): return None orbital_days = int(math.ceil(body.orbital_days)) points = get_reality_orbit_points(type(body).__name__.lower(), start_time=start_time, days=orbital_days, segments=100) # print(points) orbit_line = create_orbit_by_points(center_body.position, points, line_color=body.trail_color, alpha=alpha) return orbit_line def create_orbit_lines(self): """ 创建太阳系天体的真实轨迹(太阳和哈雷彗星除外) @return: """ self.create_orbit_line(self.sun, self.earth, self.start_time, alpha=0.5) # for body in self.bodies[1:]: # if isinstance(body, Earth): # alpha = 0.5 # else: # alpha = 0.2 # orbit_line = self.create_orbit_line(self.sun, body, self.start_time, alpha=alpha) # if orbit_line is not None: # self.orbit_lines.append(orbit_line) def init_settings(self): """ 初始化设置 @return: """ from ursina import color # 创建天空 create_sphere_sky(scale=5000) # UrsinaConfig.trail_type = "curve_line" UrsinaConfig.trail_type = "line" UrsinaConfig.trail_length = 860 UrsinaConfig.trail_thickness_factor = 2 UrsinaConfig.run_speed_factor = 20 # camera.clip_plane_near = 0.1 # camera.clip_plane_far = 51000 # camera.fov = 60 # self.sun.planet.color = color.white # application.time_scale = 0.01 # 摄像机移动 update # camera_move_update() # camera_move_to_target_update() def show_clock(self, dt): """ 显示时钟 @param dt: 时间 datetime @return: """ # if self.clock_position_center: # position, origin = (0, .25), (0, 0), # else: from ursina import window aspect_ratio = window.aspect_ratio position, origin = (0.5 * aspect_ratio - 0.15, -0.45), (-0.05, 0.1), ControlUI.current_ui.show_message(dt.strftime('%Y-%m-%d'), position=position, origin=origin, # font="verdana.ttf", font="fonts/Digital-7Mono.TTF", font_scale=2, font_color=(0, 255, 0), close_time=-1) self.text_panel.text = "时间:\n" + dt.strftime('%Y-%m-%d %H:%M') + "\n" + \ "运行速度:" + str(UrsinaConfig.run_speed_factor) + "\n" def update_text_panel(self, dt): """ 更新文字信息面板 @param d_sun: @return: """ # panel_text = "时间" #"\n\n当前速度:%s km/s" % "{:.3f}".format(velocity).rjust(6, "0") # # self.text_panel.text = panel_text self.show_clock(dt) def on_ready(self): """ 事件绑定后,模拟器运行前会触发 @return: """ # 初始化设置 self.init_settings() self.earth_start.planet.alpha = 0.5 # self.set_window_size((int(1920 * r), int(1080 * r)), False) # 最大分辨率的高度-1,保证不全屏 # self.set_window_size((1920, 1079), False) # self.set_window_size((1920 , 1080 ), False) camera_look_at(self.sun) # 显示网格以及坐标线 # self.show_grid_axises(scale_factor=100) # 创建太阳系天体的真实轨迹(太阳和哈雷彗星除外) self.create_orbit_lines() # 创建信息显示面板 # self.text_panel = create_text_panel(font="fonts/sanjixiaozhuanti.ttf", font_scale=1.5) self.text_panel = create_text_panel(font="fonts/DroidSansFallback.ttf", font_scale=1.3) def run(self, start_time='2024-01-01 00:00:00'): self.build_bodies() from astropy.time import Time from datetime import datetime start_time = Time(datetime.strptime(start_time + '+0800', '%Y-%m-%d %H:%M:%S%z'), format='datetime') # 运行中,每时每刻都会触发 on_timer_changed UrsinaEvent.on_timer_changed_subscription(self.on_timer_changed) # 运行前会触发 on_ready UrsinaEvent.on_ready_subscription(self.on_ready) # init_bodies_reality_pos_vels(self.bodies, start_time) self.start_time = start_time ursina_run(self.bodies, SECONDS_PER_DAY, position=(0, 3.5 * AU, -AU), gravity_works=False, cosmic_bg='', show_trail=True, # bg_music='sounds/no_glory.mp3', show_camera_info=False, # video_recoder=True, show_control_info=False, timer_enabled=True, show_grid=False ) if __name__ == '__main__': sim = SunEarthMoonSim() sim.run()