I'm attempting to create a roguelike using Python3 and curses. I've got everything displaying the way I want it to, but I've come across a strange bug in the code. There is a 1 key stroke delay in processing the commands. So, assuming traditional roguelike commands, pressing "k" should move you 1 square to the right. The first time you press it, it does nothing. The second time, it will move. If you then press "g", you don't move back to the left, instead the 2nd "k" gets processed and the "g" ends up "on deck". Here's the loop that's supposed to be processing the moves.
def main_loop(self):
#This will catch and handle all keystrokes. Not too happy with if,elif,elif or case. Use a dict lookup eventually
while 1:
self.render_all()
c = self.main.getch()
try:
self.keybindings[c]["function"](**self.keybindings[c]["args"])
except KeyError:
continue
And here is the dictionary lookup I promised myself I'd use in that comment
self.keybindings = {ord("h"): {"function":self.move_object,
"args":{"thing":self.things[0], "direction":"North"}},
ord('j'): {"function":self.move_object,
"args":{"thing":self.things[0], "direction":"South"}},
ord('g'): {"function":self.move_object,
"args":{"thing":self.things[0], "direction":"West"}},
ord('k'): {"function":self.move_object,
"args":{"thing":self.things[0], "direction":"East"}},
ord('y'): {"function":self.move_object,
"args":{"thing":self.things[0], "direction":"NorthWest"}},
ord('u'): {"function":self.move_object,
"args":{"thing":self.things[0], "direction":"NorthEast"}},
ord('b'): {"function":self.move_object,
"args":{"thing":self.things[0], "direction":"SouthWest"}},
ord('n'): {"function":self.move_object,
"args":{"thing":self.things[0], "direction":"SouthEast"}},
ord('l'): {"function":self.look, "args":{"origin_thing":self.things[0],}},
ord('q'): {"function":self.save_game,
"args":{"placeholder":0}}}
Finally, here is the move_object function that's supposed to be called:
def move_object(self, thing, direction):
"""I chose to let the Game class handle redraws instead of objects.
I did this because it will make it easier should I ever attempt to rewrite
this with libtcod, pygcurses, or even some sort of browser-based thing.
Display is cleanly separated from obects and map data.
Objects use the variable name "thing" to avoid namespace collision."""
curx = thing.x
cury = thing.y
newy = thing.y + directions[direction][0]
newx = thing.x + directions[direction][1]
if not self.is_blocked(newx, newy):
logging.info("Not blocked")
thing.x = newx
thing.y = newy
I found the problem and it wasn't in the code I posted. It was inside my render_all() function. I needed to add call to the window's refresh() function after making the changes I was making. I must say, I really don't like curses!