ya2 · news · projects · code · about

fix: building of screenshots
[pmachines.git] / pmachines / scene.py
index 14b991dcbbece98a68d01770e92e71975a78ad62..b2cc3d5960de435e9501d895f4215c661545e8e6 100644 (file)
@@ -1,4 +1,7 @@
 from os.path import exists
+from glob import glob
+from importlib import import_module
+from inspect import isclass
 from panda3d.core import AmbientLight, DirectionalLight, Point3, Texture, \
     TextPropertiesManager, TextNode, Spotlight, PerspectiveLens, BitMask32
 from panda3d.bullet import BulletPlaneShape, BulletGhostNode
@@ -15,14 +18,15 @@ from lib.lib.p3d.gfx import P3dGfxMgr
 
 class Scene(DirectObject):
 
-    def __init__(self, world, exit_cb, auto_close_instr, dbg_items):
+    def __init__(self, world, exit_cb, auto_close_instr, dbg_items, reload_cb):
         super().__init__()
         self._world = world
         self._exit_cb = exit_cb
         self._dbg_items = dbg_items
+        self._reload_cb = reload_cb
         self._set_camera()
         self._cursor = MouseCursor(
-            'assets/buttons/arrowUpLeft.png', (.04, 1, .04), (.5, .5, .5, 1),
+            'assets/images/buttons/arrowUpLeft.dds', (.04, 1, .04), (.5, .5, .5, 1),
             (.01, .01))
         self._set_gui()
         self._set_lights()
@@ -30,6 +34,7 @@ class Scene(DirectObject):
         self._set_mouse_plane()
         self.items = []
         self.reset()
+        self._state = 'init'
         self._paused = False
         self._item_active = None
         if auto_close_instr:
@@ -70,7 +75,10 @@ class Scene(DirectObject):
             enable_shadows=True)
         base.graphicsEngine.renderFrame()
         base.graphicsEngine.renderFrame()
-        # buffer.save_screenshot('assets/scene.png')
+        fname = self.__class__.__name__
+        if not exists('assets/images/scenes'):
+            makedirs('assets/images/scenes')
+        buffer.save_screenshot('assets/images/scenes/%s.png' % fname)
         # img = DirectButton(
         #     frameTexture=buffer.get_texture(), relief=FLAT,
         #     frameSize=(-.2, .2, -.2, .2))
@@ -86,6 +94,7 @@ class Scene(DirectObject):
     def reset(self):
         [itm.destroy() for itm in self.items]
         self._set_items()
+        self._state = 'init'
         self._commands = []
         self._command_idx = 0
         if hasattr(self, '_success_txt'):
@@ -103,13 +112,15 @@ class Scene(DirectObject):
         self._side_panel.destroy()
         self._cursor.destroy()
         taskMgr.remove(self._scene_tsk)
+        if hasattr(self, '_success_txt'):
+            self._success_txt.destroy()
 
     def _set_camera(self):
         base.camera.set_pos(0, -20, 0)
         base.camera.look_at(0, 0, 0)
 
     def __load_img_btn(self, path, col):
-        img = OnscreenImage('assets/buttons/%s.png' % path)
+        img = OnscreenImage('assets/images/buttons/%s.dds' % path)
         img.set_transparency(True)
         img.set_color(col)
         img.detach_node()
@@ -248,7 +259,7 @@ class Scene(DirectObject):
                 getattr(item, method)(pos)
                 img = 'move' if method == 'on_click_l' else 'rotate'
                 if not (img == 'rotate' and not item._instantiated):
-                    self._cursor.set_image('assets/buttons/%s.png' % img)
+                    self._cursor.set_image('assets/images/buttons/%s.dds' % img)
 
     def on_click_l(self):
         self._on_click('on_click_l')
@@ -269,7 +280,7 @@ class Scene(DirectObject):
                 self.__next_btn['frameColor'] = fcols[1]
         self._item_active = None
         [item.on_release() for item in self.items]
-        self._cursor.set_image('assets/buttons/arrowUpLeft.png')
+        self._cursor.set_image('assets/images/buttons/arrowUpLeft.dds')
 
     def repos(self):
         for item in self.items:
@@ -288,6 +299,12 @@ class Scene(DirectObject):
     def on_aspect_ratio_changed(self):
         self.repos()
 
+    def _win_condition(self):
+        pass
+
+    def _fail_condition(self):
+        return all(itm.fail_condition() for itm in self.items) and not self._paused and self._state == 'playing'
+
     def on_frame(self, task):
         hits = self._get_hits()
         pos = None
