def make_editor_gui(self): # called by main after setting up camera and application.development_mode from ursina import camera, Text, Button, ButtonList, Func, Tooltip import time self.editor_ui = Entity(parent=camera.ui, eternal=True, enabled=bool(application.development_mode)) self.exit_button = Button(parent=self.editor_ui, eternal=True, ignore_paused=True, origin=(.5, .5), position=self.top_right, z=-999, scale=(.05, .025), color=color.red.tint(-.2), text='x', on_click=application.quit) self.exit_button.enabled = self.borderless def _exit_button_input(key): from ursina import held_keys, mouse if held_keys['shift'] and key == 'q' and not mouse.right: self.exit_button.on_click() self.exit_button.input = _exit_button_input self.fps_counter = Text(parent=self.editor_ui, eternal=True, position=(.5*self.aspect_ratio, .47, -999), origin=(.8,.5), text='60', ignore=False, i=0) def _fps_counter_update(): if self.fps_counter.i > 60: self.fps_counter.text = str(int(1//time.dt)) self.fps_counter.i = 0 self.fps_counter.i += 1 self.fps_counter.update = _fps_counter_update import webbrowser self.cog_menu = ButtonList({ # 'Build' : Func(print, ' '), 'API Reference' : Func(webbrowser.open, 'https://www.ursinaengine.org/cheat_sheet_dark.html'), 'Asset Store' : Func(webbrowser.open, 'https://itch.io/tools/tag-ursina'), # 'Open Scene Editor' : Func(print, ' '), 'Change Render Mode <gray>[F10]<default>' : self.next_render_mode, 'Reset Render Mode <gray>[F9]<default>' : Func(setattr, self, 'render_mode', 'default'), 'Reload Models <gray>[F7]<default>' : application.hot_reloader.reload_models, 'Reload Textures <gray>[F6]<default>' : application.hot_reloader.reload_textures, 'Reload Code <gray>[F5]<default>' : application.hot_reloader.reload_code, }, width=.35, x=.62, enabled=False, eternal=True ) self.cog_menu.on_click = Func(setattr, self.cog_menu, 'enabled', False) self.cog_menu.y = -.5 + self.cog_menu.scale_y self.cog_menu.scale *= .75 self.cog_menu.text_entity.x += .025 self.cog_menu.highlight.color = color.azure self.cog_button = Button(parent=self.editor_ui, eternal=True, model='circle', scale=.015, origin=(1,-1), position=self.bottom_right) info_text ='''This menu is not enabled in builds <gray>(unless you set application.development to be not False).''' self.cog_menu.info = Button(parent=self.cog_menu, model='quad', text='<gray>?', scale=.1, x=1, y=.01, origin=(.5,-.5), tooltip=Tooltip(info_text, scale=.75, origin=(-.5,-.5))) self.cog_menu.info.text_entity.scale *= .75 def _toggle_cog_menu(): self.cog_menu.enabled = not self.cog_menu.enabled self.cog_button.on_click = _toggle_cog_menu
def layout(self): [destroy(c) for c in self.buttons] self.buttons = [] spacing = .05 longest_word = max(self.options, key=len) + '__' # padding width = Text.get_width(longest_word) / Text.size / 2 for e in self.options: b = Button(parent=self, text=e, name=e, scale_x=width, scale_y=.9) b.value = e b.highlight_scale = 1 b.pressed_scale = 1 self.buttons.append(b) grid_layout(self.buttons, spacing=(0.025, 0, 0), origin=(-.5, .5, 0))
def __init__(self, gameController): super().__init__( title='Menu', content=( Button(text='Restart', color=color.azure, on_click=self.restart), Button(text='Exit', color=color.azure, on_click=application.quit), ), ) self.hardRestart = False self.gameController = gameController self.ec = EditorCamera(rotation_smoothing=2, enabled=False, rotation=(30, 30, 0)) self.ec.enabled = False self.cur = Cursor() self.cur.disable() self.hide()
def __init__(self, **kwargs): super().__init__(**kwargs) self.phoneme_store = None self.voxels = [] self.correct = False self.started = False self.update_counter = None self.score = 0 self.difficulty = 3 # lower difficulty is harder self.help_text = Text( '', parent=camera.ui, x=-.6, y=.35, enabled=False ) self.score_text = Text( '', parent=camera.ui, x=.5, y=.35, enabled=False ) self.player = None self.ground = Entity(model='plane', scale=(100, 1, 100), y=-1, color=color.yellow.tint(-.2), texture='white_cube', texture_scale=(100, 100), collider='box', enabled=False) self.sky = Entity(model='sphere', texture='sky2.jpg', scale=10000, double_sided=True, color=color.white, enabled=False) self.rotated_y = 30 self.next_block = Entity(parent=camera.ui, rotation=Vec3(10, 30, 30), model='cube', scale=.1, x=.7, y=.2, texture='index') self.give_up_button = Button(parent=scene, text='give up', double_sided=True, x=-1, z=ARENA_DEPTH, y=3, on_click=self.give_up, enabled=False, scale_x=2) self.reset_text = Text( 'Press ESC to change words and/or start again.', parent=scene, x=0, z=ARENA_DEPTH, y=2, double_sided=True, enabled=False, scale=15 )
def __init__(self, title='', content=[], **kwargs): super().__init__(origin=(-0,.5), scale=(.5, Text.size*2), color=color.black) self.content = content self.text = title self.popup = False self._prev_input_field = None self._original_scale = self.scale for key, value in kwargs.items(): setattr(self, key ,value) if self.text_entity: self.text_entity.world_scale_y = 1 self.panel = Entity(parent=self, model='quad', origin=(0,.5), z=.1, color=self.color.tint(.1), collider='box') if self.popup: self.lock = Vec3(1,1,1) self.bg = Button(parent=self, z=1, scale=(999, 999), color=color.black66, highlight_color=color.black66, pressed_color=color.black66) self.bg.on_click = self.close self.layout()
class MainGame(Entity): def __init__(self, **kwargs): super().__init__(**kwargs) self.phoneme_store = None self.voxels = [] self.correct = False self.started = False self.update_counter = None self.score = 0 self.difficulty = 3 # lower difficulty is harder self.help_text = Text( '', parent=camera.ui, x=-.6, y=.35, enabled=False ) self.score_text = Text( '', parent=camera.ui, x=.5, y=.35, enabled=False ) self.player = None self.ground = Entity(model='plane', scale=(100, 1, 100), y=-1, color=color.yellow.tint(-.2), texture='white_cube', texture_scale=(100, 100), collider='box', enabled=False) self.sky = Entity(model='sphere', texture='sky2.jpg', scale=10000, double_sided=True, color=color.white, enabled=False) self.rotated_y = 30 self.next_block = Entity(parent=camera.ui, rotation=Vec3(10, 30, 30), model='cube', scale=.1, x=.7, y=.2, texture='index') self.give_up_button = Button(parent=scene, text='give up', double_sided=True, x=-1, z=ARENA_DEPTH, y=3, on_click=self.give_up, enabled=False, scale_x=2) self.reset_text = Text( 'Press ESC to change words and/or start again.', parent=scene, x=0, z=ARENA_DEPTH, y=2, double_sided=True, enabled=False, scale=15 ) def create_clouds(self): self.sky.enable() for i in range(20): cloud = Entity(parent=scene, model='cube', texture='index', scale_x=random.randint(2, ARENA_DEPTH), scale_y=random.randint(1, 6), scale_z=random.randint(2, ARENA_DEPTH), color=color.white, position=Vec3(random.randint(-50, ARENA_DEPTH+50), random.randint(10, 50), random.randint(-50, ARENA_DEPTH+50))) self.voxels.append(cloud) def give_up(self): self.score -= 1 if self.phoneme_store.words: self.build() else: self.end_game() def end_game(self): self.destroy_all() self.build_platform() self.correct = False self.update_counter = None self.update_score() if self.score > 0: self.help_text.text = f'GAME OVER! YOU WIN!\nYour score: {self.score}' else: self.help_text.text = f'GAME OVER! YOU LOSE!\nYour score: {self.score}' def reset(self): pass def build(self): self.started = True word = self.phoneme_store.get_new_word() self.update_counter = 0 if self.give_up_button.enabled: self.give_up_button.disable() if self.reset_text.enabled: self.reset_text.disable() if word is not None: if self.phoneme_store.pron() is not None: self.help_text.text = f'The word is: "{self.phoneme_store.word}"\nLeft click in the green area to lay a phoneme,\nright click to pick one up.' self.help_text.enable() self.score_text.text = f'Score: {self.score}' self.score_text.enable() if self.voxels: self.destroy_all() self.help_text.text = self.phoneme_store.word self.correct = False for z in range(ARENA_DEPTH + 1): voxel_side_wall = Voxel(self.phoneme_store, self, position=(-1, 1, z)) voxel_other_side_wall = Voxel(self.phoneme_store, self, position=(len(self.phoneme_store.phonemes), 1, z)) self.voxels.append(voxel_side_wall) self.voxels.append(voxel_other_side_wall) for x in range(len(self.phoneme_store.phonemes)): voxel = Voxel(self.phoneme_store, self, position=(x, 0, z)) voxel_wall = Voxel(self.phoneme_store, self, position=(x, 1, -1)) self.voxels.append(voxel) self.voxels.append(voxel_wall) if voxel.position[2] == ARENA_DEPTH: voxel.color = color.lime voxel.texture = 'white_cube' invoke(self.create_clouds, delay=0.1) if self.player: self.player.y = 0 self.player.x = len(self.phoneme_store.phonemes) // 2 self.player.z = 1 else: self.generate_player() else: return self.build() else: self.end_game() def build_platform(self): self.ground.enable() self.update_counter = None self.reset_text.enable() self.give_up_button.disable() self.create_clouds() self.started = False def update_score(self): self.score_text.text = f'Score: {self.score}' def destroy_all(self): for v in self.voxels: destroy(v) self.voxels = [] def generate_player(self): self.player = FirstPersonController(enabled=True) self.player.speed += 2 self.player.mouse_sensitivity = Vec2(50, 50) self.player.jump_duration = .3 self.player.gravity *= .8 self.player.y = 0 self.player.x = len(self.phoneme_store.phonemes) // 2 self.player.z = 1 def spin_block(self): self.rotated_y -= 1 self.next_block.rotation = Vec3(10, self.rotated_y, 30)
class Window(WindowProperties): def __init__(self): super().__init__() loadPrcFileData('', 'window-title ursina') loadPrcFileData('', 'notify-level-util error') loadPrcFileData('', 'textures-auto-power-2 #t') loadPrcFileData('', 'load-file-type p3assimp') # loadPrcFileData('', 'allow-portal-cull #t') # loadPrcFileData("", "framebuffer-multisample 1") # loadPrcFileData('', 'multisamples 2') # loadPrcFileData('', 'textures-power-2 none') # loadPrcFileData('', 'cursor-filename mycursor.ico') # loadPrcFileData('', 'threading-model Cull/Draw') loadPrcFileData('', 'coordinate-system y-up-left') # fallback to one of these if opengl is not supported loadPrcFileData('', 'aux-display pandadx9') loadPrcFileData('', 'aux-display pandadx8') loadPrcFileData('', 'aux-display tinydisplay') self.setForeground(True) self.vsync = True # can't be set during play self.show_ursina_splash = False self.title = application.asset_folder.name if os.name == 'nt': # windows import ctypes user32 = ctypes.windll.user32 user32.SetProcessDPIAware() self.screen_resolution = (user32.GetSystemMetrics(0), user32.GetSystemMetrics(1)) else: try: from screeninfo import get_monitors self.screen_resolution = (get_monitors()[0].width, get_monitors()[0].height) print('OS:', os.name) except: print('using default sceen resolution.', 'OS:', os.name) self.screen_resolution = Vec2(1366, 768) print('screen resolution:', self.screen_resolution) self.fullscreen_size = Vec2(self.screen_resolution[0] + 1, self.screen_resolution[1] + 1) self.windowed_size = self.fullscreen_size / 1.25 self.windowed_position = None # gets set when entering fullscreen so position will be correct when going back to windowed mode self.size = self.windowed_size self.borderless = True self.top = Vec2(0, .5) self.bottom = Vec2(0, -.5) self.center = Vec2(0, 0) def late_init(self): self.center_on_screen() if not application.development_mode: self.fullscreen = True self.cursor = True self.color = color.dark_gray self.render_modes = ('default', 'wireframe', 'colliders', 'normals') self.render_mode = 'default' self.editor_ui = None from ursina import invoke invoke(base.accept, 'aspectRatioChanged', self.update_aspect_ratio, delay=1 / 60) @property def left(self): return Vec2(-self.aspect_ratio / 2, 0) @property def right(self): return Vec2(self.aspect_ratio / 2, 0) @property def top_left(self): return Vec2(-self.aspect_ratio / 2, .5) @property def top_right(self): return Vec2(self.aspect_ratio / 2, .5) @property def bottom_left(self): return Vec2(-self.aspect_ratio / 2, -.5) @property def bottom_right(self): return Vec2(self.aspect_ratio / 2, -.5) def center_on_screen(self): print('size;', self.size) self.position = Vec2( int((self.screen_resolution[0] - self.size[0]) / 2), int((self.screen_resolution[1] - self.size[1]) / 2)) def make_editor_gui( self ): # called by main after setting up camera and application.development_mode from ursina import camera, Text, Button, ButtonList, Func, Tooltip import time self.editor_ui = Entity(parent=camera.ui, eternal=True, enabled=bool(application.development_mode)) self.exit_button = Button(parent=self.editor_ui, eternal=True, origin=(.5, .5), position=self.top_right, z=-999, scale=(.05, .025), color=color.red.tint(-.2), text='x', on_click=application.quit) self.exit_button.enabled = self.borderless def _exit_button_input(key): from ursina import held_keys, mouse if held_keys['shift'] and key == 'q' and not mouse.right: self.exit_button.on_click() self.exit_button.input = _exit_button_input self.fps_counter = Text(parent=self.editor_ui, eternal=True, position=(.5 * self.aspect_ratio, .47, -999), origin=(.8, .5), text='60', ignore=False, i=0) def _fps_counter_update(): if self.fps_counter.i > 60: self.fps_counter.text = str(int(1 // time.dt)) self.fps_counter.i = 0 self.fps_counter.i += 1 self.fps_counter.update = _fps_counter_update import webbrowser self.cog_menu = ButtonList( { # 'Build' : Func(print, ' '), 'API Reference': Func(webbrowser.open, 'https://www.ursinaengine.org/cheat_sheet_dark.html'), 'Asset Store': Func(webbrowser.open, 'https://itch.io/tools/tag-ursina'), # 'Open Scene Editor' : Func(print, ' '), 'Change Render Mode <gray>[F10]<default>': self.next_render_mode, 'Reset Render Mode <gray>[F9]<default>': Func(setattr, self, 'render_mode', 'default'), 'Reload Models <gray>[F7]<default>': application.hot_reloader.reload_models, 'Reload Textures <gray>[F6]<default>': application.hot_reloader.reload_textures, 'Reload Code <gray>[F5]<default>': application.hot_reloader.reload_code, }, width=.35, x=.62, enabled=False, eternal=True) self.cog_menu.on_click = Func(setattr, self.cog_menu, 'enabled', False) self.cog_menu.y = -.5 + self.cog_menu.scale_y self.cog_menu.scale *= .75 self.cog_menu.text_entity.x += .025 self.cog_menu.highlight.color = color.azure self.cog_button = Button(parent=self.editor_ui, eternal=True, model='circle', scale=.015, origin=(1, -1), position=self.bottom_right) info_text = '''This menu is not enabled in builds <gray>(unless you set application.development to be not False).''' self.cog_menu.info = Button(parent=self.cog_menu, model='quad', text='<gray>?', scale=.1, x=1, y=.01, origin=(.5, -.5), tooltip=Tooltip(info_text, scale=.75, origin=(-.5, -.5))) self.cog_menu.info.text_entity.scale *= .75 def _toggle_cog_menu(): self.cog_menu.enabled = not self.cog_menu.enabled self.cog_button.on_click = _toggle_cog_menu # print('-----------', time.time() - t) # 0.04 def update_aspect_ratio(self): prev_aspect = self.aspect_ratio self.size = base.win.get_size() print('changed aspect ratio:', round(prev_aspect, 3), '->', round(self.aspect_ratio, 3)) from ursina import camera, window, application camera.ui_lens.set_film_size(camera.ui_size * .5 * self.aspect_ratio, camera.ui_size * .5) for e in [e for e in scene.entities if e.parent == camera.ui ] + self.editor_ui.children: e.x /= prev_aspect / self.aspect_ratio if camera.orthographic: camera.orthographic_lens.set_film_size( camera.fov * window.aspect_ratio, camera.fov) application.base.cam.node().set_lens(camera.orthographic_lens) @property def position(self): return self._position @position.setter def position(self, value): # print('set window position:', value) self._position = value self.setOrigin(int(value[0]), int(value[1])) base.win.request_properties(self) @property def size(self): return Vec2(self.get_size()[0], self.get_size()[1]) @size.setter def size(self, value): self.set_size(int(value[0]), int(value[1])) self.aspect_ratio = value[0] / value[1] from ursina import camera camera.set_shader_input('window_size', value) @property def render_mode(self): return self._render_mode @render_mode.setter def render_mode(self, value): self._render_mode = value print('render mode:', value) base.wireframeOff() # disable collision display mode if hasattr(self, 'original_colors'): for i, e in enumerate( [e for e in scene.entities if hasattr(e, 'color')]): e.color = self.original_colors[i] if e.collider: e.collider.visible = False for e in [e for e in scene.entities if e.model and e.alpha]: e.setShaderAuto() if value == 'wireframe': base.wireframeOn() if value == 'colliders': self.original_colors = [ e.color for e in scene.entities if hasattr(e, 'color') ] for e in scene.entities: e.color = color.clear if e.collider: # e.visible = False e.collider.visible = True if value == 'normals': from ursina.shaders import normals_shader for e in [e for e in scene.entities if e.model and e.alpha]: e.shader = normals_shader e.set_shader_input('transform_matrix', e.getNetTransform().getMat()) def next_render_mode(self): i = self.render_modes.index(self.render_mode) + 1 if i >= len(self.render_modes): i = 0 self.render_mode = self.render_modes[i] @property def icon(self): return self._icon @icon.setter def icon(self, value): self._icon = value self.setIconFilename(value) def __setattr__(self, name, value): try: super().__setattr__(name, value) except: pass if name == 'fullscreen': try: if value == True: self.windowed_position = self.position self.windowed_size = self.size self.size = self.fullscreen_size self.center_on_screen() else: self.size = self.windowed_size if self.windowed_position is not None: self.position = self.windowed_position else: self.center_on_screen() object.__setattr__(self, name, value) return except: print('failed to set fullscreen', value) pass if name == 'borderless': self.setUndecorated(value) if hasattr(self, 'exit_button'): self.exit_button.enabled = not value try: application.base.win.request_properties(self) except: pass object.__setattr__(self, name, value) if name == 'color': application.base.camNode.get_display_region( 0).get_window().set_clear_color(value) if name == 'vsync': if value == True: loadPrcFileData('', 'sync-video True') else: loadPrcFileData('', 'sync-video False') print('set vsync to false') object.__setattr__(self, name, value)
class Window(WindowProperties): def __init__(self): super().__init__() loadPrcFileData('', 'window-title ursina') loadPrcFileData('', 'notify-level-util error') loadPrcFileData('', 'textures-auto-power-2 #t') loadPrcFileData('', 'load-file-type p3assimp') # loadPrcFileData('', 'allow-portal-cull #t') # loadPrcFileData("", "framebuffer-multisample 1") # loadPrcFileData('', 'multisamples 2') # loadPrcFileData('', 'textures-power-2 none') # loadPrcFileData('', 'threading-model Cull/Draw') loadPrcFileData('', 'coordinate-system y-up-left') # fallback to one of these if opengl is not supported loadPrcFileData('', 'aux-display pandadx9') loadPrcFileData('', 'aux-display pandadx8') loadPrcFileData('', 'aux-display tinydisplay') self.vsync = True # can't be set during play self.show_ursina_splash = False self.title = application.asset_folder.name self.borderless = True # self.icon = 'textures/ursina.ico' os_name = platform.system() try: if os_name == 'Windows': # windows import ctypes user32 = ctypes.windll.user32 user32.SetProcessDPIAware() self.screen_resolution = (user32.GetSystemMetrics(0), user32.GetSystemMetrics(1)) elif os_name == 'Linux': import Xlib import Xlib.display resolution = Xlib.display.Display().screen().root.get_geometry( ) self.screen_resolution = Vec2(resolution.width, resolution.height) elif os_name == 'Darwin': # mac from AppKit import NSScreen size = NSScreen.mainScreen().frame().size self.screen_resolution = [size.width, size.height] except: from screeninfo import get_monitors self.screen_resolution = [ get_monitors()[0].width, get_monitors()[0].height ] self.fullscreen_size = Vec2(*self.screen_resolution) self.windowed_size = self.fullscreen_size / 1.25 self.windowed_position = None # gets set when entering fullscreen so position will be correct when going back to windowed mode self.forced_aspect_ratio = None # example: window.forced_aspect_ratio = 16/9 self.size = self.windowed_size self.always_on_top = False self.top = Vec2(0, .5) self.bottom = Vec2(0, -.5) self.center = Vec2(0, 0) def late_init(self): self.center_on_screen() if not application.development_mode: self.fullscreen = True self.color = color.dark_gray self.render_modes = ('default', 'wireframe', 'colliders', 'normals') self.render_mode = 'default' self.editor_ui = None base.accept('aspectRatioChanged', self.update_aspect_ratio) if self.always_on_top: self.setZOrder(WindowProperties.Z_top) @property def left(self): return Vec2(-self.aspect_ratio / 2, 0) @property def right(self): return Vec2(self.aspect_ratio / 2, 0) @property def top_left(self): return Vec2(-self.aspect_ratio / 2, .5) @property def top_right(self): return Vec2(self.aspect_ratio / 2, .5) @property def bottom_left(self): return Vec2(-self.aspect_ratio / 2, -.5) @property def bottom_right(self): return Vec2(self.aspect_ratio / 2, -.5) def center_on_screen(self): self.position = Vec2( int((self.screen_resolution[0] - self.size[0]) / 2), int((self.screen_resolution[1] - self.size[1]) / 2)) def make_editor_gui( self ): # called by main after setting up camera and application.development_mode from ursina import camera, Entity, Text, Button, ButtonList, Func, Tooltip, held_keys, mouse import time self.editor_ui = Entity(parent=camera.ui, eternal=True, enabled=bool(application.development_mode)) self.exit_button = Button(parent=self.editor_ui, eternal=True, ignore_paused=True, origin=(.5, .5), enabled=self.borderless, position=self.top_right, z=-999, scale=(.05, .025), color=color.red.tint(-.2), text='x', on_click=application.quit, name='exit_button') def _exit_button_input(key): if held_keys['shift'] and key == 'q' and not mouse.right: self.exit_button.on_click() self.exit_button.input = _exit_button_input self.fps_counter = Text( parent=self.editor_ui, eternal=True, origin=(.8, .5), text='60', ignore=False, i=0, position=(.5 * self.aspect_ratio, .47 + (.02 * (not self.exit_button.enabled)), -999)) def _fps_counter_update(): if self.fps_counter.i > 60: self.fps_counter.text = str(int(1 // time.dt)) self.fps_counter.i = 0 self.fps_counter.i += 1 self.fps_counter.update = _fps_counter_update import webbrowser self.cog_menu = ButtonList( { # 'Build' : Func(print, ' '), 'API Reference': Func(webbrowser.open, 'https://www.ursinaengine.org/cheat_sheet_dark.html'), # 'Asset Store' : Func(webbrowser.open, 'https://itch.io/tools/tag-ursina'), 'ursfx (Sound Effect Maker)': lambda: exec( 'from ursina.prefabs import ursfx; ursfx.gui.enabled = True' ), # 'Open Scene Editor' : Func(print, ' '), 'Change Render Mode <gray>[F10]<default>': self.next_render_mode, 'Reset Render Mode <gray>[F9]<default>': Func(setattr, self, 'render_mode', 'default'), 'Reload Models <gray>[F7]<default>': application.hot_reloader.reload_models, 'Reload Textures <gray>[F6]<default>': application.hot_reloader.reload_textures, 'Reload Code <gray>[F5]<default>': application.hot_reloader.reload_code, }, width=.35, x=.62, enabled=False, eternal=True, name='cog_menu', ) self.cog_menu.on_click = Func(setattr, self.cog_menu, 'enabled', False) self.cog_menu.y = -.5 + self.cog_menu.scale_y self.cog_menu.scale *= .75 self.cog_menu.text_entity.x += .025 self.cog_menu.highlight.color = color.azure self.cog_button = Button(parent=self.editor_ui, eternal=True, model='quad', texture='cog', scale=.015, origin=(1, -1), position=self.bottom_right, name='cog_button') info_text = '''This menu is not enabled in builds <gray>(unless you set application.development_mode to be not False).''' self.cog_menu.info = Button(parent=self.cog_menu, model='quad', text='<gray>?', scale=.1, x=1, y=.01, origin=(.5, -.5), tooltip=Tooltip(info_text, scale=.75, origin=(-.5, -.5), eternal=True), eternal=True, name='cog_menu_info') self.cog_menu.info.text_entity.scale *= .75 def _toggle_cog_menu(): self.cog_menu.enabled = not self.cog_menu.enabled self.cog_button.on_click = _toggle_cog_menu # print('-----------', time.time() - t) # 0.04 def update_aspect_ratio(self): prev_aspect = self.aspect_ratio self.aspect_ratio = self.size[0] / self.size[1] from ursina import camera, window, application value = [int(e) for e in base.win.getSize()] camera.set_shader_input('window_size', value) print_info('changed aspect ratio:', round(prev_aspect, 3), '->', round(self.aspect_ratio, 3)) camera.ui_lens.set_film_size(camera.ui_size * .5 * self.aspect_ratio, camera.ui_size * .5) for e in [e for e in scene.entities if e.parent == camera.ui ] + self.editor_ui.children: e.x /= prev_aspect / self.aspect_ratio if camera.orthographic: camera.orthographic_lens.set_film_size( camera.fov * window.aspect_ratio, camera.fov) application.base.cam.node().set_lens(camera.orthographic_lens) @property def position(self): return self._position @position.setter def position(self, value): # print('set window position:', value) self._position = value self.setOrigin(int(value[0]), int(value[1])) base.win.request_properties(self) @property def size(self): if not self.borderless: return Vec2(*base.win.getSize()) return self._size @size.setter def size(self, value): if hasattr(self, '_forced_aspect_ratio') and self.forced_aspect_ratio: value = (value[1] * self.forced_aspect_ratio, value[1]) self._size = value self.setSize(int(value[0]), int(value[1])) self.aspect_ratio = value[0] / value[1] from ursina import camera camera.set_shader_input('window_size', value) base.win.request_properties(self) @property def forced_aspect_ratio(self): if not hasattr(self, '_forced_aspect_ratio'): return None return self._forced_aspect_ratio @forced_aspect_ratio.setter def forced_aspect_ratio(self, value): if not value: return print('ttoooo', value) self._forced_aspect_ratio = value self.size = self.size @property def render_mode(self): return self._render_mode @render_mode.setter def render_mode(self, value): self._render_mode = value # print('render mode:', value) base.wireframeOff() # disable collision display mode if hasattr(self, 'original_colors'): for i, e in enumerate( [e for e in scene.entities if hasattr(e, 'color')]): e.color = self.original_colors[i] if e.collider: e.collider.visible = False for e in [e for e in scene.entities if e.model and e.alpha]: e.setShaderAuto() if value == 'wireframe': base.wireframeOn() elif value == 'colliders': self.original_colors = [ e.color for e in scene.entities if hasattr(e, 'color') ] for e in scene.entities: e.color = color.clear if e.collider: # e.visible = False e.collider.visible = True elif value == 'normals': from ursina.shaders import normals_shader for e in [e for e in scene.entities if e.model and e.alpha]: e.shader = normals_shader e.set_shader_input('transform_matrix', e.getNetTransform().getMat()) def next_render_mode(self): i = self.render_modes.index(self.render_mode) + 1 if i >= len(self.render_modes): i = 0 self.render_mode = self.render_modes[i] @property def title(self): return self._title @title.setter def title(self, value): self._title = value loadPrcFileData('', f'window-title {value}') @property def icon(self): return self._icon @icon.setter def icon(self, value): self._icon = value self.setIconFilename(value) def __setattr__(self, name, value): try: super().__setattr__(name, value) except: pass if name == 'fullscreen': try: if value == True: self.windowed_position = self.position self.windowed_size = self.size self.size = self.fullscreen_size self.center_on_screen() else: self.size = self.windowed_size if self.windowed_position is not None: self.position = self.windowed_position else: self.center_on_screen() self.setFullscreen(value) object.__setattr__(self, name, value) return except: print_warning('failed to set fullscreen', value) pass if name == 'borderless': self.setUndecorated(value) if hasattr(self, 'exit_button'): self.exit_button.enabled = not value try: application.base.win.request_properties(self) except: pass object.__setattr__(self, name, value) if name == 'color': application.base.camNode.get_display_region( 0).get_window().set_clear_color(value) if name == 'vsync': if not application.base: # set vsync/framerate before window opened if value == True or value == False: loadPrcFileData('', f'sync-video {value}') elif isinstance(value, int): loadPrcFileData('', 'clock-mode limited') loadPrcFileData('', f'clock-frame-rate {value}') else: from panda3d.core import ClockObject # set vsync/framerate in runtime if value == True: globalClock.setMode(ClockObject.MNormal) elif value == False: print_warning( 'error: disabling vsync during runtime is not yet implemented' ) elif isinstance(value, (int, float, complex)): globalClock.setMode(ClockObject.MLimited) globalClock.setFrameRate(int(value)) object.__setattr__(self, name, value)
class Window(WindowProperties): def __init__(self): super().__init__() loadPrcFileData('', 'window-title ursina') loadPrcFileData('', 'notify-level-util error') loadPrcFileData('', 'textures-auto-power-2 #t') loadPrcFileData('', 'load-file-type p3assimp') loadPrcFileData("", "framebuffer-multisample 1") # loadPrcFileData('', 'framebuffer-multisample 1') loadPrcFileData('', 'multisamples 2') # loadPrcFileData('', 'textures-power-2 none') # loadPrcFileData('', 'cursor-filename mycursor.ico') # loadPrcFileData('', 'threading-model Cull/Draw') loadPrcFileData('', 'coordinate-system y-up-left') self.setForeground(True) self.vsync = True # can't be set during play self.show_ursina_splash = False self.title = application.asset_folder.name try: self.screen_resolution = (get_monitors()[0].width, get_monitors()[0].height) except: print('using default sceen resolution.', 'OS:', os.name) self.screen_resolution = Vec2(1366, 768) print('screen resolution:', self.screen_resolution) self.fullscreen_size = Vec2(self.screen_resolution[0]+1, self.screen_resolution[1]+1) self.windowed_size = self.fullscreen_size / 1.25 self.windowed_position = None # gets set when entering fullscreen so position will be correct when going back to windowed mode self.size = self.windowed_size self.borderless = True def late_init(self): self.position = Vec2(0,0) self.top = Vec2(0, .5) self.bottom = Vec2(0, .5) self.center = Vec2(0, 0) self.fullscreen = False self.cursor = True self.color = color.dark_gray self.render_modes = ( 'default', 'wireframe', 'colliders', 'normals', ) self.render_mode = 'default' self.editor_ui = None @property def left(self): return Vec2(-self.aspect_ratio/2, 0) @property def right(self): return Vec2(self.aspect_ratio/2, 0) @property def top_left(self): return Vec2(-self.aspect_ratio/2, .5) @property def top_right(self): return Vec2(self.aspect_ratio/2, .5) @property def bottom_left(self): return Vec2(-self.aspect_ratio/2, -.5) @property def bottom_right(self): return Vec2(self.aspect_ratio/2, -.5) def center_on_screen(self): self.position = Vec2( int((self.screen_resolution[0] - self.size[0]) / 2), int((self.screen_resolution[1] - self.size[1]) / 2) ) def make_editor_gui(self): # called by main after setting up camera and application.development_mode from ursina import camera, Text, Button, ButtonList, Func import time self.editor_ui = Entity(parent=camera.ui, eternal=True, enabled=bool(application.development_mode)) self.exit_button = Button(parent=self.editor_ui, eternal=True, origin=(.5, .5), position=self.top_right, z=-999, scale=(.05, .025), color=color.red.tint(-.2), text='x', on_click=application.quit) def _exit_button_input(key): from ursina import held_keys, mouse if held_keys['shift'] and key == 'q' and not mouse.right: self.exit_button.on_click() self.exit_button.input = _exit_button_input self.fps_counter = Text(parent=self.editor_ui, eternal=True, position=(.5*self.aspect_ratio, .47, -999), origin=(.8,.5), text='60', ignore=False, i=0) def _fps_counter_update(): if self.fps_counter.i > 60: self.fps_counter.text = str(int(1//time.dt)) self.fps_counter.i = 0 self.fps_counter.i += 1 self.fps_counter.update = _fps_counter_update import webbrowser self.cog_menu = ButtonList({ # 'Build' : Func(print, ' '), 'Asset Store' : Func(webbrowser.open, "https://itch.io/tools/tag-ursina"), # 'Open Scene Editor' : Func(print, ' '), 'Change Render Mode <gray>[F10]<default>' : self.next_render_mode, 'Reset Render Mode <gray>[F9]<default>' : Func(setattr, self, 'render_mode', 'default'), 'Reload Models <gray>[F7]<default>' : application.hot_reloader.reload_models, 'Reload Textures <gray>[F6]<default>' : application.hot_reloader.reload_textures, 'Reload Code <gray>[F5]<default>' : application.hot_reloader.reload_code, }, width=.35, x=.62, enabled=False, eternal=True ) self.cog_menu.on_click = Func(setattr, self.cog_menu, 'enabled', False) self.cog_menu.y = -.5 + self.cog_menu.scale_y self.cog_menu.scale *= .75 self.cog_menu.text_entity.x += .025 self.cog_menu.highlight.color = color.azure self.cog_button = Button(parent=self.editor_ui, eternal=True, model='circle', scale=.015, origin=(1,-1), position=self.bottom_right) def _toggle_cog_menu(): self.cog_menu.enabled = not self.cog_menu.enabled self.cog_button.on_click = _toggle_cog_menu # print('-----------', time.time() - t) # 0.04 def update_aspect_ratio(self): from ursina import camera camera.ui_lens.set_film_size(camera.ui_size * .5 * self.aspect_ratio, camera.ui_size * .5) @property def size(self): return Vec2(self.get_size()[0], self.get_size()[1]) @size.setter def size(self, value): self.set_size(int(value[0]), int(value[1])) self.aspect_ratio = value[0] / value[1] base.win.requestProperties(self) self.update_aspect_ratio() @property def render_mode(self): return self._render_mode @render_mode.setter def render_mode(self, value): self._render_mode = value print('render mode:', value) base.wireframeOff() # disable collision display mode if hasattr(self, 'original_colors'): for i, e in enumerate([e for e in scene.entities if hasattr(e, 'color')]): e.color = self.original_colors[i] if e.collider: e.collider.visible = False for e in [e for e in scene.entities if e.model and e.alpha]: e.setShaderAuto() if value == 'wireframe': base.wireframeOn() if value == 'colliders': self.original_colors = [e.color for e in scene.entities if hasattr(e, 'color')] for e in scene.entities: e.color = color.clear if e.collider: # e.visible = False e.collider.visible = True if value == 'normals': from ursina.shaders import normals_shader for e in [e for e in scene.entities if e.model and e.alpha]: e.shader = normals_shader e.set_shader_input('transform_matrix', e.getNetTransform().getMat()) def next_render_mode(self): i = self.render_modes.index(self.render_mode) + 1 if i >= len(self.render_modes): i = 0 self.render_mode = self.render_modes[i] def __setattr__(self, name, value): try: super().__setattr__(name, value) except: pass if name == 'position': self.setOrigin(int(value[0]), int(value[1])) application.base.win.request_properties(self) object.__setattr__(self, name, value) if name == 'fullscreen': try: if value == True: self.windowed_size = self.size self.windowed_position = self.position self.size = self.fullscreen_size self.center_on_screen() else: self.size = self.windowed_size if self.windowed_position is not None: self.position = self.windowed_position else: self.center_on_screen() object.__setattr__(self, name, value) return except: print('failed to set fullscreen', value) pass if name == 'borderless': self.setUndecorated(value) try: application.base.win.request_properties(self) except: pass object.__setattr__(self, name, value) if name == 'color': application.base.camNode.get_display_region(0).get_window().set_clear_color(value) if name == 'vsync': if value == True: loadPrcFileData('', 'sync-video True') else: loadPrcFileData('', 'sync-video False') print('set vsync to false') object.__setattr__(self, name, value)
super().__init__() self.parent = camera.ui self.texture = 'cursor' self.model = 'quad' self.color = color.light_gray # self.origin = (-.49, .49) self.scale *= .05 self.render_queue = 1 for key, value in kwargs.items(): setattr(self, key, value) def update(self): self.position = Vec3(mouse.x, mouse.y, -100) if __name__ == '__main__': from ursina import Ursina, Button, scene, Panel, Mesh app = Ursina() Button('button').fit_to_text() camera.orthographic = True camera.fov = 100 cursor = Cursor(model=Mesh(vertices=[(-.5, 0, 0), (.5, 0, 0), (0, -.5, 0), (0, .5, 0)], triangles=[(0, 1), (2, 3)], mode='line', thickness=2), scale=.02) mouse.visible = False app.run()
def make_editor_gui( self ): # called by main after setting up camera and application.development_mode from ursina import camera, Text, Button, ButtonList, Func import time if not application.development_mode: return self.editor_ui = Entity(parent=camera.ui, eternal=True) self.exit_button = Button(parent=self.editor_ui, eternal=True, origin=(.5, .5), position=self.top_right, z=-999, scale=(.05, .025), color=color.red.tint(-.2), text='x', on_click=application.quit) def _exit_button_input(key): from ursina import held_keys, mouse if held_keys['shift'] and key == 'q' and not mouse.right: self.exit_button.on_click() self.exit_button.input = _exit_button_input self.fps_counter = Text(parent=self.editor_ui, eternal=True, position=(.5 * self.aspect_ratio, .47, -999), origin=(.8, .5), text='60', ignore=False, i=0) def _fps_counter_update(): if self.fps_counter.i > 60: self.fps_counter.text = str(int(1 // time.dt)) self.fps_counter.i = 0 self.fps_counter.i += 1 self.fps_counter.update = _fps_counter_update import webbrowser self.cog_menu = ButtonList( { # 'Build' : Func(print, ' '), 'Asset Store': Func(webbrowser.open, "https://itch.io/tools/tag-ursina"), # 'Open Scene Editor' : Func(print, ' '), 'Reload Textures [F6]': application.hot_reloader.reload_textures, 'Reload Models [F7]': application.hot_reloader.reload_models, 'Reload Code [F5]': application.hot_reloader.reload_code, }, width=.3, x=.64, enabled=False, eternal=True) self.cog_menu.on_click = Func(setattr, self.cog_menu, 'enabled', False) self.cog_menu.y = -.5 + self.cog_menu.scale_y self.cog_menu.scale *= .75 self.cog_menu.text_entity.x += .025 self.cog_menu.highlight.color = color.azure self.cog_button = Button(parent=self.editor_ui, eternal=True, model='circle', scale=.015, origin=(1, -1), position=self.bottom_right) def _toggle_cog_menu(): self.cog_menu.enabled = not self.cog_menu.enabled self.cog_button.on_click = _toggle_cog_menu
except: pass def close(self): if self.popup: self.bg.enabled = False self.animate_scale_y(0, duration=.1) invoke(setattr, self, 'enabled', False, delay=.2) if __name__ == '__main__': ''' WindowPanel is an easy way to create UI. It will automatically layout the content. ''' from ursina import Ursina, ButtonGroup app = Ursina() wp = WindowPanel( title='Custom Window', content=( Text('Name:'), InputField(name='name_field'), Button(text='Submit', color=color.azure), Slider(), Slider(), ButtonGroup(('test', 'eslk', 'skffk')) ), ) app.run()
if name == 'vsync': if value == True: loadPrcFileData('', 'sync-video True') else: loadPrcFileData('', 'sync-video False') print('set vsync to false') object.__setattr__(self, name, value) sys.modules[__name__] = Window() if __name__ == '__main__': from ursina import * # application.development_mode = False app = Ursina() window.title = 'Title' window.borderless = False # window.fullscreen = False window.fps_counter.enabled = False # window.exit_button.visible = False # window.cog_button.enabled = False camera.orthographic = True camera.fov = 2 Entity(model='cube', color=color.green, collider='box', texture='shore') Button(scale=.5, text='test', position=window.right) app.run()