2017-11-08 19:46:56

Hello all,
I'm posting this since I've looked on Google and on Pygame's IRC channel and haven't gotten anything useful out of it.
I have a game in Python 3.x using Pygame. The game has a map editor and with it, my idea is that you could define characteristics of the room (i.e. adding, modifying, destroying, ...) with it using simple keypresses, I.e. to set the rooms reverb you'd press s, then r, then r, then 1 (since the reverb has two values: reverb, and reverb2 (reverb depth)). I've tried the following:

  • Checking if s, r, r, and 1 were pressed in one while loop (doesn't work because you can't check if the same key was pressed twice in a single if block);

  • Changing the second r to e so then you'd need to press s, r, e, and 1 (doesn't work because you have to hold them down, which is incredibly difficult);

  • Creating a function chain, so you press s, it calls a function, r calls another function, and e calls another, then 1 and 2 call another (gets way too complicated really, really fast, and puts way more stress on me when updating the editor later; also causes code bloat); and

  • Creating an event loop and a key loop which:

    • Polls the Pygame event queue every iteration, and

    • Calls pygame.key.get_pressed() each iteration.

The fourth one is desirable because, while it seems over-complicated, it gives me more control over the keyboard. Here's what I'm trying to do:

  • Determine if either 'A', 'S', or 'D' are pressed (K_a, K_s, or K_d).

  • Somehow, if, after A, S, or D are released, determine if another key is pressed.

  • Perform an action.

If anyone has any ideas on the simplest way to do this, please let me know on this topic. I'm getting really confused by it, and the last thing I want to do is create a command interpreter that all users (even newbies) have to use to create maps (where you have to type, say, 'srr1 100' or 'srr2 13000'). Most people would think that's way too technical, and I don't want any confusion for newbies. At the same time, I don't want to have to come up with billions of key combinations to modify the map.

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.
My Github

2017-11-08 21:18:06

Why can't you use menus again?

2017-11-08 21:30:29

Why do you think? The key for map creation, at least for this editor, is to be quick and efficient. Having menus means finding the same item over and over again, and I don't want to have to use menu boiler plate code just to bind keyboard shortcuts to menus.

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.
My Github

2017-11-08 21:35:57

I would create a function for when a key is pressed, and when a key is released. You might want to track which keys are down, but how would depend on how many you'd want to track and why. There would be one or more variables to track the program's current state—what screen or sub-command you're on, etc. The event handler functions would either take care of the response directly via if-else chains, or delegate to other functions as needed.
So, for you're example, say we have 3 variables: screen/mode (ex, EDITING), what command, menu, etc is active on top of that (ex, REVERB), and subcommand, which would be an integer for which step in the process of the main command you're on. This could get more complex with more complex action-trees, but the basic idea still applies.

So, for instance:

def key_pressed (k):
    if flags[k] : return # don't rapid-press a held key.
    flags[k]=True
    if screen==EDITING :
        if command == REVERB : reverb_keys (k)
        elif command == WAITING : command_check(k)
        # etc
    # (other screens go here)

def command_check (k) :
    if k=="s" command=REVERB
    # etc

def reverb_keys (k) :
    if subcommand==0 and k==KEY_R : set_reverb_1("r")
    elif subcommand==2 and k==KEY_A : reverb_2(a)
    # etc, etc


If you'd rather catch things on key release, put the corresponding parts in key_released instead
Also, if you're using flags like the above, be sure to update them on key release as well.

In summary: when you're using an event-based system like pygame, your program is probably better off being structured in terms of states and events rather than loops within loops. Pygame is a bit weird in that it allows you to mix both approaches, but as you've demonstrated, they don't mix well.

看過來!
"If you want utopia but reality gives you Lovecraft, you don't give up, you carve your utopia out of the corpses of dead gods."
MaxAngor wrote:
    George... Don't do that.

2017-11-08 22:09:25 (edited by Ethin 2017-11-08 22:14:18)

@4, thanks. Just curious: would this be simpler with pyglet?
[edit]: Nevermind. I may have ome up with a solution to this problem -- gotta test it though.[/edit

"On two occasions I have been asked [by members of Parliament!]: 'Pray, Mr. Babbage, if you put into the machine wrong figures, will the right answers come out ?' I am not able rightly to apprehend the kind of confusion of ideas that could provoke such a question."    — Charles Babbage.
My Github