@@ -306,21 +323,21 @@ class Scene(DirectObject):
             self._item_active.on_mouse_move(pos)
         if self._dbg_items:
             self._update_info(items_hit[0] if items_hit else None)
-        if all(itm.end_condition() for itm in self.items) and not hasattr(self, '_success_txt'):
-            loader.load_sfx('assets/audio/sfx/success.ogg').play()
-            font = base.loader.load_font('assets/fonts/Hanken-Book.ttf')
-            font.clear()
-            font.set_pixels_per_unit(60)
-            font.set_minfilter(Texture.FTLinearMipmapLinear)
-            font.set_outline((0, 0, 0, 1), .8, .2)
-            self._success_txt = OnscreenText(
-                _('You win!'), font=font, scale=0.2, fg=(.9, .9, .9, 1))
+        if self._win_condition():
+            self._set_win()
+        elif self._state == 'playing' and self._fail_condition():
+            self._set_fail()
+        if any(itm._overlapping for itm in self.items):
+            self._cursor.cursor_img.img.set_color(.9, .1, .1, 1)
+        else:
+            self._cursor.cursor_img.img.set_color(.9, .9, .9, 1)
         return task.cont
 
     def cb_inst(self, item):
         self.items += [item]
 
     def on_play(self):
+        self._state = 'playing'
         self.__prev_btn['state'] = DISABLED
         self.__next_btn['state'] = DISABLED
         self.__right_btn['state'] = DISABLED
@@ -353,7 +370,7 @@ class Scene(DirectObject):
         self.__store_state()
         mgr = TextPropertiesManager.get_global_ptr()
         for name in ['mouse_l', 'mouse_r']:
-            graphic = OnscreenImage('assets/buttons/%s.png' % name)
+            graphic = OnscreenImage('assets/images/buttons/%s.dds' % name)
             graphic.set_scale(.5)
             graphic.get_texture().set_minfilter(Texture.FTLinearMipmapLinear)
             graphic.get_texture().set_anisotropic_degree(2)
@@ -399,6 +416,148 @@ class Scene(DirectObject):
             clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
         btn.set_transparency(True)
 
