From 948fe7ae69d208336f73a0dae69882506732a79e Mon Sep 17 00:00:00 2001 From: march3 Date: Sun, 18 Jun 2023 14:03:10 +0800 Subject: [PATCH] =?UTF-8?q?Python=E8=B6=85=E4=BA=BA-=E5=AE=87=E5=AE=99?= =?UTF-8?q?=E6=A8=A1=E6=8B=9F=E5=99=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sim_lab/solarsystem_planets_size.py | 124 ++++++++++++++++++ .../solar_system/solarsystem_planets_size.py | 28 ++-- simulators/ursina/entities/body_timer.py | 53 ++++++++ 3 files changed, 190 insertions(+), 15 deletions(-) create mode 100644 sim_lab/solarsystem_planets_size.py diff --git a/sim_lab/solarsystem_planets_size.py b/sim_lab/solarsystem_planets_size.py new file mode 100644 index 0000000..9428278 --- /dev/null +++ b/sim_lab/solarsystem_planets_size.py @@ -0,0 +1,124 @@ +# -*- coding:utf-8 -*- +# title :太阳系行星大小比较 +# description :太阳系行星大小比较 +# author :Python超人 +# date :2023-06-17 +# link :https://gitcode.net/pythoncr/ +# python_version :3.8 +# ============================================================================== +from bodies import Sun, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto, Moon +from common.consts import SECONDS_PER_HOUR, SECONDS_PER_DAY, AU +from sim_scenes.func import ursina_run +from simulators.ursina.entities.body_timer import TimeData, AppTimeUtil +from simulators.ursina.entities.entity_utils import create_directional_light +from simulators.ursina.ursina_event import UrsinaEvent +from simulators.ursina.ursina_config import UrsinaConfig + +# 可以调整整体放大倍数 ,比例会保持不变 +FACTOR = 10 +# 地球和月球之间的距离常量,距地距离约: 363104 至 405696 km,平均距离 384000 km +E_M_DISTANCE = 405696 * FACTOR +earth1 = Earth("地球1", size_scale=FACTOR, init_position=[0, 0, 0]) +moon = Moon("月球", size_scale=FACTOR, init_position=[E_M_DISTANCE, 0, 0]) +earth2 = Earth("地球2", texture="earth2.jpg", size_scale=FACTOR) +bodies = [ + earth1, moon, + Mercury(name="水星", size_scale=FACTOR), + Venus(name="金星", size_scale=FACTOR), + earth2, + Mars(name="火星", size_scale=FACTOR), + Jupiter(name="木星", size_scale=FACTOR), + Saturn(name="土星", size_scale=FACTOR).show_rings(False), + Uranus(name="天王星", size_scale=FACTOR), + Neptune(name="海王星", size_scale=FACTOR), + Pluto(name="冥王星", size_scale=FACTOR) +] + +if __name__ == '__main__': + # 使用应用的计时器工具 + app_time_util = AppTimeUtil() + key_point_time_util = AppTimeUtil() + + last_diameter = earth1.diameter * FACTOR / 2 + plant_positions = [] + for i, body in enumerate(bodies): + body.rotation_speed /= 10 # 星体的旋转速度减小10倍 + body.ignore_mass = True + body.init_velocity = [0, 0, 0] + if i >= 2: # 从第三个星球(水星)开始 + plant_positions.append([(body.diameter * FACTOR / 2) + last_diameter, 0, 0]) + last_diameter += body.diameter * FACTOR + # print(body) + import ursina + from ursina import camera, time, Vec3, application + + + def on_ready(): + # 运行前触发 + # 为了较好的立体效果,可以增加太阳光线,光线直射地球(target=earth) + create_directional_light(position=(E_M_DISTANCE / 2, E_M_DISTANCE * 20, -E_M_DISTANCE * 100), + light_num=3, + target=earth1) + application.time_scale = 0.01 + + + key_points = [(E_M_DISTANCE / 2, 0, -E_M_DISTANCE), + (0, 0, -E_M_DISTANCE / 4), + (100000, 0, -E_M_DISTANCE / 4), + (200000, 0, -E_M_DISTANCE / 4), + (300000, 0, -E_M_DISTANCE / 4), + (400000, 0, -E_M_DISTANCE / 4), + (500000, 0, -E_M_DISTANCE), # 木星 + (1800000, 0, -E_M_DISTANCE), # 土星 + (3000000, 0, -E_M_DISTANCE), # 天王星 + (3800000, 0, -E_M_DISTANCE), # 海王星 + (4000000, 0, -E_M_DISTANCE / 10), # 冥王星 + ] + ursina_kps = [Vec3(point) * UrsinaConfig.SCALE_FACTOR for point in key_points] + + interval = 3 + + + def on_timer_changed(time_data: TimeData): + # camera_time = app_time_util.get_param("camera_time", 2) + key_point_index = app_time_util.get_param("key_point_index", 0) + body_index = app_time_util.get_param("body_index", 2) # 从第三个星球(水星)开始 + + if key_point_index + 1 >= len(ursina_kps): + # camera.position = ursina_kps[-1] + return + + if body_index < len(bodies): + last_time = app_time_util.get_param("last_time", interval + 3) # 间隔3秒出现水星 + # 判断是否第一个到达指定的时间 + if app_time_util.is_first_arrival(last_time, time_data): + bodies[body_index].init_position = plant_positions[body_index - 2] + app_time_util.inc_param("body_index", 1) + app_time_util.inc_param("last_time", interval) # 间隔3秒出现下一个行星 + + print("key_point_index", key_point_index) + current_point = ursina_kps[key_point_index] + target_point = ursina_kps[key_point_index + 1] + camera_time = 2 + key_point_index * interval + + if time_data.app_time > camera_time: + dt = (time_data.app_time - camera_time) / interval + if dt <= 1: + camera.position = ursina.lerp(current_point, target_point, dt) + # print(camera.position) + elif key_point_time_util.is_first_arrival(camera_time, time_data): + app_time_util.inc_param("key_point_index", 1) + + + # 运行中,每时每刻都会触发 on_timer_changed + UrsinaEvent.on_timer_changed_subscription(on_timer_changed) + # 运行前会触发 on_ready + UrsinaEvent.on_ready_subscription(on_ready) + + # 使用 ursina 查看的运行效果 + # 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹 + # position = 左-右+、上+下-、前+后- + ursina_run(bodies, SECONDS_PER_HOUR, + position=key_points[0], + view_closely=True, + timer_enabled=True) diff --git a/sim_scenes/solar_system/solarsystem_planets_size.py b/sim_scenes/solar_system/solarsystem_planets_size.py index ddd90b0..f96ddd6 100644 --- a/sim_scenes/solar_system/solarsystem_planets_size.py +++ b/sim_scenes/solar_system/solarsystem_planets_size.py @@ -9,7 +9,7 @@ from bodies import Sun, Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto, Moon from common.consts import SECONDS_PER_HOUR, SECONDS_PER_DAY, AU from sim_scenes.func import mayavi_run, ursina_run -from simulators.ursina.entities.body_timer import TimeData +from simulators.ursina.entities.body_timer import TimeData, AppTimeUtil from simulators.ursina.entities.entity_utils import create_directional_light from simulators.ursina.ursina_event import UrsinaEvent @@ -33,13 +33,13 @@ bodies = [ Pluto(name="冥王星", size_scale=FACTOR) ] -# 从第三个星球(水星)开始 -index = 2 -last_total_hours = 0 - if __name__ == '__main__': last_diameter = earth1.diameter * FACTOR / 2 plant_positions = [] + + # 使用应用的计时器工具 + app_time_util = AppTimeUtil() + for i, body in enumerate(bodies): body.rotation_speed /= 10 # 星体的旋转速度减小10倍 body.ignore_mass = True @@ -59,16 +59,14 @@ if __name__ == '__main__': def on_timer_changed(time_data: TimeData): - global index, last_total_hours - - if index >= len(bodies): - return - total_hours = int(time_data.total_hours) - # 每间隔3个小时,将行星按顺序进行摆放在地球和月球之间 - if total_hours % 3 == 0 and last_total_hours != total_hours: - last_total_hours = total_hours - bodies[index].init_position = plant_positions[index - 2] - index += 1 + body_index = app_time_util.get_param("body_index", 2) # 从第三个星球(水星)开始 + if body_index < len(bodies): + last_time = app_time_util.get_param("last_time", 3) # 间隔3秒出现水星 + # 判断是否第一个到达指定的时间 + if app_time_util.is_first_arrival(last_time, time_data): + bodies[body_index].init_position = plant_positions[body_index - 2] + app_time_util.inc_param("body_index", 1) + app_time_util.inc_param("last_time", 3) # 间隔3秒出现下一个行星 # 运行中,每时每刻都会触发 on_timer_changed diff --git a/simulators/ursina/entities/body_timer.py b/simulators/ursina/entities/body_timer.py index 6a46031..e57ace6 100644 --- a/simulators/ursina/entities/body_timer.py +++ b/simulators/ursina/entities/body_timer.py @@ -18,6 +18,13 @@ from simulators.ursina.ursina_event import UrsinaEvent class TimeData: def __init__(self, seconds, min_unit): + from ursina import time + if not hasattr(TimeData, "app_start_time"): + setattr(TimeData, "app_start_time", time.time()) + self.app_time = 0 + else: + self.app_time = time.time() - getattr(TimeData, "app_start_time") + self.total_seconds = seconds # 获取到 seconds 后,通过下面的计算得到时分秒、年、天 hours, remainder = divmod(seconds, 3600) @@ -65,6 +72,52 @@ class TimeData: return self.total_hours / 24 +class AppTimeUtil: + """ + 应用计数器工具类 + """ + def __init__(self): + self.arrival_time = -1 + self.current_time = 0 + self.params = {} + + def is_first_arrival(self, target_time, time_data: TimeData): + """ + 是否是第一次到达时间 + @param target_time: 目标时间 + @param time_data: 计时器数据 + @return: + """ + self.current_time = int(time_data.app_time) + if self.current_time == self.arrival_time: + return False + + if self.current_time >= int(target_time): + self.arrival_time = self.current_time + return True + + return False + + def update(self, time_data: TimeData): + self.current_time = int(time_data.app_time) + + def clear(self): + self.arrival_time = -1 + + def set_param(self, param_name, val): + self.params[param_name] = val + + def get_param(self, param_name, default_val=None): + if param_name in self.params.keys(): + return self.params[param_name] + self.set_param(param_name, default_val) + return default_val + + def inc_param(self, param_name, inc_val=1, init_val=0): + val = self.params.get(param_name, init_val) + self.set_param(param_name, val + inc_val) + + class BodyTimer(Singleton): """ 天体计时器,原理就是: -- GitLab