Multiple bindings for a single Axis

#1

Hello, I’ve been wondering if it’s possible to bind multiple inputs for a single Axis. Suppose I have bindings to allow the player to move horizontally and vertically. That could be defined like this:

(
    axes: {
        Vertical: Emulated(
            pos: Key(W),
            neg: Key(S)
        ),
        Horizontal: Emulated(
            pos: Key(D),
            neg: Key(A)
        )
    },
    actions: {
        // ...
    }
)

That works fine, but what if I want to also support arrow keys? I would expect to be able to write something like this (maybe not entirely syntactically correct, but it should illustrate the point):

(
    axes: {
        Vertical: Multiple [
            Emulated(
                pos: Key(W),
                neg: Key(S)
            ),
            Emulated(
                pos: Key(Up),
                neg: Key(Down)
            ),
        ],
        Horizontal: Multiple [
            Emulated(
                pos: Key(D),
                neg: Key(A)
            ),
            Emulated(
                pos: Key(Right),
                neg: Key(Left)
            ),
        ],
    },
    actions: {
        // ...
    }
)

Given that Actions seem to support this (you can just stick it in an array), is there a way to do that with Axes?

1 Like
(Azriel Hoh) #2

Currently there isn’t a way to do that.

Would it be sufficient if you had bindings for separate controllers, and check both?

#3

Sorry, I’m not sure if I understand, do you mean doing something like this?

(
    axes: {
        Vertical1: Emulated(
            pos: Key(W),
            neg: Key(S)
        ),
        Vertical2: Emulated(
            pos: Key(Up),
            neg: Key(Down)
        ),
        Horizontal1: Emulated(
            pos: Key(D),
            neg: Key(A)
        ),
        Horizontal2: Emulated(
            pos: Key(Right),
            neg: Key(Left)
        ),
    },
    actions: {
        // ...
    }
)

While that’s certainly an option, it feels like a hack, and it places an additional burden on the rest of the code. Please correct me if I misunderstood :slight_smile:

Would a possible PR which adds support for this be welcome? I’ve been wanting to contribute to Amethyst and I think this might make for a solid beginner entry.

2 Likes
(Azriel Hoh) #4

that’s correct :v:!

hm, one may weigh what the default data model should be / support:

  • would multiple bindings for a single axis be a common use case
  • would it be inconvenient for games that only use a single binding per axis
  • can it be made convenient for both models (single and multiple bindings) – i.e. if it’s forced to be a vector of bindings, then all other games that only use a single binding still have to go through that layer

Personally I wouldn’t really mind; but if you decide to go through with it, perhaps use tinyvec / smallvec with a default backing array size of 1 (or 2).
It would likely break existing API – everyone who uses the single axis binding version needs to adapt to use the multiple binding version, so gotta make sure it’s mentioned in the release post.

2 Likes
#5

I believe there must be a way to support all the use cases reasonably well, perhaps by making better use of Rust’s enums, or just using smallvec, like you say. I imagine it probably will break the existing API, but I think it will be worth it in the long run :slight_smile:

I will try to tinker with it, see what I come up with and report back. No promises though :slight_smile:

Thanks for the replies!

#6

I’d say that it is a very common use case. I have observed lots of games that allow up to two different key bindings per action.

If you add Multiple to the same enum that Emulated is on, I think it can be fully backwards compatible.

1 Like
#7

I have opened a PR which adds Multiple variant to the Axis enum, please let me know what you think :slight_smile: