def test_scene_change_thrashing(): class ChildScene(BaseScene): count = 0 def on_update(self, event, signal): print(f"Child") self.running = False class ParentScene(BaseScene): count = 0 fired = False def on_update(self, event, signal): if not self.fired: self.next = ChildScene self.fired = True else: self.count += 1 print(f"Parent {self.count}") if self.count >= 5: self.running = False def fail(engine): try: parent = engine.scenes[0] except IndexError: return False if parent.count > 0 and engine.current_scene != parent: return True engine = GameEngine(ParentScene, systems=[Updater(time_step=0.001), Failer], fail=fail, message="ParentScene should not be counting while a child exists.") engine.run()
def test_engine_initial_scene(): mock_scene = mock.Mock(spec=BaseScene) mock_scene.background_color = (0, 0, 0) mock_scene_class = mock.Mock(spec=BaseScene, return_value=mock_scene) engine = GameEngine(mock_scene_class) engine.start() assert engine.current_scene is mock_scene
def __init__(self, *, engine: GameEngine, inputs: Iterable[SoftwareInputs], key_config: dict = None, **kwargs): """ Initialize the controller subsystem. It is advised that you do not initialize this subsystem outside of the engine. :param engine: The game engine this will be used in. Required. :param inputs: An iterable of Axis, Switch, or Impulse objects. :param key_config: A dictionary of string names and key or button values. :param kwargs: Additional kwargs, required in ppb Systems. """ super().__init__(inputs=inputs, key_config=key_config, **kwargs) self.__values = {} self.__inputs = {} self.__key_config = key_config or {} for i in inputs: self.add(i) engine.register(events.Update, self.extend_update)
def test_free(clean_assets): free_called = False class Const(Asset): def background_parse(self, data): return "yoink" def free(self, obj): nonlocal free_called free_called = True a = Const('ppb/utils.py') engine = GameEngine( AssetTestScene, basic_systems=[AssetLoadingSystem, Failer], fail=lambda e: False, message=None, run_time=1, ) with engine: engine.start() assert a.load() == "yoink" # At this poiint, background processing should have finished del engine, a # Clean up everything that might be holding a reference. gc.collect() assert free_called
def setUp(self): self.mock_scene = mock.Mock(spec=BaseScene) self.mock_scene.background_color = (0, 0, 0) self.mock_scene_class = mock.Mock(return_value=self.mock_scene) self.engine = GameEngine(self.mock_scene_class) self.engine.display = mock.Mock(spec=Surface) self.engine.start()
def test_contexts(): class FakeRenderer(System): def __init__(self, **kwargs): self.entered = False self.exited = False def __enter__(self): self.entered = True def __exit__(self, exc_type, exc_val, exc_tb): self.exited = True engine = GameEngine(Scene, basic_systems=[FakeRenderer, Quitter, Failer], message="Will only time out.", fail=lambda x: False) engine.run() for system in engine.children._systems: if isinstance(system, FakeRenderer): break else: system = None assert isinstance(system, FakeRenderer) assert system.entered assert system.exited
def test_loading(): a = Asset('ppb/engine.py') engine = GameEngine(BaseScene, basic_systems=[AssetLoadingSystem]) with engine: engine.start() assert a.load()
def test_start(self): mock_scene = mock.Mock(spec=BaseScene) mock_scene.background_color = (0, 0, 0) mock_scene_class = mock.Mock(spec=BaseScene, return_value=mock_scene) engine = GameEngine(mock_scene_class) engine.display = mock.Mock(spec=Surface) engine.start() self.assertIs(engine.current_scene, mock_scene)
def test_missing_package(): a = Asset('does/not/exist') engine = GameEngine(BaseScene, basic_systems=[AssetLoadingSystem]) with engine: engine.start() with pytest.raises(FileNotFoundError): assert a.load()
def test_missing_resource(): a = Asset('ppb/dont.touch.this') engine = GameEngine(BaseScene, basic_systems=[AssetLoadingSystem]) with engine: engine.start() with pytest.raises(FileNotFoundError): assert a.load()
def test_signal(): engine = GameEngine(Scene, basic_systems=[Quitter, Failer], message=None, fail=lambda x: False) engine.run() assert not engine.running
def test_parsing(): class Const(Asset): def background_parse(self, data): return "nah" a = Const('ppb/flags.py') engine = GameEngine(BaseScene, basic_systems=[AssetLoadingSystem]) with engine: engine.start() assert a.load() == "nah"
def test_missing_package(clean_assets): a = Asset('does/not/exist') engine = GameEngine( AssetTestScene, basic_systems=[AssetLoadingSystem, Failer], fail=lambda e: False, message=None, run_time=1, ) with engine: engine.start() with pytest.raises(FileNotFoundError): assert a.load()
def test_missing_resource(clean_assets): a = Asset('ppb/dont.touch.this') engine = GameEngine( AssetTestScene, basic_systems=[AssetLoadingSystem, Failer], fail=lambda e: False, message=None, run_time=1, ) with engine: engine.start() with pytest.raises(FileNotFoundError): assert a.load()
def test_missing_parse(): class Const(Asset): def file_missing(self): return "igotu" a = Const('spam/eggs') engine = GameEngine(BaseScene, basic_systems=[AssetLoadingSystem]) with engine: engine.start() assert a.load() == "igotu"
def test_parsing(clean_assets): class Const(Asset): def background_parse(self, data): return "nah" a = Const('ppb/flags.py') engine = GameEngine( AssetTestScene, basic_systems=[AssetLoadingSystem, Failer], fail=lambda e: False, message=None, run_time=1, ) with engine: engine.start() assert a.load() == "nah"
def test_missing_parse(clean_assets): class Const(Asset): def file_missing(self): return "igotu" a = Const('spam/eggs') engine = GameEngine( AssetTestScene, basic_systems=[AssetLoadingSystem, Failer], fail=lambda e: False, message=None, run_time=1, ) with engine: engine.start() assert a.load() == "igotu"
class TestEngineSceneActivate(unittest.TestCase): def setUp(self): self.mock_scene = mock.Mock(spec=BaseScene) self.mock_scene_class = mock.Mock(return_value=self.mock_scene) self.engine = GameEngine(self.mock_scene_class) self.engine.start() def test_continue_running(self): """ Test that a Scene.change that returns (False, {}) doesn't change state. """ self.mock_scene.change = mock.Mock(return_value=(CONTINUE, {})) self.engine.manage_scene(*self.engine.current_scene.change()) self.assertIs(self.engine.current_scene, self.mock_scene) def test_stop_scene_no_new_scene(self): """ Test a Scene.change that returns (True, {}) leaves the scene stack empty. """ self.mock_scene.change = mock.Mock(return_value=(STOP, {})) self.engine.manage_scene(*self.engine.current_scene.change()) self.assertIsNone(self.engine.current_scene) def test_next_scene_none(self): self.mock_scene.change = mock.Mock(return_value=(CONTINUE, { "scene_class": None })) self.engine.manage_scene(*self.engine.current_scene.change()) self.assertIs(self.engine.current_scene, self.mock_scene)
class TestEngineSceneActivate(unittest.TestCase): def setUp(self): self.mock_scene = mock.Mock(spec=BaseScene) self.mock_scene.background_color = (0, 0, 0) self.mock_scene_class = mock.Mock(return_value=self.mock_scene) self.engine = GameEngine(self.mock_scene_class) self.engine.display = mock.Mock(spec=Surface) self.engine.start() def test_continue_running(self): """ Test that a Scene.change that returns (True, {}) doesn't change state. """ self.mock_scene.change = mock.Mock(return_value=(CONTINUE, {})) self.engine.manage_scene() self.assertIs(self.engine.current_scene, self.mock_scene) def test_stop_scene_no_new_scene(self): """ Test a Scene.change that returns (False, {}) leaves the scene stack empty. """ self.mock_scene.change = mock.Mock(return_value=(STOP, {})) self.engine.manage_scene() self.assertIsNone(self.engine.current_scene) def test_next_scene_none(self): self.mock_scene.change = mock.Mock(return_value=(CONTINUE, {"scene_class": None} ) ) self.engine.manage_scene() self.assertIs(self.engine.current_scene, self.mock_scene)
def test_replace_scene_event(): class FirstScene(BaseScene): def on_update(self, event, signal): signal(events.ReplaceScene(new_scene=SecondScene())) def on_scene_stopped(self, event, signal): assert event.scene is self class SecondScene(BaseScene): def on_scene_started(self, event, signal): assert event.scene is self class TestFailer(Failer): def __init__(self, engine): super().__init__(fail=self.fail, message="Will not call", engine=engine) self.first_scene_ended = False def on_scene_stopped(self, event, signal): if isinstance(event.scene, FirstScene): self.first_scene_ended = True def fail(self, engine) -> bool: if self.first_scene_ended: assert len(engine.scenes) == 1, "Too many scenes on stack." assert isinstance(engine.current_scene, SecondScene), "Wrong current scene." engine.signal(events.Quit()) return False with GameEngine(FirstScene, basic_systems=[Updater, TestFailer]) as ge: ge.run()
def test_game_engine_with_scene_class(): props = {"background_color": (69, 69, 69), "show_cursor": False} with GameEngine(Scene, basic_systems=[Quitter], scene_kwargs=props) as ge: ge.run() assert ge.current_scene.background_color == props["background_color"] assert ge.current_scene.show_cursor == props["show_cursor"]
def test_tree(): """Tests deep trees""" call_count = 0 class TestSystem(System): def __init__(self, **props): super().__init__(**props) o = Agent() self.add(o) for _ in range(5): c = Agent() o.add(c) o = c def on_idle(self, event: events.Idle, signal): nonlocal call_count call_count += 1 signal(events.Quit()) class Agent(GameObject): def on_idle(self, event: events.Idle, signal): nonlocal call_count call_count += 1 with GameEngine(Scene, basic_systems=[Failer], systems=[TestSystem], fail=lambda x: False, message="Can only time out.") as ge: ge.run() assert call_count == 7
def test_target_events(): class Test: pass call_count = 0 class Targetted(GameObject): def on_test(self, event, signal): nonlocal call_count call_count += 1 class Untargetted(GameObject): def on_test(self, event, signal): assert False target = Targetted() def setup(scene): scene.add(target) scene.add(Untargetted()) with GameEngine(setup, basic_systems=[Failer], systems=[], fail=lambda x: False, message="Can only time out.") as ge: ge.signal(Test(), targets=[target]) ge.signal(events.Quit()) ge.run() assert call_count == 1
def test_event_extension(): @dataclasses.dataclass class TestEvent: pass class TestSystem(System): def __init__(self, *, engine, **_): super().__init__(engine=engine, **_) engine.register(TestEvent, self.event_extension) def on_update(self, event, signal): signal(TestEvent()) signal(events.Quit()) def on_test_event(self, event, signal): assert event.test_value == "Red" def event_extension(self, event): event.test_value = "Red" with GameEngine(BaseScene, basic_systems=[TestSystem, Updater, Failer], message="Will only time out.", fail=lambda x: False) as ge: ge.run()
def test_game_engine_with_instantiated_scene(): scene = Scene() with GameEngine(scene, basic_systems=[Quitter]) as ge: ge.run() assert ge.current_scene == scene
def test_flush_events(): ge = GameEngine(BaseScene) ge.signal(events.SceneStopped()) ge.signal(events.Quit()) assert len(ge.events) == 2 ge.flush_events() assert len(ge.events) == 0
def test_scene_change_no_new(): class Scene(BaseScene): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.running = False def change(self): return super().change() failer = Failer(fail=lambda n: False, message="Will only time out.") with GameEngine(Scene, systems=[Updater, failer]) as ge: ge.run()
def test_signal_once(): engine = GameEngine(BaseScene, basic_systems=[Quitter]) with engine: engine.start() engine.loop_once() assert not engine.running
def test_idle(): """This test confirms that Idle events work.""" was_called = False class TestSystem(System): def on_idle(self, event: events.Idle, signal): global was_called was_called = True signal(events.Quit()) with GameEngine(BaseScene, systems=[TestSystem, Failer], fail=lambda x: False, message="Can only time out.") as ge: ge.run()
def test_contexts(): class FakeRenderer(System): def __init__(self, **kwargs): self.entered = False self.exited = False def __enter__(self): self.entered = True def __exit__(self, exc_type, exc_val, exc_tb): self.exited = True engine = GameEngine(BaseScene, basic_systems=[FakeRenderer, Quitter]) engine.run() for system in engine.systems: if isinstance(system, FakeRenderer): break else: system = None assert isinstance(system, FakeRenderer) assert system.entered assert system.exited
def test_contexts(): class FakeRenderer(System): def __init__(self, **kwargs): self.entered = False self.exited = False def __enter__(self): self.entered = True def __exit__(self, exc_type, exc_val, exc_tb): self.exited = True engine = GameEngine(BaseScene, systems=[FakeRenderer, Quitter]) engine.run() for system in engine.systems: if isinstance(system, FakeRenderer): break else: system = None assert isinstance(system, FakeRenderer) assert system.entered assert system.exited
def test_signal_once(): engine = GameEngine(Scene, basic_systems=[Quitter, Failer], message=None, fail=lambda x: False) with engine: engine.start() engine.loop_once() assert not engine.running
from ppb import GameEngine from ppb.systems import Updater, Renderer, PygameEventPoller, PygameMouseSystem from creeps.scenes import MainScene from creeps.systems import BehaviorSystem ge = GameEngine(MainScene, systems=(Updater, BehaviorSystem, Renderer, PygameEventPoller, PygameMouseSystem), scene_kwargs={"background_color": (25, 100, 50)} ) with ge: ge.run()
def test_signal(): engine = GameEngine(BaseScene, systems=[Quitter]) engine.run() assert not engine.running
def test_extending_all_events(): def all_extension(event): event.test_value = "pursuedpybear" @dataclasses.dataclass class TestEvent: pass class TestScene(BaseScene): def on_update(self, event, signal): assert event.test_value == "pursuedpybear" def on_mouse_motion(self, event, signal): assert event.test_value == "pursuedpybear" def on_test_event(self, event, signal): assert event.test_value == "pursuedpybear" ge = GameEngine(TestScene) ge.start() # We need test scene instantiated. ge.register(..., all_extension) ge.signal(events.Update(0.01)) ge.publish() ge.signal(events.MouseMotion(Vector(0, 0), Vector(0, 0), Vector(0, 1), [])) ge.publish() ge.signal(TestEvent()) ge.publish()