From 0e86689fc2b39bc7c4af6a7eb3f363d6189e9eeb Mon Sep 17 00:00:00 2001 From: Flavio Calva Date: Fri, 18 Feb 2022 19:41:05 +0100 Subject: [PATCH] domino+box: end condition --- pmachines/items/box.py | 11 ++++---- pmachines/items/domino.py | 22 +++++++++++---- pmachines/items/item.py | 41 ++++++++++++++++++++++++++-- pmachines/scene.py | 5 +++- pmachines/scenes/scene_box.py | 10 +++++-- pmachines/scenes/scene_domino.py | 20 ++++++++++---- pmachines/scenes/scene_domino_box.py | 37 +++++++++++++++++-------- prj.org | 2 +- 8 files changed, 112 insertions(+), 36 deletions(-) diff --git a/pmachines/items/box.py b/pmachines/items/box.py index ad25341..56d6285 100644 --- a/pmachines/items/box.py +++ b/pmachines/items/box.py @@ -11,14 +11,15 @@ class Box(Item): self.node.add_shape(BulletBoxShape((.5, .5, .5))) -class TargetBox(Box): +class HitStrategy: - def __init__(self, world, plane_node, cb_inst, curr_bottom, repos, mass=1, pos=(0, 0, 0), r=0, count=0, hit_by=None): + def __init__(self, hit_by, node, world): self._hit_by = hit_by - super().__init__(world, plane_node, cb_inst, curr_bottom, repos, mass=mass, pos=pos, r=r, count=count) + self._node = node + self._world = world def end_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() + 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: return True diff --git a/pmachines/items/domino.py b/pmachines/items/domino.py index fe07278..c50cb5d 100644 --- a/pmachines/items/domino.py +++ b/pmachines/items/domino.py @@ -1,5 +1,5 @@ from panda3d.bullet import BulletBoxShape, BulletRigidBodyNode, BulletGhostNode -from pmachines.items.item import Item +from pmachines.items.item import Item, StillStrategy class Domino(Item): @@ -11,11 +11,23 @@ class Domino(Item): self.node.add_shape(BulletBoxShape((.1, .25, .5))) -class TargetDomino(Domino): +class UpStrategy(StillStrategy): - def __init__(self, world, plane_node, cb_inst, curr_bottom, repos, mass=1, pos=(0, 0, 0), r=0, count=0, tgt_degrees=0): + def __init__(self, np, tgt_degrees): + super().__init__(np) self._tgt_degrees = tgt_degrees - super().__init__(world, plane_node, cb_inst, curr_bottom, repos, mass=mass, pos=pos, r=r, count=count) + self._np = np def end_condition(self): - return abs(self._np.get_r()) >= self._tgt_degrees + return super().end_condition() and abs(self._np.get_r()) <= self._tgt_degrees + + +class DownStrategy(StillStrategy): + + def __init__(self, np, tgt_degrees): + super().__init__(np) + 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 diff --git a/pmachines/items/item.py b/pmachines/items/item.py index 4e31a43..6562af2 100644 --- a/pmachines/items/item.py +++ b/pmachines/items/item.py @@ -12,6 +12,40 @@ class Command: self.rot = rot +class FixedStrategy: + + def end_condition(self): + return True + + +class StillStrategy: + + def __init__(self, np): + self._np = np + self._positions = [] + self._rotations = [] + + def end_condition(self): + 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) + + class Item: def __init__(self, world, plane_node, cb_inst, curr_bottom, scene_repos, model_path, model_scale=1, exp_num_contacts=1, mass=1, pos=(0, 0, 0), r=0, count=0): @@ -26,6 +60,7 @@ class Item: self._mass = mass self._pos = pos self._r = r + self.strategy = FixedStrategy() self._exp_num_contacts = exp_num_contacts self._curr_bottom = curr_bottom self._scene_repos = scene_repos @@ -69,6 +104,9 @@ class Item: def _set_shape(self): pass + def set_strategy(self, strategy): + self.strategy = strategy + def _repos(self): p_from, p_to = P3dGfxMgr.world_from_to((-1, 1)) for hit in self._world.ray_test_all(p_from, p_to).get_hits(): @@ -261,9 +299,6 @@ class Item: if hasattr(self, '_txt') and not self._txt.is_empty(): self._txt.set_alpha_scale(1) - def end_condition(self): - return True - def destroy(self): self._np.remove_node() taskMgr.remove(self._box_tsk) diff --git a/pmachines/scene.py b/pmachines/scene.py index 8adf4f7..f27e7b4 100644 --- a/pmachines/scene.py +++ b/pmachines/scene.py @@ -295,6 +295,9 @@ class Scene(DirectObject): def on_aspect_ratio_changed(self): self.repos() + def _end_condition(self): + pass + def on_frame(self, task): hits = self._get_hits() pos = None @@ -313,7 +316,7 @@ 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 self._paused: + if self._end_condition(): self._set_end() if any(itm._overlapping for itm in self.items): self._cursor.cursor_img.img.set_color(.9, .1, .1, 1) diff --git a/pmachines/scenes/scene_box.py b/pmachines/scenes/scene_box.py index 9982c77..c7abbc1 100644 --- a/pmachines/scenes/scene_box.py +++ b/pmachines/scenes/scene_box.py @@ -1,7 +1,7 @@ from pmachines.scene import Scene -from pmachines.items.box import Box, TargetBox +from pmachines.items.box import Box, HitStrategy from pmachines.items.shelf import Shelf -from pmachines.items.domino import Domino, TargetDomino +from pmachines.items.domino import Domino from pmachines.items.basketball import Basketball from pmachines.items.teetertooter import TeeterTooter @@ -23,7 +23,8 @@ class SceneBox(Scene): self.items += [Shelf(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, mass=0, pos=(-1.29, 0, .26), r=28.45)] self.items += [Shelf(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, mass=0, pos=(2.15, 0, -1.49), r=28.45)] self.items += [Box(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(-1.55, 0, 1.23))] - self.items += [TargetBox(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(4.38, 0, -3.35), hit_by=self.items[-1])] + self.items += [Box(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(4.38, 0, -3.35))] + self.items[-1].set_strategy(HitStrategy(self.items[-2], self.items[-1].node, self.items[-1]._world)) #self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, count=2)] #self.items += [TargetDomino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(-1.14, 0, -.04), tgt_degrees=60)] #self.items += [TargetDomino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(-.49, 0, -.04), tgt_degrees=60)] @@ -39,3 +40,6 @@ class SceneBox(Scene): txt += _('keep \5mouse_l\5 pressed to drag an item\n\n' '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 diff --git a/pmachines/scenes/scene_domino.py b/pmachines/scenes/scene_domino.py index f682626..3911464 100644 --- a/pmachines/scenes/scene_domino.py +++ b/pmachines/scenes/scene_domino.py @@ -1,7 +1,7 @@ from pmachines.scene import Scene from pmachines.items.box import Box from pmachines.items.shelf import Shelf -from pmachines.items.domino import Domino, TargetDomino +from pmachines.items.domino import Domino, DownStrategy from pmachines.items.basketball import Basketball from pmachines.items.teetertooter import TeeterTooter @@ -21,11 +21,16 @@ class SceneDomino(Scene): self.items += [Shelf(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, mass=0, pos=(-1.2, 0, -.6))] self.items += [Shelf(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, mass=0, pos=(1.2, 0, -.6))] self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, count=2)] - self.items += [TargetDomino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(-1.14, 0, -.04), tgt_degrees=60)] - self.items += [TargetDomino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(-.49, 0, -.04), tgt_degrees=60)] - self.items += [TargetDomino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(0.94, 0, -.04), tgt_degrees=60)] - self.items += [TargetDomino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(1.55, 0, -.04), tgt_degrees=60)] - self.items += [TargetDomino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(2.09, 0, -.04), tgt_degrees=88)] + self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(-1.14, 0, -.04))] + self.items[-1].set_strategy(DownStrategy(self.items[-1]._np, 60)) + self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(-.49, 0, -.04))] + self.items[-1].set_strategy(DownStrategy(self.items[-1]._np, 60)) + self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(0.94, 0, -.04))] + self.items[-1].set_strategy(DownStrategy(self.items[-1]._np, 60)) + self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(1.55, 0, -.04))] + self.items[-1].set_strategy(DownStrategy(self.items[-1]._np, 60)) + self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(2.09, 0, -.04))] + self.items[-1].set_strategy(DownStrategy(self.items[-1]._np, 88)) #self.items += [Basketball(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, count=3)] #self.items += [TeeterTooter(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, count=3)] @@ -35,3 +40,6 @@ class SceneDomino(Scene): txt += _('keep \5mouse_l\5 pressed to drag an item\n\n' '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 diff --git a/pmachines/scenes/scene_domino_box.py b/pmachines/scenes/scene_domino_box.py index 91921c2..663842b 100644 --- a/pmachines/scenes/scene_domino_box.py +++ b/pmachines/scenes/scene_domino_box.py @@ -1,7 +1,7 @@ from pmachines.scene import Scene from pmachines.items.box import Box from pmachines.items.shelf import Shelf -from pmachines.items.domino import Domino, TargetDomino +from pmachines.items.domino import Domino, UpStrategy, DownStrategy from pmachines.items.basketball import Basketball from pmachines.items.teetertooter import TeeterTooter @@ -24,22 +24,35 @@ class SceneDominoBox(Scene): self.items += [Shelf(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, mass=0, pos=(1.67, 0, -1.45))] self.items += [Shelf(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, mass=0, pos=(3.78, 0, -1.45))] #self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, count=9)] - self.items += [TargetDomino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(-.61, 0, -.94), r=37, tgt_degrees=60)] - self.items += [TargetDomino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(-.06, 0, -.89), tgt_degrees=60)] - self.items += [TargetDomino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(0.91, 0, -.89), tgt_degrees=60)] - self.items += [TargetDomino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(1.73, 0, -.89), tgt_degrees=60)] - self.items += [TargetDomino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(2.57, 0, -.89), tgt_degrees=88)] - self.items += [TargetDomino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(-.61, 0, .73), r=37, tgt_degrees=60)] - self.items += [TargetDomino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(-.06, 0, .78), tgt_degrees=60)] - self.items += [TargetDomino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(0.91, 0, .78), tgt_degrees=60)] - self.items += [TargetDomino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(1.73, 0, .78), tgt_degrees=60)] - self.items += [TargetDomino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(2.57, 0, .78), tgt_degrees=88)] + self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(-.61, 0, -.94), r=37)] + self.items[-1].set_strategy(DownStrategy(self.items[-1]._np, 35)) + self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(-.06, 0, -.89))] + self.items[-1].set_strategy(DownStrategy(self.items[-1]._np, 35)) + self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(0.91, 0, -.89))] + self.items[-1].set_strategy(DownStrategy(self.items[-1]._np, 35)) + self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(1.73, 0, -.89))] + self.items[-1].set_strategy(DownStrategy(self.items[-1]._np, 35)) + self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(2.57, 0, -.89))] + self.items[-1].set_strategy(UpStrategy(self.items[-1]._np, 30)) + self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(-.61, 0, .73), r=37)] + self.items[-1].set_strategy(DownStrategy(self.items[-1]._np, 35)) + self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(-.06, 0, .78))] + self.items[-1].set_strategy(DownStrategy(self.items[-1]._np, 35)) + self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(0.91, 0, .78))] + self.items[-1].set_strategy(DownStrategy(self.items[-1]._np, 35)) + self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(1.73, 0, .78))] + self.items[-1].set_strategy(UpStrategy(self.items[-1]._np, 30)) + self.items += [Domino(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, pos=(2.57, 0, .78))] + self.items[-1].set_strategy(UpStrategy(self.items[-1]._np, 30)) #self.items += [Basketball(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, count=3)] #self.items += [TeeterTooter(self._world, self._mouse_plane_node, self.cb_inst, self.current_bottom, self.repos, count=3)] def _instr_txt(self): txt = _('Scene: ') + self.name() + '\n\n' - txt += _('Goal: at least one domino piece per row must be up\n\n') + txt += _('Goal: only the last piece of each row must be up\n\n') txt += _('keep \5mouse_l\5 pressed to drag an item\n\n' '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 diff --git a/prj.org b/prj.org index 0397aaa..b00180a 100644 --- a/prj.org +++ b/prj.org @@ -1,6 +1,6 @@ * issues * todo -** level domino + box: end condition +** first levels: fail condition - you fail! (every item in the screen is still) ** level basketball ** level domino + box + basketball ** level teetertooter -- 2.30.2