ya2 · news · projects · code · about

fail condition
authorFlavio Calva <f.calva@gmail.com>
Mon, 28 Feb 2022 18:38:15 +0000 (19:38 +0100)
committerFlavio Calva <f.calva@gmail.com>
Mon, 28 Feb 2022 18:38:15 +0000 (19:38 +0100)
pmachines/items/box.py
pmachines/items/domino.py
pmachines/items/item.py
pmachines/scene.py
pmachines/scenes/scene_box.py
pmachines/scenes/scene_domino.py
pmachines/scenes/scene_domino_box.py
prj.org

index 56d6285f32d60fed7a4d3554e7cedd88440d5aa9..e9a33c0aee7e334f5f20098484a6c47f0e15e986 100644 (file)
@@ -18,7 +18,7 @@ class HitStrategy:
         self._node = node
         self._world = world
 
-    def end_condition(self):
+    def win_condition(self):
         for contact in self._world.contact_test(self._node).get_contacts():
             other = contact.get_node1() if contact.get_node0() == self._node else contact.get_node0()
             if other == self._hit_by.node:
index c50cb5d645c0f71eb033fe40ee306b25a5b57286..d43e73c68164345cc25094ac108347d9af37a032 100644 (file)
@@ -18,8 +18,8 @@ class UpStrategy(StillStrategy):
         self._tgt_degrees = tgt_degrees
         self._np = np
 
-    def end_condition(self):
-        return super().end_condition() and abs(self._np.get_r()) <= self._tgt_degrees
+    def win_condition(self):
+        return super().win_condition() and abs(self._np.get_r()) <= self._tgt_degrees
 
 
 class DownStrategy(StillStrategy):
@@ -29,5 +29,5 @@ class DownStrategy(StillStrategy):
         self._tgt_degrees = tgt_degrees
         self._np = np
 
-    def end_condition(self):
-        return super().end_condition() and abs(self._np.get_r()) >= self._tgt_degrees
+    def win_condition(self):
+        return self._np.get_z() < -10 or super().win_condition() and abs(self._np.get_r()) >= self._tgt_degrees
index 6562af21a45070603b56472ad3cef39512604297..38a5d960012dbe8ed875095564a56f6f1eaacb55 100644 (file)
@@ -14,7 +14,7 @@ class Command:
 
 class FixedStrategy:
 
-    def end_condition(self):
+    def win_condition(self):
         return True
 
 
@@ -25,7 +25,7 @@ class StillStrategy:
         self._positions = []
         self._rotations = []
 
-    def end_condition(self):
+    def win_condition(self):
         self._positions += [self._np.get_pos()]
         self._rotations += [self._np.get_hpr()]
         if len(self._positions) > 10:
@@ -68,6 +68,8 @@ class Item:
         self._model_path = model_path
         self._commands = []
         self._command_idx = -1
+        self._positions = []
+        self._rotations = []
         if count:
             self.node = BulletGhostNode(self.__class__.__name__)
         else:
@@ -299,6 +301,28 @@ class Item:
         if hasattr(self, '_txt') and not self._txt.is_empty():
             self._txt.set_alpha_scale(1)
 
+    def fail_condition(self):
+        if self._np.get_z() < -10:
+            return True
+        self._positions += [self._np.get_pos()]
+        self._rotations += [self._np.get_hpr()]
+        if len(self._positions) > 10:
+            self._positions.pop(0)
+        if len(self._rotations) > 10:
+            self._rotations.pop(0)
+        if len(self._positions) < 8:
+            return
+        avg_x = sum(pos.x for pos in self._positions) / len(self._positions)
+        avg_y = sum(pos.y for pos in self._positions) / len(self._positions)
+        avg_z = sum(pos.z for pos in self._positions) / len(self._positions)
+        avg_h = sum(rot.x for rot in self._rotations) / len(self._rotations)
+        avg_p = sum(rot.y for rot in self._rotations) / len(self._rotations)
+        avg_r = sum(rot.z for rot in self._rotations) / len(self._rotations)
+        avg_pos = Point3(avg_x, avg_y, avg_z)
+        avg_rot = Point3(avg_h, avg_p, avg_r)
+        return all((pos - avg_pos).length() < .1 for pos in self._positions) and \
+            all((rot - avg_rot).length() < 1 for rot in self._rotations)
+
     def destroy(self):
         self._np.remove_node()
         taskMgr.remove(self._box_tsk)
index f27e7b43c927698052aeee943a7e1a2c6996dcac..4f9410496e2d761124b4d35cc9280030e829c9e8 100644 (file)
@@ -34,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:
@@ -91,6 +92,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'):
@@ -295,9 +297,12 @@ class Scene(DirectObject):
     def on_aspect_ratio_changed(self):
         self.repos()
 
-    def _end_condition(self):
+    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
@@ -316,8 +321,10 @@ 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 self._end_condition():
-            self._set_end()
+        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:
@@ -328,6 +335,7 @@ class Scene(DirectObject):
         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
@@ -406,7 +414,7 @@ class Scene(DirectObject):
             clickSound=loader.load_sfx('assets/audio/sfx/click.ogg'))
         btn.set_transparency(True)
 
-    def _set_end(self):
+    def _set_win(self):
         loader.load_sfx('assets/audio/sfx/success.ogg').play()
         self._paused = True
         self.__store_state()
@@ -483,6 +491,59 @@ class Scene(DirectObject):
         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()
index c7abbc1e4fff1ddfe1a663885a3bac91e2794082..e928b8dbd839dff6d4f53c250090f18257938199 100644 (file)
@@ -41,5 +41,5 @@ class SceneBox(Scene):
                 'keep \5mouse_r\5 pressed to rotate an item')
         return txt
 
-    def _end_condition(self):
-        return all(itm.strategy.end_condition() for itm in self.items) and not self._paused
+    def _win_condition(self):
+        return all(itm.strategy.win_condition() for itm in self.items) and not self._paused
index 3911464fd7bae22cedd6c3d33e161a3afb0cc2ea..b06b4b5611349d20951e44baf648688d97db1c04 100644 (file)
@@ -41,5 +41,5 @@ class SceneDomino(Scene):
                 'keep \5mouse_r\5 pressed to rotate an item')
         return txt
 
-    def _end_condition(self):
-        return all(itm.strategy.end_condition() for itm in self.items) and not self._paused
+    def _win_condition(self):
+        return all(itm.strategy.win_condition() for itm in self.items) and not self._paused
index 663842b61dc23b8a1b19dcd9337276fa362faba9..2d162eb9e4a95fe42267f985a972bd29dcf2b263 100644 (file)
@@ -54,5 +54,5 @@ class SceneDominoBox(Scene):
                 'keep \5mouse_r\5 pressed to rotate an item')
         return txt
 
-    def _end_condition(self):
-        return all(itm.strategy.end_condition() for itm in self.items) and not self._paused
+    def _win_condition(self):
+        return all(itm.strategy.win_condition() for itm in self.items) and not self._paused
diff --git a/prj.org b/prj.org
index b00180ab2985d0a2185c2ef8fe2044222f61ba7c..11826f91222145d8111be72cf72adede4bfe7af1 100644 (file)
--- a/prj.org
+++ b/prj.org
@@ -1,6 +1,5 @@
 * issues
 * todo
-** first levels: fail condition - you fail! (every item in the screen is still)
 ** level basketball
 ** level domino + box + basketball
 ** level teetertooter