diff --git a/sim_scenes/science/gravity_slingshot.py b/sim_scenes/science/gravity_slingshot_1.py similarity index 100% rename from sim_scenes/science/gravity_slingshot.py rename to sim_scenes/science/gravity_slingshot_1.py diff --git a/sim_scenes/science/gravity_slingshot_2.py b/sim_scenes/science/gravity_slingshot_2.py new file mode 100644 index 0000000000000000000000000000000000000000..9236fdd22ba7d276545f1ed92d6906f5a2ff8c42 --- /dev/null +++ b/sim_scenes/science/gravity_slingshot_2.py @@ -0,0 +1,35 @@ +# -*- coding:utf-8 -*- +# title :引力弹弓模拟演示 +# description :引力弹弓模拟演示 +# author :Python超人 +# date :2023-02-11 +# link :https://gitcode.net/pythoncr/ +# python_version :3.8 +# ============================================================================== +from bodies import Sun, Earth, Jupiter, Saturn +from common.consts import SECONDS_PER_HOUR, SECONDS_PER_HALF_DAY, SECONDS_PER_DAY, SECONDS_PER_WEEK, SECONDS_PER_MONTH +from sim_scenes.func import mayavi_run, ursina_run +from bodies.body import AU + +if __name__ == '__main__': + """ + 模拟流浪地球经过木星、土星加速 + """ + bodies = [ + Jupiter(size_scale=1e2, init_position=[0, AU / 4, 0], init_velocity=[0, 0, 0]), # 木星放大 100 倍 + Saturn(size_scale=1e2, init_position=[AU/1.5, 1.5 * AU, 0], init_velocity=[0, 0, 0]), # 土星放大 100 倍 + Earth(size_scale=3e2, # 地球放大 300 倍 + init_position=[0, 0, 0], # + # init_velocity=[0, 33, -1], + init_velocity=[-1, 10, 0], # 朝向木星的速度为 38km/s,-1 km/s 是为了防止地球正面对着木星冲去 + # init_velocity=[0, 50, -1], + ), + ] + + # 使用 mayavi 查看的运行效果 + # mayavi_run(bodies, SECONDS_PER_WEEK, view_azimuth=-45) + + # 使用 ursina 查看的运行效果 + # 常用快捷键: P:运行和暂停 O:重新开始 I:显示天体轨迹 + # position = 左-右+、上+下-、前+后- + ursina_run(bodies, SECONDS_PER_MONTH, position=(0, AU / 2, -2 * AU), show_trail=True, view_closely=True) diff --git a/simulators/ursina/entities/__init__.py b/simulators/ursina/entities/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/simulators/ursina/entities/planet.py b/simulators/ursina/entities/planet.py new file mode 100644 index 0000000000000000000000000000000000000000..7b7643ee9133019fb0b6d29f77cf33a930520684 --- /dev/null +++ b/simulators/ursina/entities/planet.py @@ -0,0 +1,359 @@ +# -*- coding:utf-8 -*- +# title :ursina天体Planet +# description :ursina天体Planet +# author :Python超人 +# date :2023-02-11 +# link :https://gitcode.net/pythoncr/ +# python_version :3.8 +# ============================================================================== +# pip install -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com ursina +from ursina import Entity, camera, color, Vec2, Vec3, Vec4, Text, load_texture, destroy, PointLight + +from simulators.ursina.ursina_config import UrsinaConfig +from simulators.ursina.ursina_event import UrsinaEvent +from common.color_utils import adjust_brightness, conv_to_vec4_color, get_inverse_color +from common.func import find_file +from simulators.views.body_view import BodyView +from simulators.views.ursina_mesh import create_sphere, create_torus +import numpy as np +import math + + +class Planet(Entity): + + def on_reset(self): + # 删除拖尾 + self.clear_trails() + self.body_view.body.reset() + + def __init__(self, body_view: BodyView): + self.body_view = body_view + self.rotation_speed = self.body_view.body.rotation_speed + self.rotMode = 'x' # random.choice(["x", "y", "z"]) + self.name = body_view.name + + pos = body_view.position * body_view.body.distance_scale * UrsinaConfig.SCALE_FACTOR + scale = body_view.body.diameter * body_view.body.size_scale * UrsinaConfig.SCALE_FACTOR + self.init_scale = scale + if hasattr(body_view, "texture"): + texture = load_texture(body_view.texture) + # color.white + self.plant_color = color.white + else: + texture = None + b_color = self.body_view.color + if len(b_color) == 3: + b_color = (b_color[0], b_color[1], b_color[2], 1.0) + self.plant_color = color.rgba(*b_color) + + if hasattr(self.body_view.body, "torus_stars"): + # 创建一个星环小天体群(主要模拟小行星群,非一个天体) + model = create_torus(0.83, 1.05, 64, 1) + rotation = (90, 0, 0) + else: + # 创建一个天体 + subdivisions = 32 + if self.body_view.body.resolution is not None: + subdivisions = self.body_view.body.resolution + + model = create_sphere(0.5, subdivisions) + rotation = (0, 0, 0) + + UrsinaEvent.on_reset_subscription(self.on_reset) + + super().__init__( + # model="sphere", + model=model, + scale=scale, + texture=texture, + color=self.plant_color, + position=pos, + rotation=rotation, + double_sided=True + ) + + if hasattr(self.body_view.body, "torus_stars"): + # 星环小天体群(主要模拟小行星群,非一个天体) + self.set_light_off() + self.double_sided = True + else: + # 一个天体 + # 拖尾球体的初始化 + self.trail_init() + + if self.body_view.body.is_fixed_star: + # 如果是恒星,开启恒星的发光的效果、并作为灯光源 + self.create_fixed_star_lights() + elif self.body_view.body.light_disable: + # 如果是非恒星,并且禁用灯光 + self.set_light_off() + + if self.body_view.body.show_name: + self.create_name_text() + + def create_name_text(self): + b_color = self.body_view.color + self.name_text = Text(self.body_view.body.name, scale=1, billboard=True, parent=self, + font=UrsinaConfig.CN_FONT, background=True, + origin=(0, 0)) + self.name_text.background.color = color.rgba(b_color[0], b_color[1], b_color[2], 0.3) + # self.name_text.scale = self.scale + inverse_color = get_inverse_color(b_color) + self.name_text.color = color.rgba(inverse_color[0], inverse_color[1], inverse_color[2], 1) + + def trail_init(self): + """ + 拖尾球体的初始化 + :return: + """ + # 存放拖尾球体 + self.trails = {} + + # 根据天体的颜色获取拖尾的颜色 + trail_color = conv_to_vec4_color(self.body_view.body.trail_color) + trail_color = adjust_brightness(trail_color, 0.4) + self.trail_color = color.rgba(trail_color[0], trail_color[1], trail_color[2], 0.6) + # 拖尾球体的大小为该天体的 1/5 + self.trail_scale = self.scale_x / 5 + if self.trail_scale < 1: + # 如果太小,则 + pass + + def distance_between_two_points(self, point_a: Vec3, point_b: Vec3) -> float: + # 计算两点在 x、y、z 三个坐标轴上的差值 + diff_x = point_a.x - point_b.x + diff_y = point_a.y - point_b.y + diff_z = point_a.z - point_b.z + + # 计算两点之间的距离 + distance = math.sqrt(diff_x ** 2 + diff_y ** 2 + diff_z ** 2) + + return distance + + def create_trails(self): + """ + 创建拖尾 + :return: + """ + # 当前天体的位置 + try: + pos = self.position + except Exception as e: + print(self.body_view.body) + self.destroy_all() + return + trails_keys = self.trails.keys() + # 如果有拖尾 + if len(trails_keys) > 0: + # 获取最后一个拖尾的位置 + last_key = list(trails_keys)[-1] + last_pos = self.trails[last_key] + # 获取拖尾与当前天体的位置 + last_pos_distance = self.distance_between_two_points(pos, last_pos) + self_pos_distance = self.distance_between_two_points(pos, self.position) + # # 如果拖尾在天体的内部也不要生成 + # if self_pos_distance < self.scale_x + (self.trail_scale / 2): + # pass + # 如果位置比较近,就不创建拖尾了,保证拖尾间隔一定的距离 + if last_pos_distance < self.trail_scale * 1.2: # 间隔距离不小于1.2倍的拖尾球体 + return + + # 创建拖尾球体,并作为字典的key,存放拖尾球体的位置 + self.trails[self.create_trail(pos)] = pos + + # 计算拖尾球体超过的数量 + trail_overflow_count = len(self.trails) - UrsinaConfig.trail_length + + if trail_overflow_count > 0: + # 如果拖尾球体超过的数量,就删除之前的拖尾球体 + for entity, pos in self.trails.items(): + destroy(entity) + trail_overflow_count -= 1 + if trail_overflow_count <= 0: + break + + def create_trail(self, pos): + """ + 在天体当前的位置创建一个拖尾球体 + :param pos: + :return: + """ + # sphere = create_sphere(1,6) diamond sphere + trail = Entity(model='sphere', color=self.trail_color, scale=self.trail_scale, position=pos) + trail.set_light_off() + # trail.set_color_off() + # trail.set_color_scale_off() + # trail.enabled = False + return trail + + def turn(self): + if hasattr(self.body_view.body, "torus_stars"): + # 星环小天体群(主要模拟小行星群,非一个天体)不受 body_size_factor 影响 + self.scale = self.init_scale + else: + self.scale = self.init_scale * UrsinaConfig.body_size_factor + + pos = self.body_view.position * UrsinaConfig.SCALE_FACTOR + if self.body_view.body.parent is None: + self.x = -pos[1] + self.y = pos[2] + self.z = pos[0] + else: + self.follow_parent() + + dt = 0 + if hasattr(self.body_view.body, "dt"): + dt = self.body_view.body.dt + if self.rotation_speed is None or dt == 0: + self.rotspeed = 0 + # 旋转速度和大小成反比(未使用真实数据) + # self.rotspeed = 30000 / self.body_view.raduis # random.uniform(1.0, 2.0) + else: + # 是通过月球保持一面面对地球,调整得到 + self.rotspeed = self.rotation_speed * (dt / 3600) / 2.4 * \ + UrsinaConfig.ROTATION_SPEED_FACTOR * UrsinaConfig.body_spin_factor + # rotation_speed 度/小时 dt 秒 = (dt / 3600)小时 + + # if self.rotation_y < 0: + # self.rotation_y += 360 + try: + # 天体旋转 + self.rotation_y -= self.rotspeed + except Exception as e: + print(self.body_view.body) + self.destroy_all() + return + + # 如果有行星环 + if hasattr(self, "ring"): + # 如果有行星环,则不让行星环跟随行星转动 + self.ring.rotation = -Vec3(self.rotation_x - self.ring_rotation_x, + self.rotation_y, + self.rotation_z) + + if UrsinaConfig.show_trail: + # 有时候第一个位置不正确,所以判断一下有历史记录后在创建 + if len(self.body_view.body.his_position()) > 1: + self.create_trails() + else: + self.clear_trails() + + if hasattr(self, "name_text"): + d = (camera.world_position - self.name_text.world_position).length() + + if d < pow(self.scale_x, 1.02) * 1.2: + self.name_text.visible = False + else: + self.name_text.visible = True + # print(d, self.name_text.text, self.scale_x ,self.scale_x*1.23) + # # 计算相机和实体之间的距离 + # distance = (camera.world_position - self.world_position).length() + # # 根据距离设置文本缩放比例 + # self.name_text.scale = distance / 10 + + def follow_parent(self): + if not hasattr(self, "f_parent"): + if not hasattr(self.body_view, "bodies_system"): + return + sys = self.body_view.bodies_system + for b in sys.bodies: + if self.body_view.body.parent == b: + self.f_parent = b + break + pos = self.f_parent.position * UrsinaConfig.SCALE_FACTOR + self.x = -pos[1] + self.y = pos[2] + self.z = pos[0] + + def create_fixed_star_lights(self): + """ + 创建恒星的发光的效果、并作为灯光源 + :param entity: + :return: + """ + + # 如果是恒星(如:太阳),自身会发光,则需要关闭灯光 + self.set_light_off() + + # lights = [] + # # 创建多个新的 Entity 对象,作为光晕的容器 + # _color = color.rgba(1.0, 0.6, 0.2, 1) + if hasattr(self.body_view.body, "glows"): + # glows = (glow_num:10, glow_scale:1.03 glow_alpha:0.1~1) + glows = self.body_view.body.glows + if glows is not None: + if isinstance(glows, tuple): + if len(glows) == 3: + glow_num, glow_scale, glow_alpha = glows + elif len(glows) == 2: + glow_num, glow_scale = glows + glow_alpha = None + else: + glow_num = glows + glow_scale = 1.02 + glow_alpha = None + + if glow_num > 0: + glow_alphas = [0, 0.5, 0.4, 0.3, 0.2, 0.1] + if glow_alpha is None: + if glow_num < len(glow_alphas) - 1: + glow_alpha = glow_alphas[glow_num] + else: + glow_alpha = glow_alphas[-1] + + # _color = color.white + _color = self.body_view.body.color + _color = color.rgba(_color[0] / 255, _color[1] / 255, _color[2] / 255, 1) + for i in range(glow_num): + glow_entity = Entity(parent=self, model='sphere', color=_color, + scale=math.pow(glow_scale, i + 1), alpha=glow_alpha) + if hasattr(self.body_view.body, "light_on"): + if self.body_view.body.light_on: + for i in range(2): + # 创建 PointLight 对象,作为恒星的灯光源 + light = PointLight(parent=self, intensity=10, range=10, color=color.white) + + def create_rings(self): + """ + 创建行星环(使用土星贴图) + :return: + """ + rings_texture = 'textures/saturnRings.jpg' + rings_texture = find_file(rings_texture) + + # 行星环偏移角度 + # self.ring_rotation_x = 80 + # 创建行星环 + # self.ring = Entity(parent=self.planet, model='circle', texture=rings_texture, scale=3.5, + # rotation=(self.ring_rotation_x, 0, 0), double_sided=True) + + # 行星环偏移角度 + self.ring_rotation_x = 80 + # 创建行星环 + torus = create_torus(0.7, 1.2, 64) + self.ring = Entity(parent=self, model=torus, texture=rings_texture, scale=1, + rotation=(self.ring_rotation_x, 0, 0), double_sided=True) + + # 设置行星环不受灯光影响,否则看不清行星环 + self.ring.set_light_off() + + def clear_trails(self): + if not hasattr(self, "trails"): + return + # 删除拖尾 + for entity, pos in self.trails.items(): + destroy(entity) + self.trails.clear() + + def destroy_all(self): + # 从天体系统中移除自己(TODO:暂时还不能移除) + # self.body_view.bodies_system.bodies.remove(self.body_view.body) + # 删除拖尾 + self.clear_trails() + # 如果有行星环,则删除行星环 + if hasattr(self, "ring"): + destroy(self.ring) + self.body_view.body.appeared = False + self.body_view.appeared = False + # 最后删除自己 + destroy(self) diff --git a/simulators/ursina/entities/ursina_player.py b/simulators/ursina/entities/ursina_player.py new file mode 100644 index 0000000000000000000000000000000000000000..504888d2d77abef0671b05526df858623f32744f --- /dev/null +++ b/simulators/ursina/entities/ursina_player.py @@ -0,0 +1,65 @@ +# -*- coding:utf-8 -*- +# title :UrsinaPlayer +# description :UrsinaPlayer +# author :Python超人 +# date :2023-02-11 +# link :https://gitcode.net/pythoncr/ +# python_version :3.8 +# ============================================================================== +# pip install -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com ursina +from ursina import camera, color, mouse, Vec2, Vec3, Vec4, Text +from ursina.prefabs.first_person_controller import FirstPersonController +from simulators.ursina.ursina_config import UrsinaConfig +import numpy as np + + +class UrsinaPlayer(FirstPersonController): + """ + + """ + + # body_rotation_speed_control = 1.0 + + def __init__(self, position, view_azimuth=0, targets=None): + super().__init__() + # camera.fov = 2000 # 100 + # camera.rotation_y = 90 + self.planets = None + if targets is not None: + self.planets = [] + # targets = [view.planet.parent for view in targets] + # targets_parent = Entity() + for view in targets: + # view.planet.parent = targets_parent + self.planets.append(view.planet) + # self.camera_adj(planets) + # # planets.append(view.planet) + # + # camera.add_script(SmoothFollow(targets_parent, offset=(0, 8, -20))) + pos = np.array(position) * UrsinaConfig.SCALE_FACTOR + self.position = Vec3(pos[0], pos[1], pos[2]) + # 将摄像机位置设置为 x=0、y=1、z=0 的位置 + camera.position = Vec3(pos[0], pos[1], pos[2]) + # self.x = 90 + # self.position = Vec3(pos[0], pos[1], pos[2]) + # 将摄像机的观察角度绕 x 轴旋转 45 度,绕 y 轴旋转 0 度,绕 z 轴旋转 0 度 + # self.rotation = Vec3(45, 90, 0) + # camera.look_at(Vec3(0, 0, 0)) + # camera.world_rotation = Vec3(0, 190, 190) + # camera.enabled = True + # self.gravity = 0 + # self.vspeed = 400 + # self.speed = 1000 + # self.mouse_sensitivity = Vec2(160, 160) + # self.on_enable() + # self.rotation_speed = 80 + + self.on_disable() # 防止鼠标被窗口锁定 + + # def input(self, key): + # if key == "escape": + # if mouse.locked: + # self.on_disable() + # else: + # sys.exit() + # return super().input(key) diff --git a/simulators/ursina/ui/control_handler.py b/simulators/ursina/ui/control_handler.py index d54683f9edcf011f18815682ca4352209224c175..b14bd260ba890e1527a96d9c730b5ad9ebfdcb60 100644 --- a/simulators/ursina/ui/control_handler.py +++ b/simulators/ursina/ui/control_handler.py @@ -224,7 +224,8 @@ class ControlHandler(EventHandler): elif key == 'space': self.ui.enabled = not self.ui.enabled elif key == 'left mouse down': - print(key) + # print(key) + pass elif key == 'y': # 寻找天体 if hasattr(self, "search_bodies_button_list"): if self.search_bodies_button_list.enabled: diff --git a/simulators/ursina_simulator.py b/simulators/ursina_simulator.py index 69e29744d7114dce4afad01c32ceb26380539b9d..0bd854bb5abe40682fff9ddc2a01d32e1ff3a0ad 100644 --- a/simulators/ursina_simulator.py +++ b/simulators/ursina_simulator.py @@ -16,7 +16,8 @@ from simulators.ursina.ursina_event import UrsinaEvent from simulators.ursina.ui.control_ui import ControlUI from simulators.ursina.ui.control_handler import ControlHandler -from simulators.views.ursina_view import UrsinaView, UrsinaPlayer +from simulators.views.ursina_view import UrsinaView +from simulators.ursina.entities.ursina_player import UrsinaPlayer from simulators.ursina.ursina_config import UrsinaConfig from simulators.simulator import Simulator from common.system import System diff --git a/simulators/views/ursina_view.py b/simulators/views/ursina_view.py index 3e1560bc5e9f43f54e0c6ea072aaf1742fde0054..33cdce785567bc528c2243b24e3bba0d826b25af 100644 --- a/simulators/views/ursina_view.py +++ b/simulators/views/ursina_view.py @@ -7,416 +7,13 @@ # python_version :3.8 # ============================================================================== # pip install -i http://pypi.douban.com/simple/ --trusted-host=pypi.douban.com ursina -from ursina import Ursina, window, Entity, Mesh, SmoothFollow, Texture, clamp, time, \ - camera, color, mouse, Vec2, Vec3, Vec4, Text, \ - load_texture, held_keys, destroy, PointLight - -from ursina.prefabs.first_person_controller import FirstPersonController -import sys from bodies import Body - -from simulators.ursina.ursina_config import UrsinaConfig -from simulators.ursina.ursina_event import UrsinaEvent -from common.color_utils import adjust_brightness, conv_to_vec4_color, get_inverse_color -from common.func import find_file from simulators.views.body_view import BodyView -from simulators.views.ursina_mesh import create_sphere, create_torus +from simulators.ursina.entities.planet import Planet import numpy as np import math -class UrsinaPlayer(FirstPersonController): - """ - - """ - - # body_rotation_speed_control = 1.0 - - def __init__(self, position, view_azimuth=0, targets=None): - super().__init__() - # camera.fov = 2000 # 100 - # camera.rotation_y = 90 - self.planets = None - if targets is not None: - self.planets = [] - # targets = [view.planet.parent for view in targets] - # targets_parent = Entity() - for view in targets: - # view.planet.parent = targets_parent - self.planets.append(view.planet) - # self.camera_adj(planets) - # # planets.append(view.planet) - # - # camera.add_script(SmoothFollow(targets_parent, offset=(0, 8, -20))) - pos = np.array(position) * UrsinaConfig.SCALE_FACTOR - self.position = Vec3(pos[0], pos[1], pos[2]) - # 将摄像机位置设置为 x=0、y=1、z=0 的位置 - camera.position = Vec3(pos[0], pos[1], pos[2]) - # self.x = 90 - # self.position = Vec3(pos[0], pos[1], pos[2]) - # 将摄像机的观察角度绕 x 轴旋转 45 度,绕 y 轴旋转 0 度,绕 z 轴旋转 0 度 - # self.rotation = Vec3(45, 90, 0) - # camera.look_at(Vec3(0, 0, 0)) - # camera.world_rotation = Vec3(0, 190, 190) - # camera.enabled = True - # self.gravity = 0 - # self.vspeed = 400 - # self.speed = 1000 - # self.mouse_sensitivity = Vec2(160, 160) - # self.on_enable() - # self.rotation_speed = 80 - - self.on_disable() # 防止鼠标被窗口锁定 - - # def input(self, key): - # if key == "escape": - # if mouse.locked: - # self.on_disable() - # else: - # sys.exit() - # return super().input(key) - - -class Planet(Entity): - - def on_reset(self): - # 删除拖尾 - self.clear_trails() - self.body_view.body.reset() - - def __init__(self, body_view: BodyView): - self.body_view = body_view - self.rotation_speed = self.body_view.body.rotation_speed - self.rotMode = 'x' # random.choice(["x", "y", "z"]) - self.name = body_view.name - - pos = body_view.position * body_view.body.distance_scale * UrsinaConfig.SCALE_FACTOR - scale = body_view.body.diameter * body_view.body.size_scale * UrsinaConfig.SCALE_FACTOR - self.init_scale = scale - if hasattr(body_view, "texture"): - texture = load_texture(body_view.texture) - # color.white - self.plant_color = color.white - else: - texture = None - b_color = self.body_view.color - if len(b_color) == 3: - b_color = (b_color[0], b_color[1], b_color[2], 1.0) - self.plant_color = color.rgba(*b_color) - - if hasattr(self.body_view.body, "torus_stars"): - # 创建一个星环小天体群(主要模拟小行星群,非一个天体) - model = create_torus(0.83, 1.05, 64, 1) - rotation = (90, 0, 0) - else: - # 创建一个天体 - subdivisions = 32 - if self.body_view.body.resolution is not None: - subdivisions = self.body_view.body.resolution - - model = create_sphere(0.5, subdivisions) - rotation = (0, 0, 0) - - UrsinaEvent.on_reset_subscription(self.on_reset) - - super().__init__( - # model="sphere", - model=model, - scale=scale, - texture=texture, - color=self.plant_color, - position=pos, - rotation=rotation, - double_sided=True - ) - - if hasattr(self.body_view.body, "torus_stars"): - # 星环小天体群(主要模拟小行星群,非一个天体) - self.set_light_off() - self.double_sided = True - else: - # 一个天体 - # 拖尾球体的初始化 - self.trail_init() - - if self.body_view.body.is_fixed_star: - # 如果是恒星,开启恒星的发光的效果、并作为灯光源 - self.create_fixed_star_lights() - elif self.body_view.body.light_disable: - # 如果是非恒星,并且禁用灯光 - self.set_light_off() - - if self.body_view.body.show_name: - self.create_name_text() - - def create_name_text(self): - b_color = self.body_view.color - self.name_text = Text(self.body_view.body.name, scale=1, billboard=True, parent=self, - font=UrsinaConfig.CN_FONT, background=True, - origin=(0, 0)) - self.name_text.background.color = color.rgba(b_color[0], b_color[1], b_color[2], 0.3) - # self.name_text.scale = self.scale - inverse_color = get_inverse_color(b_color) - self.name_text.color = color.rgba(inverse_color[0], inverse_color[1], inverse_color[2], 1) - - def trail_init(self): - """ - 拖尾球体的初始化 - :return: - """ - # 存放拖尾球体 - self.trails = {} - - # 根据天体的颜色获取拖尾的颜色 - trail_color = conv_to_vec4_color(self.body_view.body.trail_color) - trail_color = adjust_brightness(trail_color, 0.4) - self.trail_color = color.rgba(trail_color[0], trail_color[1], trail_color[2], 0.6) - # 拖尾球体的大小为该天体的 1/5 - self.trail_scale = self.scale_x / 5 - if self.trail_scale < 1: - # 如果太小,则 - pass - - def distance_between_two_points(self, point_a: Vec3, point_b: Vec3) -> float: - # 计算两点在 x、y、z 三个坐标轴上的差值 - diff_x = point_a.x - point_b.x - diff_y = point_a.y - point_b.y - diff_z = point_a.z - point_b.z - - # 计算两点之间的距离 - distance = math.sqrt(diff_x ** 2 + diff_y ** 2 + diff_z ** 2) - - return distance - - def create_trails(self): - """ - 创建拖尾 - :return: - """ - # 当前天体的位置 - try: - pos = self.position - except Exception as e: - print(self.body_view.body) - self.destroy_all() - return - trails_keys = self.trails.keys() - # 如果有拖尾 - if len(trails_keys) > 0: - # 获取最后一个拖尾的位置 - last_key = list(trails_keys)[-1] - last_pos = self.trails[last_key] - # 获取拖尾与当前天体的位置 - last_pos_distance = self.distance_between_two_points(pos, last_pos) - self_pos_distance = self.distance_between_two_points(pos, self.position) - # # 如果拖尾在天体的内部也不要生成 - # if self_pos_distance < self.scale_x + (self.trail_scale / 2): - # pass - # 如果位置比较近,就不创建拖尾了,保证拖尾间隔一定的距离 - if last_pos_distance < self.trail_scale * 1.2: # 间隔距离不小于1.2倍的拖尾球体 - return - - # 创建拖尾球体,并作为字典的key,存放拖尾球体的位置 - self.trails[self.create_trail(pos)] = pos - - # 计算拖尾球体超过的数量 - trail_overflow_count = len(self.trails) - UrsinaConfig.trail_length - - if trail_overflow_count > 0: - # 如果拖尾球体超过的数量,就删除之前的拖尾球体 - for entity, pos in self.trails.items(): - destroy(entity) - trail_overflow_count -= 1 - if trail_overflow_count <= 0: - break - - def create_trail(self, pos): - """ - 在天体当前的位置创建一个拖尾球体 - :param pos: - :return: - """ - # sphere = create_sphere(1,6) diamond sphere - trail = Entity(model='sphere', color=self.trail_color, scale=self.trail_scale, position=pos) - trail.set_light_off() - # trail.set_color_off() - # trail.set_color_scale_off() - # trail.enabled = False - return trail - - def turn(self): - if hasattr(self.body_view.body, "torus_stars"): - # 星环小天体群(主要模拟小行星群,非一个天体)不受 body_size_factor 影响 - self.scale = self.init_scale - else: - self.scale = self.init_scale * UrsinaConfig.body_size_factor - - pos = self.body_view.position * UrsinaConfig.SCALE_FACTOR - if self.body_view.body.parent is None: - self.x = -pos[1] - self.y = pos[2] - self.z = pos[0] - else: - self.follow_parent() - - dt = 0 - if hasattr(self.body_view.body, "dt"): - dt = self.body_view.body.dt - if self.rotation_speed is None or dt == 0: - self.rotspeed = 0 - # 旋转速度和大小成反比(未使用真实数据) - # self.rotspeed = 30000 / self.body_view.raduis # random.uniform(1.0, 2.0) - else: - # 是通过月球保持一面面对地球,调整得到 - self.rotspeed = self.rotation_speed * (dt / 3600) / 2.4 * \ - UrsinaConfig.ROTATION_SPEED_FACTOR * UrsinaConfig.body_spin_factor - # rotation_speed 度/小时 dt 秒 = (dt / 3600)小时 - - # if self.rotation_y < 0: - # self.rotation_y += 360 - try: - # 天体旋转 - self.rotation_y -= self.rotspeed - except Exception as e: - print(self.body_view.body) - self.destroy_all() - return - - # 如果有行星环 - if hasattr(self, "ring"): - # 如果有行星环,则不让行星环跟随行星转动 - self.ring.rotation = -Vec3(self.rotation_x - self.ring_rotation_x, - self.rotation_y, - self.rotation_z) - - if UrsinaConfig.show_trail: - # 有时候第一个位置不正确,所以判断一下有历史记录后在创建 - if len(self.body_view.body.his_position()) > 1: - self.create_trails() - else: - self.clear_trails() - - if hasattr(self, "name_text"): - d = (camera.world_position - self.name_text.world_position).length() - - if d < pow(self.scale_x, 1.02) * 1.2: - self.name_text.visible = False - else: - self.name_text.visible = True - # print(d, self.name_text.text, self.scale_x ,self.scale_x*1.23) - # # 计算相机和实体之间的距离 - # distance = (camera.world_position - self.world_position).length() - # # 根据距离设置文本缩放比例 - # self.name_text.scale = distance / 10 - - def follow_parent(self): - if not hasattr(self, "f_parent"): - if not hasattr(self.body_view, "bodies_system"): - return - sys = self.body_view.bodies_system - for b in sys.bodies: - if self.body_view.body.parent == b: - self.f_parent = b - break - pos = self.f_parent.position * UrsinaConfig.SCALE_FACTOR - self.x = -pos[1] - self.y = pos[2] - self.z = pos[0] - - def create_fixed_star_lights(self): - """ - 创建恒星的发光的效果、并作为灯光源 - :param entity: - :return: - """ - - # 如果是恒星(如:太阳),自身会发光,则需要关闭灯光 - self.set_light_off() - - # lights = [] - # # 创建多个新的 Entity 对象,作为光晕的容器 - # _color = color.rgba(1.0, 0.6, 0.2, 1) - if hasattr(self.body_view.body, "glows"): - # glows = (glow_num:10, glow_scale:1.03 glow_alpha:0.1~1) - glows = self.body_view.body.glows - if glows is not None: - if isinstance(glows, tuple): - if len(glows) == 3: - glow_num, glow_scale, glow_alpha = glows - elif len(glows) == 2: - glow_num, glow_scale = glows - glow_alpha = None - else: - glow_num = glows - glow_scale = 1.02 - glow_alpha = None - - if glow_num > 0: - glow_alphas = [0, 0.5, 0.4, 0.3, 0.2, 0.1] - if glow_alpha is None: - if glow_num < len(glow_alphas) - 1: - glow_alpha = glow_alphas[glow_num] - else: - glow_alpha = glow_alphas[-1] - - # _color = color.white - _color = self.body_view.body.color - _color = color.rgba(_color[0] / 255, _color[1] / 255, _color[2] / 255, 1) - for i in range(glow_num): - glow_entity = Entity(parent=self, model='sphere', color=_color, - scale=math.pow(glow_scale, i + 1), alpha=glow_alpha) - if hasattr(self.body_view.body, "light_on"): - if self.body_view.body.light_on: - for i in range(2): - # 创建 PointLight 对象,作为恒星的灯光源 - light = PointLight(parent=self, intensity=10, range=10, color=color.white) - - def create_rings(self): - """ - 创建行星环(使用土星贴图) - :return: - """ - rings_texture = 'textures/saturnRings.jpg' - rings_texture = find_file(rings_texture) - - # 行星环偏移角度 - # self.ring_rotation_x = 80 - # 创建行星环 - # self.ring = Entity(parent=self.planet, model='circle', texture=rings_texture, scale=3.5, - # rotation=(self.ring_rotation_x, 0, 0), double_sided=True) - - # 行星环偏移角度 - self.ring_rotation_x = 80 - # 创建行星环 - torus = create_torus(0.7, 1.2, 64) - self.ring = Entity(parent=self, model=torus, texture=rings_texture, scale=1, - rotation=(self.ring_rotation_x, 0, 0), double_sided=True) - - # 设置行星环不受灯光影响,否则看不清行星环 - self.ring.set_light_off() - - def clear_trails(self): - if not hasattr(self, "trails"): - return - # 删除拖尾 - for entity, pos in self.trails.items(): - destroy(entity) - self.trails.clear() - - def destroy_all(self): - # 从天体系统中移除自己(TODO:暂时还不能移除) - # self.body_view.bodies_system.bodies.remove(self.body_view.body) - # 删除拖尾 - self.clear_trails() - # 如果有行星环,则删除行星环 - if hasattr(self, "ring"): - destroy(self.ring) - self.body_view.body.appeared = False - self.body_view.appeared = False - # 最后删除自己 - destroy(self) - - class UrsinaView(BodyView): """ ursina天体视图(天体效果展示用)