+    def _set_win(self):
+        loader.load_sfx('assets/audio/sfx/success.ogg').play()
+        self._paused = True
+        self.__store_state()
+        frm = DirectFrame(frameColor=(.4, .4, .4, .06),
+                          frameSize=(-.6, .6, -.3, .3))
+        font = base.loader.load_font('assets/fonts/Hanken-Book.ttf')
+        font.clear()
+        font.set_pixels_per_unit(60)
+        font.set_minfilter(Texture.FTLinearMipmapLinear)
+        font.set_outline((0, 0, 0, 1), .8, .2)
+        self._txt = OnscreenText(
+            _('You win!'),
+            parent=frm,
+            font=font, scale=0.2,
+            fg=(.9, .9, .9, 1))
+        u_l = self._txt.textNode.get_upper_left_3d()
+        l_r = self._txt.textNode.get_lower_right_3d()
+        w, h = l_r[0] - u_l[0], u_l[2] - l_r[2]
+        btn_scale = .05
+        mar = .06  # margin
+        z = h / 2 - font.get_line_height() * self._txt['scale'][1]
+        z += (btn_scale + 2 * mar) / 2
+        self._txt['pos'] = 0, z
+        u_l = self._txt.textNode.get_upper_left_3d()
+        l_r = self._txt.textNode.get_lower_right_3d()
+        c_l_r = l_r[0], l_r[1], l_r[2] - 2 * mar - btn_scale
+        fsz = u_l[0] - mar, l_r[0] + mar, c_l_r[2] - mar, u_l[2] + mar
+        frm['frameSize'] = fsz
+        colors = [
+            (.6, .6, .6, 1),  # ready
+            (1, 1, 1, 1), # press
+            (.8, .8, .8, 1), # rollover
+            (.4, .4, .4, .4)]
+        imgs = [self.__load_img_btn('home', col) for col in colors]
+        btn = DirectButton(
+            image=imgs, scale=btn_scale,
+            pos=(-2.8 * btn_scale, 1, l_r[2] - mar - btn_scale),
+            parent=frm, command=self._on_end_home, extraArgs=[frm],
+            relief=FLAT, frameColor=(.6, .6, .6, .08),
+            rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
+            clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
+        btn.set_transparency(True)
+        imgs = [self.__load_img_btn('rewind', col) for col in colors]
+        btn = DirectButton(
+            image=imgs, scale=btn_scale,
+            pos=(0, 1, l_r[2] - mar - btn_scale),
+            parent=frm, command=self._on_restart, extraArgs=[frm],
+            relief=FLAT, frameColor=(.6, .6, .6, .08),
+            rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
+            clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
+        btn.set_transparency(True)
+        scenes = []
+        for _file in glob('pmachines/scenes/*.py'):
+            _fn = _file.replace('.py', '').replace('/', '.')
+            for member in import_module(_fn).__dict__.values():
+                if isclass(member) and issubclass(member, Scene) and \
+                        member != Scene:
+                    scenes += [member]
+        scenes = sorted(scenes, key=lambda elm: elm.sorting)
+        enabled = scenes.index(self.__class__) < len(scenes) - 1
+        if enabled:
+            next_scene = scenes[scenes.index(self.__class__) + 1]
+        else:
+            next_scene = None
+        imgs = [self.__load_img_btn('right', col) for col in colors]
+        btn = DirectButton(
+            image=imgs, scale=btn_scale,
+            pos=(2.8 * btn_scale, 1, l_r[2] - mar - btn_scale),
+            parent=frm, command=self._on_next_scene,
+            extraArgs=[frm, next_scene], relief=FLAT,
+            frameColor=(.6, .6, .6, .08),
+            rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
+            clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
+        btn['state'] = NORMAL if enabled else DISABLED
+        btn.set_transparency(True)
+
+    def _set_fail(self):
+        loader.load_sfx('assets/audio/sfx/success.ogg').play()
+        self._paused = True
+        self.__store_state()
+        frm = DirectFrame(frameColor=(.4, .4, .4, .06),
+                          frameSize=(-.6, .6, -.3, .3))
+        font = base.loader.load_font('assets/fonts/Hanken-Book.ttf')
+        font.clear()
+        font.set_pixels_per_unit(60)
+        font.set_minfilter(Texture.FTLinearMipmapLinear)
+        font.set_outline((0, 0, 0, 1), .8, .2)
+        self._txt = OnscreenText(
+            _('You have failed!'),
+            parent=frm,
+            font=font, scale=0.2,
+            fg=(.9, .9, .9, 1))
+        u_l = self._txt.textNode.get_upper_left_3d()
+        l_r = self._txt.textNode.get_lower_right_3d()
+        w, h = l_r[0] - u_l[0], u_l[2] - l_r[2]
+        btn_scale = .05
+        mar = .06  # margin
+        z = h / 2 - font.get_line_height() * self._txt['scale'][1]
+        z += (btn_scale + 2 * mar) / 2
+        self._txt['pos'] = 0, z
+        u_l = self._txt.textNode.get_upper_left_3d()
+        l_r = self._txt.textNode.get_lower_right_3d()
+        c_l_r = l_r[0], l_r[1], l_r[2] - 2 * mar - btn_scale
+        fsz = u_l[0] - mar, l_r[0] + mar, c_l_r[2] - mar, u_l[2] + mar
+        frm['frameSize'] = fsz
+        colors = [
+            (.6, .6, .6, 1),  # ready
+            (1, 1, 1, 1), # press
+            (.8, .8, .8, 1), # rollover
+            (.4, .4, .4, .4)]
+        imgs = [self.__load_img_btn('home', col) for col in colors]
+        btn = DirectButton(
+            image=imgs, scale=btn_scale,
+            pos=(-2.8 * btn_scale, 1, l_r[2] - mar - btn_scale),
+            parent=frm, command=self._on_end_home, extraArgs=[frm],
+            relief=FLAT, frameColor=(.6, .6, .6, .08),
+            rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
+            clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
+        btn.set_transparency(True)
+        imgs = [self.__load_img_btn('rewind', col) for col in colors]
+        btn = DirectButton(
+            image=imgs, scale=btn_scale,
+            pos=(0, 1, l_r[2] - mar - btn_scale),
+            parent=frm, command=self._on_restart, extraArgs=[frm],
+            relief=FLAT, frameColor=(.6, .6, .6, .08),
+            rolloverSound=loader.load_sfx('assets/audio/sfx/rollover.ogg'),
+            clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
+        btn.set_transparency(True)
+
+    def _on_restart(self, frm):
+        self.__on_close_instructions(frm)
+        self.reset()
+
+    def _on_end_home(self, frm):
+        self.__on_close_instructions(frm)
+        self.on_home()
+
+    def _on_next_scene(self, frm, scene):
+        self.__on_close_instructions(frm)
+        self._reload_cb(scene)
+
     def __store_state(self):
         btns = [
             self.__home_btn, self.__info_btn, self.__right_btn,