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

Python超人-宇宙模拟器

上级 30b8ddd2
......@@ -136,8 +136,8 @@ def calc_simulator(params, factor=1):
def before_evolve(dt, context: CalcContext):
sim.start_time = conv_to_astropy_time(params.start_time)
# td = TimeData(sim.total_times * dt, BodyTimer.MIN_UNIT_SECONDS)
time_data = TimeData(sim.total_times * dt, BodyTimer.MIN_UNIT_SECONDS)
# td = TimeData(sim.total_times * dt, BodyTimer.MIN_UNIT_SECONDS, dt)
time_data = TimeData(sim.total_times * dt, BodyTimer.MIN_UNIT_SECONDS, dt)
sim.total_times += 1
t = sim.start_time + time_data.total_days
......@@ -157,7 +157,7 @@ def calc_simulator(params, factor=1):
d_sun = calculate_distance(sim.halley_comet.position, sim.sun.position)
d_earth = calculate_distance(sim.halley_comet.position, sim.earth.position)
time_data = context.get_param("time_data")
# td = TimeData(sim.total_times * dt * UrsinaSimulator.INTERVAL_FATOR, BodyTimer.MIN_UNIT_SECONDS)
# td = TimeData(sim.total_times * dt * UrsinaSimulator.INTERVAL_FATOR, BodyTimer.MIN_UNIT_SECONDS, dt)
# sim.set_bodies_position(td)
......
......@@ -43,7 +43,7 @@ if __name__ == '__main__':
def on_ready():
# 运行前触发
create_sphere_sky(scale=2000)
sky = create_sphere_sky(scale=10000, rotation_y=150)
def on_timer_changed(time_data):
......@@ -52,6 +52,13 @@ if __name__ == '__main__':
# 地球转了一圈(360)就停止,370是留些余量
if abs(earth.planet.rotation_y) > 365:
exit(0)
# from ursina import camera, Vec3, time
# camera.parent.position += Vec3(0.0000001 * time_data.dt, 0, -0.0000003 * time_data.dt)
# Camera3d.look_to(earth.planet)
# camera.parent.look_at(earth.planet)
# # camera.rotation_x = 0
# # camera.rotation_y = 0
# camera.rotation_z = 0
UniverseSimScenes.set_window_size((1920, 1079), False)
......@@ -63,8 +70,8 @@ if __name__ == '__main__':
# 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹
# position = 左-右+、上+下-、前+后-
ursina_run(bodies,
# SECONDS_PER_HOUR / 2,
SECONDS_PER_HOUR,
SECONDS_PER_HOUR / 5,
# SECONDS_PER_HOUR,
position=(1.45 * earth.radius, 0, -30000),
cosmic_bg="", # 无背景(黑色)
show_grid=False, # 不显示网格
......
# -*- coding:utf-8 -*-
# title :虫洞效果模拟
# description :虫洞效果模拟
# author :Python超人
# date :2023-11-19
# link :https://gitcode.net/pythoncr/
# python_version :3.9
# ==============================================================================
import random
from bodies import Sun, Earth, FixedStar
from sim_scenes.universe_sim_scenes import UniverseSimScenes
from simulators.ursina.entities.entity_utils import create_ambient_light
from bodies.universe_body import create_universe_body
from common.consts import SECONDS_PER_DAY, SECONDS_PER_WEEK, SECONDS_PER_MONTH, SECONDS_PER_YEAR, AU
from objs import Obj, SpaceShip, StarWarsSpeeder, ScifiGunship, SciFiBomber, CoreValagaClas
from sim_scenes.func import mayavi_run, mpl_run, ursina_run, camera_look_at, two_bodies_colliding, camera_move_control, \
get_run_speed_factor, create_text_panel
from ursina import camera, application, lerp, Vec3
from bodies import Body
from simulators.ursina.ursina_event import UrsinaEvent
from dataclasses import dataclass, field
import inspect
@dataclass(order=True)
class WormholeInfo:
# entity: object
name: str = field(default='')
position: list[float] = field(default_factory=[0, 0, 0])
camera_target_init_speed: int = 100
camera_init_speed: int = 100
camera_target_speed: int = 1200
camera_target_max_speed: int = 1500
camera_forward_speed: int = - 0.1
camera_max_speed: int = 1500
camera_acc_speed: int = 1.02
camera_forward_acc_speed: int = 0.01
size_factor: float = 16
rotation_x: float = None
rotation_y: float = None
rotation_z: float = None
around_max_count: int = 400
around_max_speed: int = -100
around_min_speed: int = 100
around_direction: str = "right"
around_acc_speed: int = -1.5
class WormholeSim(UniverseSimScenes):
SIZE_SCALE = 1
D = AU / 10 * SIZE_SCALE
def create_universes(self):
D = self.D
# camera_target_init_speed: int = 100
# camera_init_speed: int = 100
# camera_target_speed: int = 1200
# camera_target_max_speed: int = 1500
# camera_forward_speed: int = - 0.1
# camera_max_speed: int = 1500
# camera_acc_speed: int = 1.02
# camera_forward_acc_speed: int = 0.01
# size_factor: float = 16
# rotation_x: float = None
# rotation_y: float = None
# rotation_z: float = None
# around_max_count: int = 400
# around_max_speed: int = -100
# around_min_speed: int = 100
# around_direction: str = "right"
# around_acc_speed: int = -1.5
wormhole_infos = [
{"name": "我们宇宙", "position": [D, 0, -D], "rotation_y": 100, "around_direction": "down",
"camera_forward_speed": 0, "around_max_count": 400},
{"name": "粉色宇宙", "position": [D, 0, D], "rotation_z": 0, "around_acc_speed": -2,
"around_min_speed": 150, "camera_forward_speed": -0.2, "around_max_count": 700},
{"name": "蓝天宇宙", "position": [- D, -D, D], "around_direction": "left", "around_max_count": 600},
{"name": "金色宇宙", "position": [- D, 0, -D], "around_max_count": 600},
{"name": "深红宇宙", "position": [-D, D, D], "around_max_count": 800},
# {"position": [D, -D, D]},
# {"position": [- D, -D, -D]},
# {"position": [- D, 0, D]},
# {"position": [D, D, -D]},
# {"position": [- D, D, -D]},
# {"position": [- D, D, D]},
# {"position": [D, -D, -D]}
]
def build_wormhole_info_param(wormhole_info):
# ps = WormholeInfoParams()
if self.wormholeinfo_default_vals is None:
self.wormholeinfo_default_vals = {}
init_wormholeinfo_default_vals = True
else:
init_wormholeinfo_default_vals = False
ps = {}
attributes = inspect.getmembers(WormholeInfo)
for attr in attributes:
if not attr[0].startswith('_'):
pn = attr[0]
if init_wormholeinfo_default_vals:
self.wormholeinfo_default_vals[pn] = attr[1]
if pn not in wormhole_info.keys():
continue
ps[pn] = wormhole_info[pn] # attr[1].default
return ps
for idx, wormhole_info in enumerate(wormhole_infos):
pos = wormhole_info.get("position", [0, 0, 0])
name = wormhole_info.get("name", f"宇宙{idx}")
ps1 = build_wormhole_info_param(wormhole_info)
ps1["position"] = pos
ps1["name"] = name
universe = self.create_universe(name, idx, pos)
self.universes.append(universe)
self.wormhole_infos[universe] = WormholeInfo(**ps1)
def __init__(self):
D = self.D
self.camera_target = CoreValagaClas(name="摄像机镜头", mass=1e30, color=(111, 140, 255),
# init_position=[0, 0, 0],
init_position=[D, 0, -D],
init_velocity=[0, 0, 0],
size_scale=self.SIZE_SCALE * 1e3).set_ignore_gravity(True)
self.wormholeinfo_default_vals = None
self.camera_target.go_target = None
self.camera_target.go_target_stage = None
self.last_universe = None
self.current_universe = None
self.target_universe = None
self.universes = []
self.fixed_stars = []
self.wormhole_infos = {}
self.create_universes()
self.create_fixed_stars()
self.bodies = [self.camera_target] + self.universes + self.fixed_stars
def create_universe(self, name, idx, position):
if name is None:
name = f"宇宙{idx}"
universe_body = create_universe_body(name, texture=f'cosmic_pan_{idx + 1}.jpg', # self.textures[idx],
size_scale=self.SIZE_SCALE,
init_position=position,
init_velocity=[0, 0, 0],
)
universe_body.set_light_disable(True)
return universe_body
def fixed_stars_D(self):
r = random.random()
D = self.D * (2 + r)
return D
def create_fixed_stars(self):
D = self.fixed_stars_D
positions = [[D(), D(), D()], [D(), D(), -D()], [D(), -D(), D()],
[D(), -D(), -D()], [-D(), D(), D()], [-D(), D(), -D()],
[-D(), -D(), D()], [-D(), -D(), -D()]]
# positions = [[D, D, D], [D, D, -D], [D, -D, D], [D, 0, D], [D, 0, - D], [D, 0, D],
# [D, -D, -D], [-D, D, D], [-D, D, -D], [0, -D, -D], [0, D, D], [0, D, -D],
# [-D, -D, D], [-D, -D, -D], [-D, -D, 0], [-D, -D, 0]]
for position in positions:
fixed_star = FixedStar(color=(200, 200, 200), size_scale=0.5, init_position=position)
fixed_star.glows = (0, 1.1, 1.08)
self.fixed_stars.append(fixed_star)
def init_setting(self):
camera.clip_plane_near = 0.6
# camera.clip_plane_near = 0.01
camera.clip_plane_far = 10000000
# create_sphere_sky(scale=200000)
application.time_scale = 0.001
# camera.scale = 1000
# camera.parent = camera_target.planet
# camera.rotation_x = 90
camera.fov = 120
for universe in self.universes:
universe.planet.collider = "sphere"
universe.planet.enabled = False
camera.forward_speed = 0
def get_wormhole_data(self, data_name, default_val=None, universe=None):
def ret_value():
if default_val is None:
if data_name in self.wormholeinfo_default_vals.keys():
return self.wormholeinfo_default_vals[data_name]
return default_val
if universe is None:
universe = self.current_universe
wormhole_info = self.wormhole_infos[universe]
if wormhole_info is None:
return ret_value()
if not hasattr(wormhole_info, data_name):
return ret_value()
val = getattr(wormhole_info, data_name)
if val is None:
return ret_value()
return val
def universe_reset(self):
self.current_idx += 1
self.target_idx += 1
if self.current_idx > len(self.universes) - 1:
self.current_idx = 0
if self.target_idx > len(self.universes) - 1:
self.target_idx = 0
for u in self.universes:
self.scale_down(u)
u.planet.enabled = False
self.last_universe = self.current_universe
self.current_universe = self.universes[self.current_idx]
self.target_universe = self.universes[self.target_idx]
rotation_x: float = self.get_wormhole_data("rotation_x")
rotation_y: float = self.get_wormhole_data("rotation_y")
rotation_z: float = self.get_wormhole_data("rotation_z")
if rotation_x is not None:
self.current_universe.planet.rotation_x = rotation_x
if rotation_y is not None:
self.current_universe.planet.rotation_y = rotation_y
if rotation_z is not None:
self.current_universe.planet.rotation_z = rotation_z
self.camera_target.speed = self.get_wormhole_data("camera_target_init_speed")
camera.speed = self.get_wormhole_data("camera_init_speed")
if self.last_universe is None:
self.camera_target.go_target = self.target_universe
self.camera_target.go_target_stage = "target_universe"
self.camera_target.go_target_hit = False
else:
self.camera_target.go_target = self.last_universe
self.last_universe.planet.enabled = True
size_factor = self.get_wormhole_data("size_factor", universe=self.last_universe)
self.scale_down(self.last_universe, scale_size=self.SIZE_SCALE * size_factor)
self.camera_target.go_target_stage = "last_universe"
self.camera_target.go_target_hit = False
self.scale_down(u)
self.camera_target.speed = self.get_wormhole_data("camera_target_speed")
camera.forward_speed = self.get_wormhole_data("camera_forward_speed")
self.scale_up(self.current_universe)
# self.scale_down(self.target_universe)
self.current_universe.planet.enabled = True
# self.current_universe.planet.set_light_off()
self.target_universe.planet.enabled = True
# self.target_universe.planet.set_light_off()
def body_update_reset(self):
# for b in self.bodies:
# b.planet.update = lambda: None
self.camera_target.planet.update = lambda: None
def on_ready(self):
"""
事件绑定后,模拟器运行前会触发
@return:
"""
self.init_setting()
# create_ambient_light(parent=camera)
self.current_idx = -1
self.target_idx = 0
self.current_universe = None
self.body_update_reset()
self.universe_reset()
# camera_look_at(self.camera_target)
self.camera_target.planet.collider = "sphere"
self.camera_target.planet.enabled = False
camera.collider = "sphere"
camera.current_universe = self.current_universe
camera_look_at(self.camera_target, rotation_z=0)
# self.text_panel = create_text_panel(font="fonts/DroidSansFallback.ttf", font_scale=1.3)
def update_text_panel(self):
"""
更新文字信息面板
@param d_sun:
@return:
"""
if not hasattr(self, "text_panel"):
return
panel_text = "虫洞穿越宇宙:\n\n当前宇宙:%s " % self.current_universe.name
panel_text += "\n\n下站宇宙:%s" % self.target_universe.name
if self.last_universe is not None:
panel_text += "\n\n上站宇宙:%s " % self.last_universe.name
self.text_panel.text = panel_text
def scale_up(self, obj):
if obj is None:
return
obj.planet.init_scale = self.SIZE_SCALE * 100
def scale_down(self, obj, scale_size=None):
if obj is None:
return
if scale_size is None:
scale_size = self.SIZE_SCALE
obj.planet.init_scale = scale_size
def around_universe(self, around_target):
around_max_count = self.get_wormhole_data("around_max_count")
around_max_speed = self.get_wormhole_data("around_max_speed")
around_min_speed = self.get_wormhole_data("around_min_speed")
around_direction = self.get_wormhole_data("around_direction")
around_acc_speed = self.get_wormhole_data("around_acc_speed")
# around_target = camera
self.camera_target.planet.look_at(around_target)
# print(self.camera_target.planet.rotation_x,self.camera_target.planet.rotation_y,self.camera_target.planet.rotation_z)
planet_direction = getattr(self.camera_target.planet, around_direction)
if not hasattr(self.camera_target, "around_speed"):
self.camera_target.around_speed = 0
if not hasattr(self.camera_target, "around_count"):
self.camera_target.around_count = 0
if self.camera_target.around_count > around_max_count:
if hasattr(self.camera_target, "around_speed") and \
abs(self.camera_target.around_speed) > abs(around_min_speed):
self.camera_target.around_speed -= around_acc_speed
else:
# delattr(self.camera_target, "around_speed")
delattr(self.camera_target, "around_count")
self.camera_target.go_target_stage = "last_universe"
self.camera_target.speed = self.get_wormhole_data("camera_init_speed")
else:
self.camera_target.around_speed += around_acc_speed
if hasattr(self.camera_target, "around_speed"):
if abs(self.camera_target.around_speed) > abs(around_max_speed):
self.camera_target.around_speed = around_max_speed
self.camera_target.planet.position += planet_direction * self.camera_target.around_speed
print("around_speed", self.camera_target.around_speed)
if hasattr(self.camera_target, "around_count"):
self.camera_target.around_count += 1
# camera.forward_speed = -0.05
if abs(camera.forward_speed) > 0.01:
camera_forward_acc_speed = self.get_wormhole_data("camera_forward_acc_speed")
camera.forward_speed += camera_forward_acc_speed
# else:
# camera.forward_speed = 0
def go_last_universe(self, go_target):
if self.camera_target.planet.intersects(go_target).hit:
if not self.camera_target.go_target_hit:
self.camera_target.go_target_hit = True
self.camera_target.go_target_stage = "around_universe"
self.camera_target.go_target = self.target_universe
self.camera_target.speed = self.get_wormhole_data("camera_init_speed")
camera.speed = 1 # 在看上一个宇宙时候,停留一会
# # camera.forward_speed = -0.05
# if camera.forward_speed < 0:
# camera_forward_acc_speed = self.get_wormhole_data("camera_forward_acc_speed")
# camera.forward_speed += camera_forward_acc_speed
# else:
# camera.forward_speed = 0
if hasattr(self.camera_target, "around_speed"):
if abs(self.camera_target.around_speed) > abs(10):
around_acc_speed = self.get_wormhole_data("around_acc_speed")
around_direction = self.get_wormhole_data("around_direction")
planet_direction = getattr(self.camera_target.planet, around_direction)
self.camera_target.around_speed -= around_acc_speed
self.camera_target.planet.position += planet_direction * self.camera_target.around_speed
else:
delattr(self.camera_target, "around_speed")
def on_timer_changed(self, time_data):
self.target_universe.planet.rotation_y -= 0.5
if self.last_universe is not None:
self.last_universe.planet.rotation_y += 0.3
camera_look_at(self.camera_target, rotation_z=0)
# camera.rotation_x -= 2
# self.camera_target.planet.look_at(self.target_universe.planet)
# self.camera_move(time_data)
from ursina import time, distance
camera_max_speed = self.get_wormhole_data("camera_max_speed")
camera_acc_speed = self.get_wormhole_data("camera_acc_speed")
camera_target_max_speed = self.get_wormhole_data("camera_target_max_speed", )
if self.camera_target.go_target is not None:
go_target = self.camera_target.go_target.planet
if self.camera_target.go_target_stage == "around_universe":
# 摄像机镜头环绕目标宇运动(摄像机镜头暂时不去目标)
self.around_universe(go_target)
else:
# 摄像机镜头看向目标宇宙,并逐渐靠近目标
self.camera_target.planet.look_at(go_target)
self.camera_target.planet.position = \
lerp(self.camera_target.planet.position, go_target.position,
self.camera_target.speed * time.dt)
# 摄像机镜头加速度计算(摄像机镜头圆滑效果),并对摄像机镜头移动速度进行限制
self.camera_target.speed *= camera_acc_speed
if self.camera_target.speed > camera_target_max_speed:
self.camera_target.speed = camera_target_max_speed
if self.camera_target.go_target_stage == "last_universe":
# 进入新的宇宙后,摄像机回看上一个宇宙的镜头
self.go_last_universe(go_target)
elif self.camera_target.go_target_stage == "target_universe":
# 摄像机镜头去往新的宇宙进行中
if self.camera_target.planet.intersects(go_target).hit and not self.camera_target.go_target_hit:
# 摄像机镜头达到新的目标宇宙后,摄像机就不后退了
self.camera_target.go_target_hit = True
camera.forward_speed = 0
# camera.speed = 3000 # TODO:这个不能反复执行
# self.camera_target.planet.position += self.camera_target.planet.forward*100
# print(self.camera_target.planet.position)
# 摄像机加速度计算(摄像机圆滑效果)
camera.speed *= camera_acc_speed
if camera.speed > camera_max_speed:
camera.speed = camera_max_speed
if camera.speed != 0:
dd = distance(camera.position, self.target_universe.planet.position)
camera.position = lerp(camera.position, self.target_universe.planet.position, camera.speed * time.dt / dd)
if camera.forward_speed != 0:
camera.position += camera.forward * camera.forward_speed
# if self.camera_target.planet.intersects(self.target_universe.planet).hit:
if camera.intersects(self.target_universe.planet).hit:
self.universe_reset()
self.update_text_panel()
def build_events(self):
# 订阅事件后,上面2个函数功能才会起作用
# 运行中,每时每刻都会触发 on_timer_changed
UrsinaEvent.on_timer_changed_subscription(wormhole_sim.on_timer_changed)
# 运行前会触发 on_ready
UrsinaEvent.on_ready_subscription(wormhole_sim.on_ready)
def run(self):
self.set_window_size((1920, 1079), False)
self.build_events()
# 使用 ursina 查看的运行效果
# 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹
# position = 左-右+、上+下-、前+后-
ursina_run(self.bodies, SECONDS_PER_DAY / 24,
# position=(0, AU / 1200, -1.003 * AU),
# position=[-AU/100, 0, 0],
# position=[0, 0, -AU / 10],
# position=[0, 0, ],
position=[0, self.D, -self.D * 2],
cosmic_bg='',
gravity_works=False,
# bg_music='sounds/no_glory.mp3',
timer_enabled=True,
video_recoder=True,
show_exit_button=False,
show_grid=False,
show_camera_info=False,
show_control_info=False,
show_trail=False)
if __name__ == '__main__':
"""
"""
wormhole_sim = WormholeSim()
wormhole_sim.run()
......@@ -367,7 +367,7 @@ def create_light_ship(size_scale, init_position, speed=LIGHT_SPEED):
init_velocity=[0, 0, speed]).set_light_disable(True)
def create_3d_card(left=-.885, top=0.495, width=0.02, height=0.02):
def create_3d_card(left=-.885, top=0.495, width=0.01, height=0.01):
# 创建一个 Panel 组件
from ursina import Text, Panel, color, camera, Vec3
from simulators.ursina.ursina_config import UrsinaConfig
......@@ -707,13 +707,19 @@ def speed_smooth_adjust_test():
plt.show()
def create_sphere_sky(texture="bg_pan.jpg", scale=8000):
def create_sphere_sky(texture="bg_pan.jpg", scale=8000, rotation_x=None, rotation_y=None, rotation_z=None):
from common.image_utils import find_texture
from simulators.ursina.entities.sphere_sky import SphereSky
sky_texture = find_texture(texture, None)
if sky_texture is not None:
sky = SphereSky(texture=sky_texture)
sky.scale = scale
if rotation_x is not None:
sky.rotation_x = rotation_x
if rotation_y is not None:
sky.rotation_y = rotation_y
if rotation_z is not None:
sky.rotation_z = rotation_z
return sky
else:
print(f'`textures`目录下没有找到图片`{texture}`,请访问如下链接下载,下载后,将图片放在`textures`目录下')
......
......@@ -17,7 +17,7 @@ from simulators.ursina.ursina_event import UrsinaEvent
class TimeData:
def __init__(self, seconds, min_unit):
def __init__(self, seconds, min_unit, dt):
from ursina import time
if not hasattr(TimeData, "app_start_time"):
setattr(TimeData, "app_start_time", time.time())
......@@ -32,6 +32,7 @@ class TimeData:
days, hours = divmod(hours, 24)
years = days // 365
days = days % 365
self.dt = dt
self.years = int(years)
self.days = int(days)
......@@ -196,7 +197,7 @@ class BodyTimer(Singleton):
# time_text = f'{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}'
# print(self.text)
UrsinaEvent.on_timer_changed(TimeData(seconds, self.min_unit))
UrsinaEvent.on_timer_changed(TimeData(seconds, self.min_unit, dt))
def ignore_gravity(self, body):
return True
......
......@@ -37,15 +37,21 @@ class Camera3d(Entity):
def switch_position(self):
if self.camera_pos == "right": # 摄像机右眼
self.x -= 2 * self.eye_distance
# self.x -= 2 * self.eye_distance
self.position += self.left * 2 * self.eye_distance
self.camera_pos = "left"
elif self.camera_pos == "left": # 摄像机左眼
self.x += 2 * self.eye_distance
# self.x += 2 * self.eye_distance
self.position += self.right * 2 * self.eye_distance
self.camera_pos = "right"
def update(self):
pass
@staticmethod
def look_to(target, axis='forward'):
Camera3d.o.camera3d.look_at(target, axis)
@staticmethod
def init(eye_distance=None, init_pos=None):
Camera3d.is_ready = True
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册