Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
Python_超人
宇宙模拟器
提交
e23afbfa
宇宙模拟器
项目概览
Python_超人
/
宇宙模拟器
通知
19
Star
2
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
宇宙模拟器
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
提交
e23afbfa
编写于
1月 16, 2024
作者:
三月三net
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Python超人-宇宙模拟器
上级
f6aa7c8b
变更
1
隐藏空白更改
内联
并排
Showing
1 changed file
with
371 addition
and
0 deletion
+371
-0
sim_scenes/featured/two_way_foil.py
sim_scenes/featured/two_way_foil.py
+371
-0
未找到文件。
sim_scenes/featured/two_way_foil.py
0 → 100644
浏览文件 @
e23afbfa
# -*- coding:utf-8 -*-
# title :三体二向箔场景模拟
# description :三体二向箔场景模拟
# author :Python超人
# date :2023-10-27
# link :https://gitcode.net/pythoncr/
# python_version :3.9
# ==============================================================================
import
time
from
ursina
import
camera
,
application
,
lerp
from
bodies
import
Sun
,
Mercury
,
Venus
,
Earth
,
Mars
,
Jupiter
,
Saturn
,
Uranus
,
Neptune
,
Pluto
from
common.celestial_data_service
import
get_init_pos_vels
,
init_bodies_pos_vels
from
common.consts
import
SECONDS_PER_WEEK
,
AU
from
common.image_utils
import
resize_image
from
objs
import
QuadObj
,
CircleObj
,
Obj
from
sim_scenes.func
import
camera_look_at
,
two_bodies_colliding
,
camera_move_control
,
get_run_speed_factor
from
sim_scenes.func
import
ursina_run
,
create_sphere_sky
from
sim_scenes.universe_sim_scenes
import
UniverseSimScenes
from
simulators.ursina.ursina_event
import
UrsinaEvent
from
simulators.func
import
ext_fun_for_method
class
TwoWayFoilSim
(
UniverseSimScenes
):
"""
三体二向箔场景模拟
"""
def
__init__
(
self
):
self
.
current_stage
=
self
.
stage_01
def
build_solar_system
(
self
):
# region 构建太阳系
self
.
sun
,
self
.
mercury
,
self
.
venus
,
self
.
earth
,
self
.
mars
,
self
.
jupiter
,
\
self
.
saturn
,
self
.
uranus
,
self
.
neptune
,
self
.
pluto
=
\
Sun
(
size_scale
=
0.8e2
,
texture
=
"sun_light.jpg"
),
\
Mercury
(
size_scale
=
2e3
,
distance_scale
=
1.5
),
\
Venus
(
size_scale
=
2e3
,
distance_scale
=
1.5
),
\
Earth
(
size_scale
=
2e3
,
distance_scale
=
1.5
,
rotate_angle
=
0
),
\
Mars
(
size_scale
=
2e3
,
distance_scale
=
1.4
),
\
Jupiter
(
size_scale
=
0.3e3
,
distance_scale
=
0.72
),
\
Saturn
(
size_scale
=
0.3e3
,
distance_scale
=
0.52
),
\
Uranus
(
size_scale
=
0.8e3
,
distance_scale
=
0.36
),
\
Neptune
(
size_scale
=
0.8e3
,
distance_scale
=
0.27
),
\
Pluto
(
size_scale
=
10e3
,
distance_scale
=
0.23
)
self
.
bodies
=
[
self
.
sun
,
self
.
mercury
,
self
.
venus
,
self
.
earth
,
self
.
mars
,
self
.
jupiter
,
self
.
saturn
,
self
.
uranus
,
self
.
neptune
,
self
.
pluto
]
# endregion
# self.sun.glows = (2, 1.005, 0.01)
# # glows = (glow_num:10, glow_scale:1.03 glow_alpha:0.1~1)
# self.sun.glows = (0, 1.005, 0.1, 160)
self
.
sun
.
glows
=
(
2
,
1.005
,
0.01
)
self
.
two_way_foil_dt_factor
=
1
self
.
sun
.
two_way_foil_dt
=
0.003
*
self
.
two_way_foil_dt_factor
self
.
saturn
.
two_way_foil_dt
=
0.005
*
self
.
two_way_foil_dt_factor
self
.
uranus
.
two_way_foil_dt
=
0.002
*
self
.
two_way_foil_dt_factor
init_bodies_pos_vels
(
self
.
bodies
)
def
build_two_way_foil
(
self
):
"""
创建二向箔(一个原始的方形二向箔,一个不断扩展的圆形二向箔)
@return:
"""
# 原始的方形二向箔
self
.
two_way_foil
=
QuadObj
(
texture
=
'two_way_foil.png'
,
# size_scale=4e7,
size_scale
=
1e7
,
init_velocity
=
[
0
,
-
50
,
60
],
init_position
=
[
0
,
5
*
AU
,
-
6
*
AU
])
\
.
set_light_disable
(
True
).
set_ignore_gravity
(
True
)
# 不断扩展的圆形二向箔
self
.
two_way_foil_circle
=
CircleObj
(
texture
=
"two_way_foil_circle.png"
,
size_scale
=
self
.
two_way_foil
.
size_scale
*
2
,
)
\
.
set_light_disable
(
True
).
set_ignore_gravity
(
True
)
self
.
bodies
.
append
(
self
.
two_way_foil
)
self
.
bodies
.
append
(
self
.
two_way_foil_circle
)
def
build
(
self
):
self
.
build_solar_system
()
self
.
build_two_way_foil
()
def
on_ready
(
self
):
"""
事件绑定后,模拟器运行前会触发
@return:
"""
# 创建天空
# camera.clip_plane_near = 0.1
camera
.
clip_plane_far
=
1000000
create_sphere_sky
(
scale
=
200000
)
application
.
time_scale
=
5
# 圆形二向箔初始化(一开始不显示)
self
.
two_way_foil_circle
.
planet
.
rotation_x
=
90
self
.
two_way_foil_circle
.
planet
.
enabled
=
False
def
change_two_way_foil
():
# 长方形膜状物,长八点五厘米,宽五点二厘米,比一张信用卡略大一些,极薄,看不出任何厚度。
# 封装状态下晶莹剔透、无色透明。待机模式下由于封装力场逐渐蒸发,会发出白光,使其表面呈纯白色,看上去就是一张纸条
self
.
two_way_foil
.
planet
.
scale_x
=
8.5
self
.
two_way_foil
.
planet
.
scale_y
=
5.2
glow_circle
=
self
.
sun
.
planet
.
glow_circle
fixed_star_ratio
=
glow_circle
.
scale_x
/
self
.
sun
.
planet
.
scale_x
def
glow_circle_update
():
glow_circle
.
enabled
=
self
.
sun
.
planet
.
enabled
glow_circle
.
position
=
self
.
sun
.
planet
.
position
glow_circle
.
scale_x
=
fixed_star_ratio
*
self
.
sun
.
planet
.
scale_y
if
glow_circle
.
scale_x
<
5
:
glow_circle
.
update
=
lambda
:
None
glow_circle
.
enabled
=
False
glow_circle
.
scale_z
=
fixed_star_ratio
*
self
.
sun
.
planet
.
scale_x
# glow_circle.scale_z = fixed_star_ratio * fixed_star.scale_z
glow_circle
.
look_at
(
camera
)
glow_circle
.
update
=
glow_circle_update
ext_fun_for_method
(
self
.
two_way_foil
.
planet
,
after_run_fun
=
change_two_way_foil
)
def
gen_pixcel_image
(
self
,
planet
):
"""
将纹理图改为像素图片
@param planet:
@return:
"""
import
os
if
planet
.
texture
is
None
:
return
in_img
=
str
(
planet
.
texture
.
path
)
if
"_pixcel"
in
in_img
:
return
out_img
=
os
.
path
.
split
(
in_img
)
out_file
=
out_img
[
1
].
split
(
'.'
)
out_file
=
f
'
{
out_file
[
0
]
}
_pixcel.
{
out_file
[
1
]
}
'
out_img
=
os
.
path
.
abspath
(
os
.
path
.
join
(
out_img
[
0
],
"temp"
,
out_file
))
if
not
os
.
path
.
exists
(
out_img
):
resize_image
(
in_img
,
out_img
,
50
,
25
)
from
ursina
import
Texture
planet
.
texture
=
Texture
(
out_img
)
return
out_img
def
flatten_animation
(
self
,
body
):
"""
天体二维化的动画
@param body: 天体
@return:
"""
def
flatten_update
(
planet
):
def
warp
():
# 原始的 update 方法中有计算天体的运行
planet
.
init_update
()
# 对Y轴进行压平动画,如果压平大小不足 1/50,则继续压缩,直到压缩到 1/50 就不压缩了
# (如果觉得 1/50 的厚度压的不够,还可以继续压缩,基本上就够了)
# if planet.scale_y_v > planet.init_scale_y / 50:
if
planet
.
scale_y_v
>
0.5
:
planet
.
scale_y_v
/=
1.01
# else:
# self.gen_pixcel_image(planet)
planet
.
scale_x_v
+=
0.05
# 灯光关闭,不然压到2纬就会是黑色
planet
.
set_light_off
(
True
)
planet
.
scale_y
=
planet
.
scale_y_v
planet
.
scale_x
=
planet
.
scale_x_v
planet
.
scale_z
=
planet
.
scale_x_v
return
warp
body
.
is_2d
=
True
# 压平时,转速将为以前的 1/200
body
.
planet
.
rotation_speed
/=
200
# 记录原始的厚度大小
body
.
planet
.
scale_y_v
=
body
.
planet
.
scale_y
body
.
planet
.
init_scale_y
=
body
.
planet
.
scale_y
body
.
planet
.
scale_x_v
=
body
.
planet
.
scale_x
body
.
planet
.
init_scale_x
=
body
.
planet
.
scale_x
# 原始的 update 方法中有计算天体的运行,需要保留
body
.
planet
.
init_update
=
body
.
planet
.
update
# 替换 update
body
.
planet
.
update
=
flatten_update
(
body
.
planet
)
def
get_target
(
self
):
for
body
in
self
.
bodies
:
if
hasattr
(
body
,
"is_2d"
):
continue
return
body
return
None
def
stage_01
(
self
):
"""
二向箔飞向太阳
@return:
"""
# 如果二向箔和太阳碰撞
if
two_bodies_colliding
(
self
.
two_way_foil
,
self
.
sun
):
# 隐藏原始二向箔,保持在原地,不在飞行
# self.two_way_foil.planet.enabled = False
self
.
two_way_foil
.
init_velocity
=
[
0
,
0
,
0
]
def
two_way_foil_update
():
target
=
self
.
get_target
()
if
target
is
self
.
sun
:
# 关闭太阳的光晕
self
.
sun
.
hide_children
()
# 让实体A朝向实体B
# self.two_way_foil.planet.look_at(target)
if
target
is
not
None
:
# 让实体A向着实体B移动
dt
=
target
.
two_way_foil_dt
if
hasattr
(
target
,
"two_way_foil_dt"
)
\
else
0.003
*
self
.
two_way_foil_dt_factor
# current_time = time.time()
# if current_time - self.two_way_foil.last_time >= 0.1:
# dt = dt * 2
# self.two_way_foil.last_time = current_time
# target.two_way_foil_dt = dt
self
.
two_way_foil
.
planet
.
position
=
\
lerp
(
self
.
two_way_foil
.
planet
.
position
,
target
.
planet
.
position
,
dt
)
else
:
self
.
two_way_foil
.
planet
.
enabled
=
False
self
.
two_way_foil
.
planet
.
update
=
two_way_foil_update
# 圆形二向箔显示并设置透明度为0.8
self
.
two_way_foil_circle
.
planet
.
alpha
=
0.8
self
.
two_way_foil_circle
.
planet
.
enabled
=
True
# 当前阶段为 stage_02:二向箔压平天体的阶段
self
.
current_stage
=
self
.
stage_02
def
stage_02
(
self
):
"""
二向箔压平天体(二维化)的阶段
@return:
"""
self
.
two_way_foil
.
planet
.
enabled
=
False
# self.sun.two_dim.planet.init_scale += 0.05
# 圆形二向箔不断扩展变大
self
.
two_way_foil_circle
.
planet
.
init_scale
+=
0.8
# 调整天体二维化的时间,一般需要延时,保证扩展和二维化同步的真实效果
two_way_delay_times
=
[
0.5
,
# 太阳
0.5
,
0.8
,
1.0
,
# 水星 金星 地球
1.2
,
2.0
,
3.0
,
# 火星 木星 土星
4.0
,
4.5
,
5.5
]
# 天王星 海王星 冥王星
for
idx
,
b
in
enumerate
(
self
.
bodies
):
if
isinstance
(
b
,
Obj
):
# 二向箔不处理
continue
if
hasattr
(
b
,
"two_way_time"
):
# 二向箔和天体碰撞的时间不为空,则说明已经碰撞
if
b
.
two_way_time
is
not
None
:
# 如果碰撞后的延时时间到,则进行压平天体处理(二维化)
if
time
.
time
()
-
b
.
two_way_time
>
two_way_delay_times
[
idx
]:
self
.
flatten_animation
(
b
)
# 二向箔和天体碰撞的时间设置为空,就是说明二维化结束
b
.
two_way_time
=
None
elif
two_bodies_colliding
(
self
.
two_way_foil_circle
,
b
):
# 二向箔和天体碰撞,但暂时先不二维化,记下时间,延时二维化
b
.
two_way_time
=
time
.
time
()
# 圆形二向箔不断旋转的效果
self
.
two_way_foil_circle
.
planet
.
rotation_z
+=
0.4
def
on_timer_changed
(
self
,
time_data
):
"""
@param time_data:
@return:
"""
# 原始方形二向箔飞行的翻转效果
if
self
.
two_way_foil
.
planet
.
enabled
:
self
.
two_way_foil
.
planet
.
rotation_x
+=
0.1
self
.
two_way_foil
.
planet
.
rotation_y
+=
1
# # 摄像机始终看向二向箔
# camera_look_at(self.two_way_foil)
target
=
self
.
get_target
()
if
target
is
not
None
:
if
target
is
self
.
sun
:
# 摄像机始终看向二向箔
camera_look_at
(
self
.
two_way_foil
)
else
:
# 摄像机始终看向二向箔
camera_look_at
(
self
.
two_way_foil
)
camera
.
position
+=
camera
.
forward
*
10
self
.
camera_move
(
time_data
)
# camera.position = \
# lerp(camera.position, target.planet.position, 0.001)
self
.
current_stage
()
def
s_f
(
self
,
value
=
1
):
if
value
==
0
:
return
0
return
get_run_speed_factor
()
*
value
def
camera_move
(
self
,
time_data
):
"""
摄像机移动控制
@param dt:
@return:
"""
# 摄像机移动控制数据
camera_move_infos
=
[
# 条件:年份
# 移动的信息:
# 按坐标系方向移动 x:右+左-, y:升+降-, z:前+(接近太阳)后-(远离太阳)
# 以摄像机视角移动 f:前 b:后 l:左 r:右 u:上 d:下
(
1
,
{
"l"
:
2
}),
(
10
,
{
"f"
:
50
}),
# (40, {"f": 80}),
# (1983, {"to": {"ct_id": 1, "t": 10}}),
# (2, {"x": 2, "y": -2, "z": -15}),
# (3, {"y": -6, "z": -12}),
# (4, {"y": -3, "z": -12}),
# (5, {"z": -8, "f": -5}),
# (6, {"z": -8, "f": -3}),
# (7, {"z": -8}),
# (8, {"z": -8, "y": -0.2}),
# (9, {}),
# (100, {"f": 10}),
# (200, {"f": 10}),
# (500, {"f": 10}),
# (2062, {"y": -3}),
# (2063, {"y": -10, "z": 2}),
(
2181
,
{}),
# (2082, {"exit": True})
]
camera_move_control
(
camera_move_infos
,
cond_cb
=
lambda
ps
:
ps
[
"next_cond"
]
>
time_data
.
total_days
>=
ps
[
"cond"
],
value_conv
=
self
.
s_f
,
smooth
=
None
)
if
__name__
==
'__main__'
:
"""
三体二向箔场景模拟
"""
sim
=
TwoWayFoilSim
()
sim
.
build
()
# 订阅事件后,上面2个函数功能才会起作用
# 运行中,每时每刻都会触发 on_timer_changed
UrsinaEvent
.
on_timer_changed_subscription
(
sim
.
on_timer_changed
)
# 运行前会触发 on_ready
UrsinaEvent
.
on_ready_subscription
(
sim
.
on_ready
)
# 使用 ursina 查看的运行效果
# 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹
# position = 左-右+、上+下-、前+后-
ursina_run
(
sim
.
bodies
,
SECONDS_PER_WEEK
,
position
=
(
0
,
2
*
AU
,
-
11
*
AU
),
# position=(0, 5 * AU, -5 * AU),
cosmic_bg
=
''
,
bg_music
=
'sounds/no_glory.mp3'
,
show_camera_info
=
False
,
show_control_info
=
False
,
timer_enabled
=
True
,
show_timer
=
True
,
show_grid
=
False
)
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录