Universal Axis Input (I'm dumb)

I was dumb, and was printing lots of stuff each frame. Oops

Howdy guys, here’s a challenge for you.

I want to have a function that takes a single input in the form of a dictionary:


player_axis_dict = {'command_name':[[control_name, sensitivity, deadzone], [control_name, sensitivity, deadzone]]}

#Example:
player_axis_dict = {
        'throttle':[['MOUSEX', 5.3, 0.01], ['JOY1AXIS0', 2.3, 0.01]]
        'yaw':[['MOUSEY', 3.6, 0.01], ['JOY1AXIS1', 1.4, 0.01]]

As an output, it must be the command name followed by a value between -1 and 1:


{'throttle':0.5, 'yaw':0}

The value is calculated by something like:


axis_value = raw_value*sensitivity #raw value is also between zero and 1
if abs(axis_value) <= deadzone:
    value = 0
axis_value =  max(-1, min(1, value))

I started off with the mouse, and wrote some code that accomplished this. I then ran it through the profiler, and discovered it was eating 4% logic, with spikes up to 7% If I add joystick on top of this, it’ll be way to heavy.

So how can I make this more efficient?
Here’s the relevant code:


def get_input(cont):
    global all_input
    ..... stuff with buttons ...
    axis_input = get_axis_input(player_axis_dict)

def get_axis_input(axis_dict):
    input_values = get_axis_values()
    axis_values = {}
    for axis in axis_dict:
        #Deadzone and sensitivity:
        axis_inf = axis_dict[axis]
        name, sens, deadzone = axis_inf
            
        raw_value = input_values.get(name, 0)
        value = input_values.get(name, 0)*sens
        if abs(value) <= deadzone:
            value = 0
        axis_values[axis] =  max(-1, min(1, value))
    return axis_values

def get_axis_values():
    '''Returns a dictionary of {'axisname':offset}'''
    axis_dict = {}
    #Mouse Input
    mouse_values = get_mouse_axis()
    axis_dict['MOUSEX'] = mouse_values[0]
    axis_dict['MOUSEY'] = mouse_values[1]
    
    #Joystick Input
    ....nothing yet...
    return axis_dict




def get_mouse_axis():
    pos = bge.logic.mouse.position
    x = round(pos[0]-0.5, 3)
    y = round(pos[1]-0.5, 3)
    bge.logic.mouse.position = (0.5, 0.5)
    return [x,y]

How can I improve this?

For bonus points, how can I do joystick? I haven’t had a look at it yet though, so you don’t have to answer.

I was dumb, and was printing lots of stuff each frame. Oops

have it check the mouse offset less often and interpolate the time step?

Indeed printing eats a lot of processing power.

Another way to improve this is to trigger the code only on relevant changes (e.g. with a mouse movement sensor, joystick sensor). Luckily the joystick sensor has an “All Events” option and the keyboard sensor has an “All Keys” option. Unfortunately the mouse sensor is missing that.

Currently you check all axis:


for axis in axis_dict:

if you check the changed axis only … you save processing time (see above).

Even with that the code does not look heavy (means it should be pretty fast).

Another way to improve this is to trigger the code only on relevant changes (e.g. with a mouse movement sensor, joystick sensor). Luckily the joystick sensor has an “All Events” option and the keyboard sensor has an “All Keys” option. Unfortunately the mouse sensor is missing that.

Hmm, I’m not sure if this helps or just makes this-code-induced slowdowns only noticeable sometimes. Guess it’s a matter of preference which is better as well. With something like input, I’d rather it was consistent in how much processor it eats.

Currently you check all axis:

Axis dict is exactly six ‘axis’ big

Even with that the code does not look heavy (means it should be pretty fast).

That’s why I was surprised that it was eating 4%. It now eats only 2%, though when I add a whole heap of buttons on top of that, it get’s back up to 4%. A quick test with all six axis and sixteen buttons, input processing eats maybe 5-6% processing power. I’m hoping that the entire player (including animated dashboard) will consume no more than ~10% logic.
Hmm, I’ve just thought of an optimization for another part of my code… Yup, 1% logic gone.

6% logic just for some input mapping is pretty much (depends on the ms you get). If there is not much other going on, it should be fine.