Spaces:
Paused
Paused
| # Copyright (c) Meta Platforms, Inc. and affiliates. | |
| # This source code is licensed under the MIT license found in the | |
| # LICENSE file in the root directory of this source tree. | |
| """ Controller Abstract Base Class Module """ | |
| from __future__ import annotations | |
| from typing import Optional | |
| from abc import abstractmethod | |
| import logging | |
| from animated_drawings.model.scene import Scene | |
| from animated_drawings.view.view import View | |
| from animated_drawings.config import ControllerConfig | |
| class Controller(): | |
| """ | |
| Base Controller class from which all other Controllers will be derived. | |
| Controllers are responsible for: | |
| - running the game loop. | |
| - handling user input and forwarding it to the view or scene. | |
| - triggering the scene's update method | |
| - trigger the view's render method | |
| """ | |
| def __init__(self, cfg: ControllerConfig, scene: Scene) -> None: | |
| self.cfg: ControllerConfig = cfg | |
| self.scene: Scene = scene | |
| self.view: Optional[View] = None | |
| def set_scene(self, scene: Scene) -> None: | |
| """ Sets the scene attached to this controller.""" | |
| self.scene = scene | |
| def set_view(self, view: View) -> None: | |
| """ Sets the view attached to this controller.""" | |
| self.view = view | |
| def _tick(self) -> None: | |
| """Subclass and add logic is necessary to progress time""" | |
| def _update(self) -> None: | |
| """Subclass and add logic is necessary to update scene after progressing time""" | |
| def _is_run_over(self) -> bool: | |
| """Subclass and add logic is necessary to end the scene""" | |
| def _start_run_loop_iteration(self) -> None: | |
| """Subclass and add code to start run loop iteration""" | |
| def _handle_user_input(self) -> None: | |
| """Subclass and add code to handle user input""" | |
| def _render(self) -> None: | |
| """Subclass and add logic needed to have viewer render the scene""" | |
| def _finish_run_loop_iteration(self) -> None: | |
| """Subclass and add steps necessary before starting next iteration of run loop. """ | |
| def _prep_for_run_loop(self) -> None: | |
| """Subclass and add anything necessary to do immediately prior to run loop. """ | |
| def _cleanup_after_run_loop(self) -> None: | |
| """Subclass and add anything necessary to do after run loop has finished. """ | |
| def run(self) -> None: | |
| """ The run loop. Subclassed controllers should overload and define functionality for each step in this function.""" | |
| self._prep_for_run_loop() | |
| while not self._is_run_over(): | |
| self._start_run_loop_iteration() | |
| self._update() | |
| self._render() | |
| self._tick() | |
| self._handle_user_input() | |
| self._finish_run_loop_iteration() | |
| self._cleanup_after_run_loop() | |
| def create_controller(controller_cfg: ControllerConfig, scene: Scene, view: View) -> Controller: | |
| """ Takes in a controller dictionary from mvc config file, scene, and view. Constructs and return appropriate controller.""" | |
| if controller_cfg.mode == 'video_render': | |
| from animated_drawings.controller.video_render_controller import VideoRenderController | |
| return VideoRenderController(controller_cfg, scene, view,) | |
| elif controller_cfg.mode == 'interactive': | |
| from animated_drawings.controller.interactive_controller import InteractiveController | |
| from animated_drawings.view.window_view import WindowView | |
| assert isinstance(view, WindowView) # for static analysis. checks elsewhere ensure this always passes | |
| return InteractiveController(controller_cfg, scene, view) | |
| else: | |
| msg = f'Unknown controller mode specified: {controller_cfg.mode}' | |
| logging.critical(msg) | |
| assert False, msg | |