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

Python超人-宇宙模拟器

上级 d0849ca1
......@@ -26,7 +26,7 @@ class Neptune(Body):
def __init__(self, name="海王星", mass=1.0241e26,
init_position=[0, 0, 30.7 * AU],
init_velocity=[-5.43, 0, 0],
texture="neptune.png", size_scale=1.0, distance_scale=1.0,
texture="neptune.jpg", size_scale=1.0, distance_scale=1.0,
rotation_speed=22.3463, ignore_mass=False, trail_color=None, show_name=False):
params = {
"name": name,
......
......@@ -15,6 +15,11 @@
"""
MO = 1.9891e30
"""
1光速=299792.458千米/秒,注意:质量为0才能达到光速
"""
LIGHT_SPEED = 299792.458
"""
天文单位
"""
......
......@@ -11,6 +11,7 @@ from common.consts import SECONDS_PER_WEEK, SECONDS_PER_DAY, SECONDS_PER_HALF_DA
from common.system import System
from simulators.ursina.ursina_config import UrsinaConfig
from simulators.ursina.ursina_event import UrsinaEvent
from common.consts import LIGHT_SPEED
def mayavi_run(bodies, dt=SECONDS_PER_WEEK,
......@@ -187,15 +188,18 @@ def create_solar_system_bodies(ignore_mass=False, init_velocity=None):
return bodies
def create_light(size_scale, init_position):
def create_light_body(size_scale, init_position, speed=LIGHT_SPEED):
"""
用天体模拟一个光子
@param size_scale: 光体的大小
@param init_position: 光体的初始位置
@param speed: 光体的速度->1光速=299792.458 千米/秒(km/秒)
@return:
"""
from bodies import Body
return Body(name='光速', mass=0, size_scale=size_scale, color=(255, 255, 0),
return Body(name='光速', mass=0, texture='metal.jpg', size_scale=size_scale, color=(255, 255, 0),
init_position=init_position,
init_velocity=[0, 0, 299792.458]).set_light_disable(True) # 1光速=299792.458 千米/秒(km/秒)
init_velocity=[0, 0, speed]).set_light_disable(True)
def create_text_panel(width=0.35, height=.5):
......
......@@ -6,102 +6,35 @@
# link :https://gitcode.net/pythoncr/
# python_version :3.8
# ==============================================================================
from bodies import Sun, Asteroids, Body
from common.consts import SECONDS_PER_WEEK, SECONDS_PER_DAY, SECONDS_PER_YEAR, AU
from sim_scenes.func import ursina_run, create_solar_system_bodies, create_text_panel, create_light
from simulators.ursina.ursina_event import UrsinaEvent
from ursina import camera
from sim_scenes.func import ursina_run, create_solar_system_bodies, create_light_body
from common.consts import LIGHT_SPEED
from sim_scenes.solar_system.speed_of_light_init import SpeedOfLightInit
# 已到达天体列表
arrived_bodies = []
text_panel = None
arrived_info = ""
camera_follow_light = None # 摄像机固定,不会跟随光
camera_follow_light = 'ForwardView' # 摄像机跟随光,方向是向前看
camera_follow_light = 'SideView' # 摄像机跟随光,方向是侧面看
CAMERA_FOLLOW_LIGHT = None # 不跟随光
CAMERA_FOLLOW_LIGHT = 'ForwardView' # 向前看
CAMERA_FOLLOW_LIGHT = 'SideView' # 侧面看
def on_reset():
global arrived_info
arrived_bodies.clear()
arrived_info = "[00:00:00] 从 [太阳] 出发\n\n"
if text_panel is not None:
text_panel.text = arrived_info
# 订阅重新开始事件
UrsinaEvent.on_reset_subscription(on_reset)
def on_ready():
global text_panel
text_panel = create_text_panel()
text_panel.text = arrived_info
if CAMERA_FOLLOW_LIGHT == "SideView":
camera.parent = light_body.planet
camera.rotation_y = -85
elif CAMERA_FOLLOW_LIGHT == "ForwardView":
light_body.planet.enabled = False
camera.parent = light_body.planet
camera.rotation_y = -15
UrsinaEvent.on_ready_subscription(on_ready)
def on_timer_changed(time_text, time_data):
global arrived_info
years, days, hours, minutes, seconds = time_data
for body in bodies:
if body is light_body or isinstance(body, Sun) \
or body in arrived_bodies or isinstance(body, Asteroids):
# 对于光速天体、太阳、小行星群、“已到达天体列表”中的天体无需计算
continue
# 计算判断,如果光速天体距离到达了某个天体,就记录到“已到达天体列表”中
if light_body.position[2] >= body.position[2]:
arrived_bodies.append(body)
if text_panel is not None:
arrived_info += f"[{time_text}]\t到达\t[{body.name}]\n\n"
text_panel.text = arrived_info
print(f"[{time_text}] 到达 [{body.name}]")
# 订阅计时器事件(记录已到达天体列表)
UrsinaEvent.on_timer_changed_subscription(on_timer_changed)
if CAMERA_FOLLOW_LIGHT == "SideView":
# 摄像机位置 = 前-后+、上+下-、左-右+、
position = (AU, 0, 0)
show_trail = True
light_size_scale = 1e3
light_init_position = [AU / 3, 0, 0]
elif CAMERA_FOLLOW_LIGHT == "ForwardView":
# 摄像机位置 = 左-右+、上+下-、前+后-
position = (0, AU / 10, -AU)
show_trail = False
light_size_scale = 1e2
light_init_position = [AU / 12, 0, 0]
else:
# 摄像机位置 = 左-右+、上+下-、前+后-
position = (0, AU, -6 * AU)
show_trail = True
light_size_scale = 2e3
light_init_position = [AU / 3, 0, 0]
# 实例化一个初始化对象(订阅事件,记录到达每个行星所需要的时间)
init = SpeedOfLightInit(camera_follow_light)
# 创建太阳系天体(忽略质量,引力无效,初速度全部为0)
bodies = create_solar_system_bodies(ignore_mass=True, init_velocity=[0, 0, 0])
# 创建一个以光速前进的天体(模拟一个光子,质量为0才能达到光速)
light_body = create_light(light_size_scale, light_init_position)
# 从 init 对象中获取 光体的大小(light_size_scale),光体的位置(light_init_position)
# 创建一个以光速前进的天体(模拟一个光子) speed=1光速=299792.458千米/秒,注意:质量为0才能达到光速,虽然如此,但也可以试试超光速
light_body = create_light_body(init.light_size_scale, init.light_init_position, speed=LIGHT_SPEED * 1)
# 增加光速天体到天体集合
bodies.append(light_body)
init.bodies = bodies
init.light_body = light_body
init.event_subscription()
# 使用 ursina 查看的运行效果
# 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹
# position = 左-右+、上+下-、前+后-
ursina_run(bodies, 60,
position=position,
show_trail=show_trail, show_timer=True,
position=init.position,
show_trail=init.show_trail, show_timer=True,
# view_closely=True,
bg_music="sounds/interstellar.mp3")
# -*- coding:utf-8 -*-
# title :在太阳系中以光速运行
# description :在太阳系中以光速运行
# author :Python超人
# date :2023-04-05
# link :https://gitcode.net/pythoncr/
# python_version :3.8
# ==============================================================================
from bodies import Sun, Asteroids, Body
from common.consts import AU
from sim_scenes.func import create_text_panel
from simulators.ursina.ursina_event import UrsinaEvent
from ursina import camera
class SpeedOfLightInit:
def __init__(self, camera_follow_light):
"""
@param camera_follow_light: 三种不同的摄像机视角
None # 摄像机固定,不会跟随光
ForwardView # 摄像机跟随光,方向是向前看
SideView # 摄像机跟随光,方向是侧面看
"""
# 存放记录光体已到达天体列表
self.arrived_bodies = []
# 显示消息面板(记录光体已到达天体的时间)
self.text_panel = None
# 显示消息面板的信息(记录光体已到达天体的时间)
self.arrived_info = ""
self.__camera_follow_light = camera_follow_light
self.light_body = None
self.bodies = None
if self.__camera_follow_light == "SideView":
# 摄像机位置 = 前-后+、上+下-、左-右+、
self.position = (AU, 0, 0)
self.show_trail = True
self.light_size_scale = 1e3
self.light_init_position = [AU / 3, 0, 0]
elif self.__camera_follow_light == "ForwardView":
# 摄像机位置 = 左-右+、上+下-、前+后-
self.position = (0, AU / 10, -AU)
self.show_trail = False
self.light_size_scale = 1e2
self.light_init_position = [AU / 12, 0, 0]
else:
# 摄像机位置 = 左-右+、上+下-、前+后-
self.position = (0, AU, -6 * AU)
self.show_trail = True
self.light_size_scale = 2e3
self.light_init_position = [AU / 3, 0, 0]
# 点击了重置按钮
def on_reset(self):
self.arrived_bodies.clear() # 重置存放记录光体已到达天体列表
self.arrived_info = "[00:00:00]\t从 [太阳] 出发\n\n"
if self.text_panel is not None:
self.text_panel.text = self.arrived_info
def event_subscription(self):
# 订阅重新开始事件
UrsinaEvent.on_reset_subscription(self.on_reset)
UrsinaEvent.on_ready_subscription(self.on_ready)
# 订阅计时器事件(记录已到达天体列表)
UrsinaEvent.on_timer_changed_subscription(self.on_timer_changed)
def on_ready(self):
self.text_panel = create_text_panel()
self.text_panel.text = self.arrived_info
if self.__camera_follow_light == "SideView":
camera.parent = self.light_body.planet
camera.rotation_y = -85
elif self.__camera_follow_light == "ForwardView":
self.light_body.planet.enabled = False
camera.parent = self.light_body.planet
camera.rotation_y = -15
def on_timer_changed(self, time_text, time_data):
global arrived_info
years, days, hours, minutes, seconds = time_data
for body in self.bodies:
if body is self.light_body or isinstance(body, Sun) \
or body in self.arrived_bodies or isinstance(body, Asteroids):
# 对于光速天体、太阳、小行星群、“已到达天体列表”中的天体无需计算
continue
# 计算判断,如果光速天体距离到达了某个天体,就记录到“已到达天体列表”中
if self.light_body.position[2] >= body.position[2]:
self.arrived_bodies.append(body)
if self.text_panel is not None:
self.arrived_info += f"[{time_text}]\t到达\t[{body.name}]\n\n"
self.text_panel.text = self.arrived_info
print(f"[{time_text}] 到达 [{body.name}]")
# -*- coding:utf-8 -*-
# title :计时器天体
# description :计时器天体
# title :天体计时器
# description :天体计时器
# author :Python超人
# date :2023-02-11
# link :https://gitcode.net/pythoncr/
......
# -*- coding:utf-8 -*-
# title :创建一个宇宙网格对象
# description :创建一个宇宙网格对象
# author :Python超人
# date :2023-02-11
# link :https://gitcode.net/pythoncr/
# python_version :3.8
# ==============================================================================
from ursina import Entity, camera
class SphereSky(Entity):
def __init__(self, **kwargs):
super().__init__(name='sky', model='sphere', texture='sky_default', scale=1000, double_sided=True)
self.set_light_off()
for key, value in kwargs.items():
setattr(self, key, value)
def update(self):
self.world_position = camera.world_position
# -*- coding:utf-8 -*-
# title :计时器
# description :计时器
# author :Python超人
# date :2023-02-11
# link :https://gitcode.net/pythoncr/
# python_version :3.8
# ==============================================================================
from ursina import Text, Ursina, application
import datetime
from simulators.ursina.ursina_config import UrsinaConfig
from simulators.ursina.ursina_event import UrsinaEvent
class Timer(Text):
def __init__(self):
# 创建一个文本对象来显示计时器的时间
super().__init__(text='00:00', position=(0.65, -0.45), font=UrsinaConfig.CN_FONT)
UrsinaEvent.on_timer_changed_subscription(self.on_timer_changed)
def on_timer_changed(self, time_text, time_data):
self.text = time_text
if __name__ == '__main__':
app = Ursina()
t = Timer()
def update():
t.update()
app.run()
# -*- coding:utf-8 -*-
# title :创建一个宇宙网格对象
# description :创建一个宇宙网格对象
# author :Python超人
# date :2023-02-11
# link :https://gitcode.net/pythoncr/
# python_version :3.8
# ==============================================================================
from ursina import Entity, Grid, color
from simulators.ursina.ursina_mesh import create_arrow_line
class WorldGrid(Entity):
"""
创建一个宇宙网格对象
"""
def draw_axises(self):
"""
画坐标轴
@return:
"""
arrow_x, line_x, text_x = create_arrow_line((0, 0, 0), (10, 0, 0), label="X", color=color.red)
arrow_y, line_y, text_y = create_arrow_line((0, 0, 0), (0, 10, 0), label="Y", color=color.green)
arrow_z, line_z, text_z = create_arrow_line((0, 0, 0), (0, 0, 10), label="Z", color=color.yellow)
def __init__(self):
super().__init__()
s = 120
grid = Entity(model=Grid(s, s), scale=s * 60, color=color.rgba(255, 255, 255, 20), rotation_x=90,
position=(0, -80, 0))
grid.set_light_off()
# self.draw_axises()
......@@ -19,6 +19,8 @@ from simulators.views.ursina_view import UrsinaView
from simulators.ursina.ursina_config import UrsinaConfig
from simulators.simulator import Simulator
from common.system import System
from simulators.ursina.entities.world_grid import WorldGrid
from simulators.ursina.entities.sphere_sky import SphereSky
from common.func import find_file
import datetime
import os
......@@ -26,44 +28,6 @@ from ursina import EditorCamera
from sim_scenes.func import ursina_run
class WorldGrid(Entity):
"""
创建一个宇宙网格对象
"""
def draw_axises(self):
"""
画坐标轴
@return:
"""
arrow_x, line_x, text_x = create_arrow_line((0, 0, 0), (10, 0, 0), label="X", color=color.red)
arrow_y, line_y, text_y = create_arrow_line((0, 0, 0), (0, 10, 0), label="Y", color=color.green)
arrow_z, line_z, text_z = create_arrow_line((0, 0, 0), (0, 0, 10), label="Z", color=color.yellow)
def __init__(self):
super().__init__()
s = 100
grid = Entity(model=Grid(s, s), scale=s * 20, color=color.rgba(255, 255, 255, 20), rotation_x=90,
position=(0, -80, 0))
grid.set_light_off()
# self.draw_axises()
class MySky(Entity):
def __init__(self, **kwargs):
# from ursina.shaders import unlit_shader
super().__init__(name='sky', model='sphere', texture='sky_default', scale=1000, double_sided=True)
self.set_light_off()
for key, value in kwargs.items():
setattr(self, key, value)
def update(self):
self.world_position = camera.world_position
class UrsinaSimulator(Simulator):
"""
Ursina官网: https://www.ursinaengine.org/
......@@ -181,12 +145,11 @@ class UrsinaSimulator(Simulator):
timer = BodyTimer()
timer.calc_time(evolve_dt)
# def create_timer(self):
# from simulators.ursina.entities.timer import Timer
# # 创建一个文本对象来显示计时器的时间
# self.timer = Timer()
# return self.timer
def create_timer(self):
from simulators.ursina.entities.timer import Timer
# 创建一个文本对象来显示计时器的时间
self.timer = Timer()
return self.timer
def cosmic_background(self, texture='../textures/cosmic2.jpg'):
"""
......@@ -204,7 +167,7 @@ class UrsinaSimulator(Simulator):
from ursina import Sky
sky = Sky(texture=texture, scale=sky_scale)
# sky = MySky(texture=texture, scale=sky_scale)
# sky = SphereSky(texture=texture, scale=sky_scale)
sky.scale = sky_scale
# sky.set_shader_input('texture_scale', Vec2(20, 20))
# 一定要够大,如果小于 Sky(texture=texture).scale = 50000,宇宙背景就会出现黑色方洞
......@@ -282,8 +245,8 @@ class UrsinaSimulator(Simulator):
# ui = UrsinaUI()
ctl = ControlUI(ControlHandler(), position=(0.6, 0.5))
# if show_timer:
# self.create_timer()
if self.show_timer:
self.create_timer()
EditorCamera(ignore_paused=True)
# 防止打开中文输入法
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册