KeyPresserator
Hello, loves!
Let’s move on_key_press out of DungeonView. Down to 146 lines, from 226 just a few commits ago.
I think I’ll just do it unless something interesting comes up. Here it is going in:
def on_key_press(self, symbol: int, modifiers: int) -> bool | None:
if self.key_lock is not None:
return
self.key_lock = symbol
if symbol == arcade.key.RIGHT:
self.move_player(Direction.EAST)
elif symbol == arcade.key.LEFT:
self.move_player(Direction.WEST)
elif symbol == arcade.key.UP:
self.move_player(Direction.NORTH)
elif symbol == arcade.key.DOWN:
self.move_player(Direction.SOUTH)
elif symbol == arcade.key.F:
self.dungeon.maker_flood()
elif symbol == arcade.key.B and (modifiers & arcade.key.MOD_CTRL):
message = 'You have been eaten by a breakpoint!'
self.pub_sub.publish('announce', 'view', message=message)
pass
elif symbol == arcade.key.H:
self.dungeon.make_initial_announcement()
elif symbol == arcade.key.K:
self.dungeon.show_path_to('a red key', self)
else:
self.key_lock = None
def on_key_release(self, symbol: int, modifiers: int) -> bool | None:
if symbol == self.key_lock:
self.key_lock = None
Basically if a key is down, we ignore any other keys. When a key goes down, we dispatch and do stuff. The new object would like to be started with a DungeonView, and let’s pass in the dungeon, in case we want to do something cute with testing.
I’ll just replicate that in a class, instantiate it, and forward to it. Or, wait, how can we arrange that it gets the key-presses its own self? That will take a bit of research, we’ll stick with plan A.
class DungeonView(arcade.View):
def __init__(self, dungeon, testing=False):
if not testing:
super().__init__()
self.dungeon = dungeon
self.pub_sub = dungeon.pub_sub
self.subscribe(dungeon, self.pub_sub)
self.setup_assets()
self.keyed_floor_sprites = KeyedSpriteList(arcade.SpriteList())
self.content_views: dict[Content, ContentView] = dict()
self.content_views_by_cell: dict[Cell, list[ContentView]] = defaultdict(list)
self.content_sprite_list = None
self.cameras = None
self.keys = KeyPress(self, self.dungeon, self.pub_sub)
def on_key_press(self, symbol: int, modifiers: int) -> bool | None:
self.keys.on_key_press(symbol, modifiers)
def on_key_release(self, symbol: int, modifiers: int) -> bool | None:
self.keys.on_key_release(symbol, modifiers)
class KeyPress:
def __init__(self, view, dungeon, pub_sub):
self.view = view
self.dungeon = dungeon
self.pub_sub = pub_sub
self.key_lock = None
def on_key_press(self, symbol: int, modifiers: int) -> bool | None:
if self.key_lock is not None:
return
self.key_lock = (symbol, modifiers)
if symbol == arcade.key.RIGHT:
self.view.move_player(Direction.EAST)
elif symbol == arcade.key.LEFT:
self.view.move_player(Direction.WEST)
elif symbol == arcade.key.UP:
self.view.move_player(Direction.NORTH)
elif symbol == arcade.key.DOWN:
self.view.move_player(Direction.SOUTH)
elif symbol == arcade.key.F:
self.dungeon.maker_flood()
elif symbol == arcade.key.B and (modifiers & arcade.key.MOD_CTRL):
message = 'You have been eaten by a breakpoint!'
self.pub_sub.publish('announce', 'view', message=message)
pass
elif symbol == arcade.key.H:
self.dungeon.make_initial_announcement()
elif symbol == arcade.key.K:
self.dungeon.show_path_to('a red key', self.view)
else:
self.key_lock = None
def on_key_release(self, symbol: int, modifiers: int) -> bool | None:
if (symbol, modifiers) == self.key_lock:
self.key_lock = None
This seems to work just fine. Commit: moved on_key_press to KeyPress object.
A bit of research finds that this incantation tells me whether there is an active window, so that tests can deal with KeyPress (and DungeonView) without creating a window.
class KeyPress(arcade.View):
def __init__(self, view, dungeon, pub_sub):
if arcade.window_commands._window:
super().__init__()
self.view = view
self.dungeon = dungeon
self.pub_sub = pub_sub
self.key_lock = None
I thought this would allow me to remove the on_key_press and on_key_release methods from DungeonView. Further research tells me that only the active view receives key presses. so we’ll need to leave the forwarding in. No biggie. Reset.
Summary
So that went swimmingly, which I think means “well”, and the better check for whether there is a window is useful. I’ve updated the calling sequence for DungeonView and its creators. DungeonView is down to a positively healthy 156 lines, from 226 just a few sessions ago. I think we can do better. Possibly we will.
Down to 146: removed unused draw_passages, which doesn’t work as constituted anyway.
See you next time!