Key Bindings as functions

So the idea is to use functions when you want to check the state of a key, so instead of doing:

UPBGE:


ACTIVE = bge.logic.KX_INPUT_ACTIVE
W_KEY = bge.logic.keyboard.inputs[bge.events.WKEY].status[0] == ACTIVE
if W_KEY: #MyAction

BGE:


ACTIVE = bge.logic.KX_INPUT_ACTIVE
W_KEY = bge.logic.keyboard.events[bge.events.WKEY] == ACTIVE
if W_KEY: #MyAction

You do:


self.forward = keyBind(bge.events.WKEY)
  # ...
if self.forward(): #MyAction

I’ve already implemented it my addon and to my surprise it is even more powerful than I though (say yes to heigher order functions). Now you can use logic bricks to configure components game keys, or you can send fake keys to a specific script.

Here you have more details of how you can use it: http://coredoc.royalwebhosting.net/api/event.html#key-bindings

The implementation of this system in your project (without the addon or UPBGE) is trivial. All you need to do is add this piece of code:

UPBGE:


def keyPress(key):
    return bge.logic.keyboard.inputs[key].status[0] == bge.logic.KX_INPUT_ACTIVE

def keyBind(key):
    def keyAction():
        return bge.logic.keyboard.inputs[key].status[0] == bge.logic.KX_INPUT_ACTIVE
        
    return keyAction

BGE:


def keyPress(key):
    return bge.logic.keyboard.events[key] == bge.logic.KX_INPUT_ACTIVE

def keyBind(key):
    def keyAction():
        return bge.logic.keyboard.events[key] == bge.logic.KX_INPUT_ACTIVE
        
    return keyAction

And that’s it. It’s so trivial that you could even do it by accident. I hope you enjoy this system, I’ll surely do.

Yup, you can make these things a lot simpler for specific use cases. One of my favourites is:


MAPPING = {  # Uses strings so it can easily be loaded from files
    'forward':'WKEY',
    'backward':'SKEY',
    'shoot':'EKEY',
}

held = bge.logic.KX_INPUT_ACTIVE
tapped = bge.logic.KX_INPUT_JUST_ACTIVATED
released = bge.logic.KX_INPUT_JUST_RELEASED

def get_key(action):
    keyname = MAPPING(action)
    keycode = bge.events.__dict__(keyname)
    return bge.logic.keyboard.events[keycode]



if action_state('forward') is held:
    do_things
if action_state('shoot') is tapped:
    do_other_things

# You can also do:
if action_state('forward'):
    do_things
# Because inactive is 0.....

I also have a similar function somewhere where the get_key is more general and also does mouse/joystick buttons.

On a side note, I spend the whole day today writing a system similar to javascripts DOM event handler in BGE python so I can make user interfaces really easy. It is quite a nice system, just got a few more things to finish up…
I’ve spent a lot of time writing input handlers, and would enjoy chatting about the design of this one. I’ll just have to make some documentation…

I’ve recently become a big fan of the callback approach for (amongst other things) some uses of input handling, and would be interested to know if you have a good method for registering callbacks? I have yet to make a nice callback meta-management system

1 Like

@sdfgeoff


from core import event
from bge import events, logic

[...]

com = object.components[n]

#Changing a key for another
com.forward = event.keyBind(events.UPARROWKEY)

#Disabling a key
com.forward = lambda: False

#Any of two keys
com.forward = lambda: event.keyPress(events.UPARROWKEY) or event.keyPress(events.UKEY)

#The default key or another:
default = com.forward
com.forward = lambda: default() or event.keyPress(events.UPARROWKEY)

#Two keys at the same time:
com.forward = lambda: event.keyPress(events.UPARROWKEY) and event.keyPress(events.UKEY)

#Joystick
com.forward =  lambda: max(logic.joysticks[0].axisValues[1], 0)
com.backward = lambda: min(logic.joysticks[0].axisValues[1], 0)

#An external event
myevents["forward"] = True
[...]
com.forward = lambda: myevents["forward"]

#Another external event, a game property
com.forward = lambda: obj["forward"]

#This one even lets us use logic bricks to configure keys, for example doing:
#[Keyboard] -> [And] -> [Property: Mode(Level), Property("forward")]

Have you looked at this? What my method is caplable of and what yours is is completly diferent, to the point I feel I maybe gone a little overboard since with my method you can even make a key be pressed with a random sequence, like:

com.forward = lambda: bge.logic.getRandomFloat()

As for managing callbacks… I don’t see the problem there. Just create a list:


callbacks = []

def fun1(x): print("I'm callback 1 with arg", x)
def fun2(x): print("I'm callback 2 with arg", x)

callbacks.append(fun1)
callbacks.append(fun2)

for n in callbacks: n(x) #Where x is something.

callbacks.remove(fun1)
callbacks.remove(fun2)

The only problem there is that you can’t use lambdas, since you don’t have a reference to remove it.
To solve that you can replace the list with a dict and that would be it. You would need to put a
name to each entry tough.