提交 948fe7ae 编写于 作者: 三月三net's avatar 三月三net

Python超人-宇宙模拟器

上级 2d83330b
# -*- 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)
......@@ -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
......
......@@ -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):
"""
天体计时器,原理就是:
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册