diff --git a/examples/moving_dot.py b/examples/moving_dot.py new file mode 100644 index 0000000..8b72913 --- /dev/null +++ b/examples/moving_dot.py @@ -0,0 +1,93 @@ +"""Minimal example of a non-agent dynamic artist moving between two fixed points.""" + +import gamms +from gamms.VisualizationEngine import Color, Shape +from gamms.VisualizationEngine.artist import Artist +from gamms.typing import ArtistType, IContext + + +START_POINT = (-8.0, 0.0) +END_POINT = (8.0, 0.0) +VIS_KWARGS = {} + + +def draw_moving_dot(ctx: IContext, data: dict): + start_x, start_y = data["start"] + end_x, end_y = data["end"] + alpha = data.get("_alpha") + + x = (1.0 - alpha) * start_x + alpha * end_x + y = (1.0 - alpha) * start_y + alpha * end_y + + ctx.visual.render_circle( + x, + y, + data.get("radius", 0.9), + data.get("color", Color.Red), + ) + + +def draw_path_line(ctx: IContext, data: dict): + start_x, start_y = data["start"] + end_x, end_y = data["end"] + ctx.visual.render_line( + start_x, + start_y, + end_x, + end_y, + data.get("path_color", Color.LightGray), + width=data.get("width", 2), + ) + + +def add_anchor(ctx: IContext, name: str, x: float, y: float, color): + anchor = Artist(ctx, Shape.Circle, 5) + anchor.data["x"] = x + anchor.data["y"] = y + anchor.data["radius"] = 0.6 + anchor.data["color"] = color + anchor.set_artist_type(ArtistType.STATIC) + ctx.visual.add_artist(name, anchor) + return anchor + + +def add_path_line(ctx: IContext, name: str, start: tuple[float, float], end: tuple[float, float]): + path = Artist(ctx, draw_path_line, 15) + path.data["start"] = start + path.data["end"] = end + path.data["path_color"] = Color.LightGray + path.data["width"] = 2 + path.set_artist_type(ArtistType.STATIC) + ctx.visual.add_artist(name, path) + return path + + +def main() -> None: + ctx = gamms.create_context( + vis_engine=gamms.visual.Engine.PYGAME, + vis_kwargs=VIS_KWARGS, + ) + + add_anchor(ctx, "start_anchor", START_POINT[0], START_POINT[1], Color.Blue) + add_anchor(ctx, "end_anchor", END_POINT[0], END_POINT[1], Color.Green) + add_path_line(ctx, "moving_dot_path", START_POINT, END_POINT) + + moving_dot = Artist(ctx, draw_moving_dot, 20) + moving_dot.set_artist_type(ArtistType.DYNAMIC) + moving_dot.data["start"] = START_POINT + moving_dot.data["end"] = END_POINT + moving_dot.data["radius"] = 0.9 + moving_dot.data["color"] = Color.Red + moving_dot.data["path_color"] = Color.LightGray + ctx.visual.add_artist("moving_dot", moving_dot) + + while not ctx.is_terminated(): + ctx.visual.simulate() + moving_dot.data["start"], moving_dot.data["end"] = moving_dot.data["end"], moving_dot.data["start"] + + ctx.terminate() + + +if __name__ == "__main__": + main() + diff --git a/gamms/VisualizationEngine/__init__.py b/gamms/VisualizationEngine/__init__.py index 9adce9c..10f03e2 100644 --- a/gamms/VisualizationEngine/__init__.py +++ b/gamms/VisualizationEngine/__init__.py @@ -49,7 +49,11 @@ def lazy(fullname: str): module = importlib.util.module_from_spec(spec) loader = importlib.util.LazyLoader(spec.loader) # Make module with proper locking and get it inserted into sys.modules. - sys.modules[fullname] = module + try: + # Issues with newer versions of Python + sys.modules[fullname] = module + except: + pass loader.exec_module(module) return module diff --git a/gamms/VisualizationEngine/pygame_engine.py b/gamms/VisualizationEngine/pygame_engine.py index 7a3f351..ce87936 100644 --- a/gamms/VisualizationEngine/pygame_engine.py +++ b/gamms/VisualizationEngine/pygame_engine.py @@ -322,8 +322,8 @@ def handle_tick(self): self._simulation_time += self._clock.get_time() / 1000 alpha = self._simulation_time / self._sim_time_constant alpha = self._pygame.math.clamp(alpha, 0, 1) - for agent_artist in self._iter_agent_artists(): - agent_artist.data['_alpha'] = alpha + for artist in self._dynamic_artists.values(): + artist.data['_alpha'] = alpha def handle_single_draw(self): self._screen.fill(Color.White) @@ -532,8 +532,9 @@ def _get_agent_artist(self, agent_name: str) -> IArtist: def _toggle_waiting_simulation(self, waiting_simulation: bool): self._waiting_simulation = waiting_simulation for agent_artist in self._iter_agent_artists(): - agent_artist.data['_alpha'] = 0.0 agent_artist.data['_waiting_simulation'] = waiting_simulation + for artist in self._dynamic_artists.values(): + artist.data['_alpha'] = 0.0 def _toggle_waiting_user_input(self, waiting_user_input: bool): self._waiting_user_input = waiting_user_input