Providing Input on… Input

When I’m looking at the Babylon.js forum or checking out feedback on YouTube videos, I often see comments asking about making games. They tend to range from “How do I add X feature to my game?” to “You should make a Babylon.js game engine!” While our community uses Babylon.js for many a different kind of project, those comments about games always stick out to me.

When I first started learning to code, it was because I wanted to learn how to make a game. My big dream, growing up, was to make games and game technology. I’ve made several little games here and there throughout my life, on an assortment of game engines (and even a few from scratch). On just about every project that I’ve done, I’ve always found that two biggest issues for me were graphics/animation and user input.

For Game Graphics, I’ve resigned to the fact that I’m not that good at art and that’s perfectly fine. I can always purchase assets or hire someone to make things for me. User Input is a different animal entirely…

Image for post
Image for post
An accurate representation of my skill level and feelings toward art that I make.

User Input is often viewed as a big part of what’s known as Player Agency. Player Agency is the idea that, as a player, you can provide input and make choices that will influence the game world and have some kind of consequence. It’s this idea that let’s the player interact with the world created for them. For video games, all choices and influences come from some kind of input from a device. This device can be as simple as a joystick to move and a button to jump or as complex as a flight simulator.

Image for post
Image for post
Photo by ThisisEngineering RAEng on Unsplash

The biggest issues I had, as a kid, when setting up the input for games wasn’t getting something to happen when a button was pressed but getting that something to happen and not have some crazy reaction like the character disappearing into the horizon. It was either that or having two buttons fighting to see who’s input is recognized. Fortunately, input systems have gotten easier to work with and abstracted away most of the boilerplate code that was required in the past.

Let’s fast forward to this year, shall we? The Babylon team has been looking into ways to get input to work such that the same calls on the JS side work with the Native side. I decided to take this opportunity to see what could be done about it and learn more about Babylon’s current input systems.

Image for post
Image for post
Photo by blurrystock on Unsplash

Whenever I’d need to do something with key presses in a Playground, I’d often just add an event listener for the desired key and go from there. The funny thing about event listeners is that if you want to change the action done for the event, you need to manually remove the old event listener and replace it with a new one. Otherwise, you’d be doing both actions at the same time.

So the next thing that I did was to look into the camera’s input manager. With a simple function call, it will set up some controls to maneuver around the scene. The way that it accomplished this was to hide some of those event listener calls behind attachControl and detachControl functions. You could even override those functions to add more customization.

// Example that you've probably seen in the Playground
camera.attachControl(canvas, true);

This may work for keyboards and mice but what if the user wanted to use an Xbox or Dual Shock controller? That takes us to the next manager, the GamepadManager. As I dove into the GamepadManager, I noticed that the only events it worked with were when a device is connected and when a device is disconnected. Everything else is done by “polling”. Polling is when a function will ask what input it’s receiving from a device. Polling is a method of handling input that you’ll find in many different game engines like Unity, Unreal, and Godot. If I had to compare listening for events and polling, I’d equate event listening to getting a knock on the door with the UPS driver dropping off a package where as polling is more like refreshing the Tracking page and knowing exactly where your package is.

Image for post
Image for post
Photo by 🇨🇭 Claudio Schwarz | @purzlbaum on Unsplash

The GamepadManager handles input by first looking for when a device is connected. When one is, the code can now provide context for what a specific input means on a specific device.

gamepadManager.onGamepadConnectedObservable.add((gamepad, state)=>{     // If this is a 360 gamepad, do something on a button press     if (gamepad instanceof BABYLON.Xbox360Pad) {          //Xbox button down observable          gamepad.onButtonDownObservable.add((button, state)=>{               // Do Something          });
}
});

During my time looking into all of these, I’ve noticed that all of the methods of input have one issue. They all use some form of DOM-based referencing. The DOM, or Document Object Model, is a way of describing the structure of HTML and XML documents. While this is great for the web, it doesn’t directly translate to the Native side, at least without a lot of work.

If you consider the above, combined with the fact that our input systems are broken down into at least two different, unrelated systems, it makes handling input from various sources a bit difficult. I had an idea though…

Why can’t we create a system that abstracts out the DOM code and treats keyboards, mice, and gamepads in the exact same way? Furthermore, if we can streamline the abstraction for the user, they won’t have to rely on boilerplate code to fill in the gaps.

Well, as it turns out, we intend to do just that. We’re currently working on an abstracted input system to join all inputs together under one roof, make it easier to add inputs to your scenes, and even bring that functionality to the Native side. The way I picture it looking is something like this:

Image for post
Image for post
A basic layout for how I plan on the new input system working, designed in my expertly crafted art style.

As you can see, the Device Input System (tentative name) serves as a sort of central hub for joining inputs from various API’s and sources. All inputs at this level will be organized and treated the same. The next level up will handle keeping track of devices and provide a specific context to each connected device. The Input Profile level will go a step further and allow the user to abstract a specific input into a device agnostic name like “Fire” so that inputs can be organized and swapped when desired. While this input system is still very much a work in progress, we’re incredibly excited about what it will mean for all of the Babylon game developers out there!

If this interests you, feel free to stop on by the forums for more updates and even provide some input on what kind of features you’d like to see.

Written by

Babylon.js: Powerful, Beautiful, Simple, Open — Web-Based 3D At Its Best. https://www.babylonjs.com/

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store