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

Python超人-宇宙模拟器

上级 ba31cad0
此差异已折叠。
# -*- coding:utf-8 -*-
# title :虫洞效果模拟
# description :虫洞效果模拟
# author :Python超人
# date :2023-11-03
# link :https://gitcode.net/pythoncr/
# python_version :3.9
# ==============================================================================
from bodies import Sun, Earth
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
from ursina import camera, application, lerp
from bodies import Body
from simulators.ursina.ursina_event import UrsinaEvent
ours_cosmic_bg = "cosmic_pan_1.jpg"
worms_cosmic_bg = "cosmic_pan_4.jpg"
class WormholeSim:
SIZE_SCALE = 1 # 生成的太阳放大 50 倍
RUN_DIAMETER = 1.392e6
velocity_rate = 22
def __init__(self):
self.camera_target = CoreValagaClas(name="摄像机目标", mass=1e30, color=(111, 140, 255),
# init_position=[0, 0, 0],
init_position=[0, 0, AU / 10],
init_velocity=[0, 0, 0],
size_scale=WormholeSim.SIZE_SCALE * 1e1) # .set_ignore_gravity(True)
self.universes = []
self.ours_universe = create_universe_body("我们的宇宙", "cosmic_pan_1.jpg",
size_scale=WormholeSim.SIZE_SCALE,
init_position=[0, 0, -AU / 120],
init_velocity=[0, 0, 0],
)
self.universes.append(self.ours_universe)
self.worm_hole = create_universe_body("虫洞1", "cosmic_pan_4.jpg",
init_position=[0, 0, AU / 120],
init_velocity=[0, 0, 0],
size_scale=WormholeSim.SIZE_SCALE)
self.universes.append(self.worm_hole)
self.bodies = [self.camera_target] + self.universes
def on_ready(self):
"""
事件绑定后,模拟器运行前会触发
@return:
"""
# 创建天空
camera.clip_plane_near = 0.0001
camera.clip_plane_far = 10000000000
# create_sphere_sky(scale=200000)
application.time_scale = 0.001
# camera.scale = 1000
# camera.parent = camera_target.planet
# camera.rotation_x = 90
camera.fov = 100
self.worm_hole.planet.rotation_y = 100
self.ours_universe.planet.rotation_y = 200
self.ours_universe.planet.rotation_x = 30
camera_look_at(self.camera_target)
camera.collider = "sphere"
self.worm_hole.planet.collider = "sphere"
self.ours_universe.planet.init_scale = self.SIZE_SCALE * 1000
self.camera_target.current_universe = self.ours_universe
self.camera_target.targe_universe = self.worm_hole
# camera_position = camera.position
def on_timer_changed(self, time_data):
# return
# pass
# camera_look_at(camera_target)
# camera.rotation_x -= 2
self.camera_target.planet.look_at(self.camera_target.targe_universe.planet)
if camera.intersects(self.camera_target.targe_universe.planet).hit:
# worm_hole.planet.init_scale = SIZE_SCALE * 1000
self.camera_target.current_universe.planet.init_scale = self.SIZE_SCALE
if self.camera_target.targe_universe.planet.init_scale < self.SIZE_SCALE * 1000:
self.camera_target.targe_universe.planet.init_scale *= 1.1
# if ours_universe.planet.init_scale > SIZE_SCALE:
# ours_universe.planet.init_scale /= 1.1
if not hasattr(camera, "init_rotation_y"):
camera.init_rotation_y = camera.rotation_y
camera.rotation_y_v = 0.01
if abs(camera.init_rotation_y - camera.rotation_y) < 10:
camera.rotation_y_v += 0.5
elif abs(camera.init_rotation_y - camera.rotation_y) < 90:
camera.rotation_y_v += 0.3
elif abs(camera.init_rotation_y - camera.rotation_y) < 120:
camera.rotation_y_v -= 0.1
elif abs(camera.init_rotation_y - camera.rotation_y) < 180:
camera.rotation_y_v -= 0.01
if camera.rotation_y_v < 0.1:
camera.rotation_y_v = 0.1
else:
camera.rotation_y_v = 0
camera.rotation_y += camera.rotation_y_v
# camera_look_at(ours_universe)
# else:
# if two_bodies_colliding(camera_target, worm_hole):
# camera_target.stop_and_ignore_gravity()
# print(1,camera_target.planet.position)
# camera_target.planet.position = lerp(camera_target.planet.position, worm_hole.planet.position, 1e-2)
# print(2,camera_target.planet.position)
# camera.position = (camera.position[0],camera.position[1],camera.position[2]) #
camera.position = lerp(camera.position, self.camera_target.planet.position, 0.1e-2)
# camera_position = [camera_position[0], camera_position[1], camera_position[2] - 0.01]
# camera.position = camera_position
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.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],
cosmic_bg='',
# gravity_works=False,
timer_enabled=True,
show_grid=False,
show_trail=False)
if __name__ == '__main__':
"""
"""
wormhole_sim = WormholeSim()
wormhole_sim.run()
# -*- coding:utf-8 -*-
# title :虫洞效果模拟
# description :虫洞效果模拟
# author :Python超人
# date :2023-11-19
# link :https://gitcode.net/pythoncr/
# python_version :3.9
# ==============================================================================
from bodies import Sun, Earth
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 = 2000
camera_target_max_speed: int = 2000
camera_forward_speed: int = - 0.1
camera_max_speed: int = 5000
camera_acc_speed: int = 1.02
camera_forward_acc_speed: int = 0.01
size_factor: float = 10
rotation_x: float = None
rotation_y: float = None
rotation_z: float = None
around_max_count: int = 300
around_max_speed: int = -200
around_min_speed: int = 100
around_direction: str = "right"
around_acc_speed: int = -2
# class WormholeInfoParams:
# def __init__(self):
# self.params = []
#
# def add(self, param_name):
#
# return self
class WormholeSim:
SIZE_SCALE = 1
D = AU / 10 * SIZE_SCALE
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.wormhole_infos = {}
self.create_universes()
self.bodies = [self.camera_target] + self.universes
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],
)
return universe_body
def create_universes(self):
D = self.D
# camera_target_init_speed: int = 100
# camera_init_speed: int = 100
# camera_target_speed: int = 2000
# camera_forward_speed: int = - 0.1
# camera_max_speed: int = 2000
# camera_acc_speed: int = 1.02
# camera_forward_acc_speed: int = 0.01
# size_factor: float = 10
# rotation_x: float = None
# rotation_y: float = None
# rotation_z: float = None
# around_max_count: int = 300
# around_max_speed: int = -200
# around_direction: str = "right"
# around_acc_speed: int = -2
wormhole_infos = [
{"position": [D, 0, -D], "rotation_y": -150},
{"position": [D, 0, D], "rotation_z": 30, "around_acc_speed": -10, "around_min_speed": 150},
{"position": [- D, -D, D]},
{"position": [- D, 0, -D]},
{"position": [D, D, D]},
{"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_setting(self):
camera.clip_plane_near = 0.00005
# camera.clip_plane_near = 0.01
camera.clip_plane_far = 100000000
# create_sphere_sky(scale=200000)
application.time_scale = 0.001
# camera.scale = 1000
# camera.parent = camera_target.planet
# camera.rotation_x = 90
camera.fov = 100
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:
"""
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 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":
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
around_target = go_target
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 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
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":
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")
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
dd = distance(camera.position, self.target_universe.planet.position)
if camera.speed != 0:
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.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,
timer_enabled=True,
show_grid=False,
show_trail=False)
if __name__ == '__main__':
"""
"""
wormhole_sim = WormholeSim()
wormhole_sim.run()
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册