Spaces:
Building
Building
# 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 | |