Link to download projects: https://drive.google.com/uc?export=download&id=1QfuQEx8xPXwONcBgyfs3ASN-UZhBnJVO

OVERVIEW

This project is encapsulating the current user Input project and make more useful functions to help user use keyboard input more easily.
It will be pretty easy to use if the user has used Unreal Engine before, because the interface I created is referencing UE4 C++.

SET UP PROJECTS

Users need to import two projects I have created so that they can use my project. One is called “Advanced User Input” under the Engine category, which has all code bases. The another one is called “Input Builder” under the Tool category. Add dependencies, references.

STEP 1: Setup data. Users need to create an input sheet looks like the following image and put it under MyGame_->Content->Inputs

Input builder will read this file and create a binary version of it. Like the following image:

First two bytes are the size of Action Mappings and the size of Axis Mappings. The type is uint_8. The highlight part “20 00 00 00” is the binary format of KeyCodes::eKeyCodes. It represents Space in this enum.

In MyGame_->Content->AssetsToBuild.lua, add:

In AssetsBuildLibary-> AssetBuildFunctions.lua, add:

Just like when adding effect, geometry.

SETP 2: Setup AdvancedUserInput handle.

User needs to include the “.h” file first.

#include "Engine/AdvancedUserInput/AdvancedUserInput.h"

User can declare this handle as global variable or member variable in my game class.

eae6320::UserInput::AdvancedUserInput::Handle s_UserInput;

Load Input in eae6320::cMyGame::Initialize():

eae6320::UserInput::AdvancedUserInput::s_manager.Load("data/inputs/defaultinput.input", s_UserInput);

Update the handle in eae6320::cMyGame::UpdateBasedOnInput(). This function is handling all core input events, so it should be ticked.

UserInput::AdvancedUserInput::s_manager.Get(s_UserInput)->UpdateInput();

STEP 3: Bind input with functions

There are two type of bindings: ActionBinding and AxisBinding.

ActionBinding has three type of input events:

  • OnRelease
  • OnHold
  • OnPress

The function that it binds should be a function without argument and returns void.
It can be a member function or global / static function.
For example, please check the following image with the input data on the previous page.

It demonstrates how to use ActionBinding. “Jump” is connected to [space], “Interact” is connected to [E] according to the input sheet.
So, when player presses space, OnReleaseEvent / OnHoldEvent / MemberFunction will be called depends on different “IT_On…” (IT stands for Input Type).

AxisBinding doesn’t have different type of input event. The function it binds should be a function with a float argument and returns void.
It can be a member function or global / static function.

For example, “MoveRight” is connected with “A” as negative key and “D” as positive key. If the negative key is pressed, the float argument will be -1. On the opposite, it will be 1. If there is no key being pressed, the argument will be 0 but the bound function will always be called.

Here is the reference for those bound functions:
Static / Global function:

Member function:

CHALLENGES

The most struggling part I have met was wring the template code of my delegate class, especially when I wrote the member function delegate. Maybe I am wrong, the intellisense will not show what is wrong as usual when you are using template.

This is the quick overview of the member function delegate. It has two typename <T, …ParamType>. Here is the link to the detail explanation of parameter pack: https://en.cppreference.com/w/cpp/language/parameter_pack

T is the class of function, …ParamType is the argument type, it can be none, or multiple. Originally, I wanted to create a multi-arguments delegate but that will require my binding class to be a template class too, so I decided not to do that.

This is the source code of BindAxis(cosnt char*, T*, void(T::*i_func)(float))
It shows how to create a member function delegate. The basic idea is that it passes in a function pointer, and store it in the delegate handler. The delegate handler will execute it when the binding key / keys are pressed / released / held.

Another struggling part is about if I should convert my input sheet into binary file and load it on run-time.

The initial idea of having an input sheet is that player can change their input key according to their favors. But when I convert it to the binary file, player can not read-write those files.

Then I think I can use UserSettings to read user preference by creating another human-readable input sheet and overwriting the default one. I ended up decided not to do that because it was complex to insert this overwriting part into my code.

I needed to write some change binding function to help achieve this overwritten, but I did not have time any more.