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

Python超人-宇宙模拟器

上级 13a2fe21
......@@ -12,6 +12,7 @@ import numpy as np
import random
import os
import math
import time
def get_dominant_colors(infile, resize=(20, 20)):
......@@ -96,6 +97,15 @@ def find_file(file_path, default_val=None, find_deep=5):
return default_val
def wait_for(secs):
wait = secs * 800
while True:
if wait <= 0:
return
time.sleep(0.001)
wait -= 1
def calculate_distance(pos1, pos2=[0, 0, 0]):
"""
计算两点间的距离
......
......@@ -285,6 +285,31 @@ 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):
# 创建一个 Panel 组件
from ursina import Text, Panel, color, camera, Vec3
from simulators.ursina.ursina_config import UrsinaConfig
panel = Panel(
parent=None,
model='quad',
# texture='white_cube',
color=color.black,
origin=(-.48, .48, -.48),
scale=(width, height),
position=(left, top, 0)
)
def switch_color():
if panel.color == color.black:
panel.color = color.white
else:
panel.color = color.black
panel.switch_color = switch_color
return panel
def create_text_panel(width=0.35, height=.5):
# 创建一个 Panel 组件
from ursina import Text, Panel, color, camera, Vec3
......
......@@ -7,8 +7,10 @@
# python_version :3.8
# ==============================================================================
import sys
import time
from common.func import wait_for
from common.consts import AU
from sim_scenes.func import ursina_run, create_solar_system_bodies, create_light_ship
from sim_scenes.func import ursina_run, create_solar_system_bodies, create_light_ship, create_3d_card
from common.consts import LIGHT_SPEED
from sim_scenes.science.speed_of_light_init import SpeedOfLightInit
......@@ -42,7 +44,7 @@ else:
camera_pos = "right"
print("camera_pos:", camera_pos)
camera_l2r = 0.1 * AU
camera_l2r = 0.01 * AU
if camera_pos == "right": # 摄像机右眼
init.light_init_position[0] += camera_l2r
......@@ -56,9 +58,22 @@ init.light_init_position[1] = 1000000
# 从 init 对象中获取 光体的大小(light_size_scale),光体的位置(light_init_position)
# 创建一个以光速前进的天体(模拟一个光子) speed=1光速=299792.458千米/秒,注意:质量为0才能达到光速,虽然如此,但也可以试试超光速
light_ship = create_light_ship(init.light_size_scale, init.light_init_position, speed=LIGHT_SPEED * 1)
light_ship.camera_pos = camera_pos
# 增加光速天体到天体集合
bodies.append(light_ship)
def switch_position():
if light_ship.camera_pos == "right": # 摄像机右眼
light_ship.position[0] -= 2 * camera_l2r
light_ship.camera_pos = "left"
elif light_ship.camera_pos == "left": # 摄像机左眼
light_ship.position[0] += 2 * camera_l2r
light_ship.camera_pos = "right"
light_ship.switch_position = switch_position
# 运行前指定bodies、light_body并订阅事件
init.light_ship = light_ship
init.bodies = bodies
......@@ -68,22 +83,32 @@ UrsinaEvent.on_reset_unsubscription(init.on_reset)
def on_reset():
init.on_reset
init.on_reset()
init.arrived_info = "距离[太阳中心]:${distance}\n\n"
init.arrived_info = "距离[太阳中心]:${distance}\n\n光速飞船速度:${speed}\n\n"
def on_ready():
init._3d_card = create_3d_card()
def on_timer_changed(time_data: TimeData):
init.text_panel.parent.enabled = False
velocity, _ = get_value_direction_vectors(light_ship.velocity)
distance = round(init.light_ship.position[2] / AU, 4)
text = init.arrived_info.replace("${distance}", "%.4f AU" % distance)
init.text_panel.text = text.replace("${speed}", str(round(velocity / LIGHT_SPEED, 1)) + "倍光速")
init._3d_card.switch_color()
light_ship.switch_position()
if time_data.total_seconds > 20:
wait_for(0.3)
# 订阅重新开始事件
# 按键盘的 “O” 重置键会触发 on_reset
UrsinaEvent.on_reset_subscription(on_reset)
UrsinaEvent.on_ready_subscription(on_ready)
# 订阅计时器事件(记录已到达天体列表)
# 运行中,每时每刻都会触发 on_timer_changed
UrsinaEvent.on_timer_changed_subscription(on_timer_changed)
......
import cv2
from PIL import ImageGrab, Image
import numpy as np
import argparse
import time
import os
import win32gui
import win32ui
import win32con
import win32api
import traceback
def get_window_handle(window_name="universe_sim"):
"""
获取模拟器窗口句柄
@param window_name:
@return:
"""
handle = win32gui.FindWindow(None, window_name)
return handle
def get_args():
parser = argparse.ArgumentParser()
parser.add_argument('--fps', type=int, default=30, help='frame per second')
parser.add_argument('--total_time', type=int, default=10000000, help='video total time')
parser.add_argument('--save_name', type=str, default='video.mp4', help='save file name')
# parser.add_argument('--screen_type', default=0, type=int, choices=[0, 1], help='1: full screen, 0: region screen')
args = parser.parse_args()
print("total_time:", args.total_time)
print("fps:", args.fps)
print("save_name:", args.save_name)
return args
def screen_shot(window_img_dc):
width, height = win32api.GetSystemMetrics(win32con.SM_CXVIRTUALSCREEN), \
win32api.GetSystemMetrics(win32con.SM_CYVIRTUALSCREEN)
# 创建一个内存设备描述表
mem_dc = window_img_dc.CreateCompatibleDC()
# 创建位图对象
screenshot = win32ui.CreateBitmap()
screenshot.CreateCompatibleBitmap(window_img_dc, width, height)
mem_dc.SelectObject(screenshot)
# 截图至内存设备描述表
mem_dc.BitBlt((0, 0), (width, height), window_img_dc, (0, 0), win32con.SRCCOPY)
# 将截图保存到文件中
# screenshot.SaveBitmapFile(mem_dc, 'screenshot.bmp')
signedIntsArray = screenshot.GetBitmapBits(True)
# 下面3个语句都能实现转换,推荐第1个
img = np.fromstring(signedIntsArray, dtype='uint8')
img.shape = (height, width, 4)
# 内存释放
mem_dc.DeleteDC()
win32gui.DeleteObject(screenshot.GetHandle())
img = img[:, :, 0:3] # 去掉透明数据
return img
# def is_blank_screen(img_arr):
# for x in range(500, 600):
# for y in range(10, 20):
# pix = img_arr[x, y, ]
# # 检查标题栏,此时标题栏的颜色为白色
# if pix.sum() > 600:
# return True
# return False
def sim_window_screen_shot(wait_ses=-1):
times = wait_ses * 100
while True:
handle = get_window_handle()
if handle > 0:
desktop_dc = win32gui.GetWindowDC(handle)
img_dc = win32ui.CreateDCFromHandle(desktop_dc)
try:
img = screen_shot(img_dc)
except Exception as e:
print("ERROR:", str(e))
traceback.print_exc()
return None
return img
if wait_ses < 0:
return None
time.sleep(0.01)
times -= 1
if times <= 0:
return None
def create_video(args, height, width):
fourcc = cv2.VideoWriter_fourcc(*'mp4v')
video = cv2.VideoWriter(args.save_name, fourcc, args.fps, (width, height))
return video
# def show_image(img):
# from PIL import Image
# image = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
# image = Image.fromarray(image)
# print(type(image)) # 结果为<class 'PIL.JpegImagePlugin.JpegImageFile'>
# print(image.size) # 结果为(822,694),这里注意Image输出的结果先显示列数,后显示行数
# image.show()
if __name__ == '__main__':
args = get_args()
handle = get_window_handle()
# print(get_args())
print("请在10秒内打开模拟器")
img = sim_window_screen_shot(10)
if img is None:
print("没有找到模拟器窗口,录屏失败!")
exit(1)
# show_image(img)
video = create_video(args, img.shape[0], img.shape[1])
imageNum = 0
print("开始录屏")
while True:
img = sim_window_screen_shot()
if img is None:
print("\n模拟器窗口已关闭,退出录屏")
break
# if is_blank_screen(img):
# if imageNum % args.fps == 0:
# print('x', end='')
#
# continue
if imageNum % args.fps == 0:
print('.', end='')
# else:
# print(imageNum, end='')
imageNum += 1
# frame = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
if imageNum < args.fps * args.total_time:
# show_image(frame)
video.write(img)
print("视频保存中")
video.release()
cv2.destroyAllWindows()
# crop('video.mp4')
print("视频保存完成")
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册