Enhanced Input: Adding Input Action at Runtime?

A quick question: it’s possible to add input actions in an active Mapping Context at runtime?

Don’t think so, but you can have a mapping context that is just the new action you want. think that’s the intended use. You can have as many mapping context as needed.

1 Like

Thank you for the advice. It seems reasonable and I’ll give it a try.

My use case: player receives new abilities depending on the combat progress. I’ve seen similar approach in the Batman Arkham series, in which player receives a screen message saying that a new combo is available, for instance X+X+Y, for a very short time window. I was wondering how to implement such feature with Enhanced Input. Let’s say, a new ability is granted to the player unlocking a custom input (chorded actions), or grant all abilities and inputs on Begin play and unlock based on meeting specific conditions.

Why not have a map with the moves (can be an enum holding all moves cast to an int) then as a value just have a bool parameter.
Then check this map if to execute a movement. If the bool is true => do the move sequence, else ignore.

Dynamic binding could be done in c++ if I remember correctly.

Perhaps GAS might with with dynamic abilities.

1 Like

It’s a good point, thank you. I’ll have a look at this option too.
I wanted to use GAS and dynamic assignment with Lyra Starter Game.
I’ll see if I can find anything related to that.

DynBindCharacter.h (2.7 KB)
DynBindCharacter.cpp (6.4 KB)

Dynamic binding and unbinding of input action.
If you would want full dynamic binding to be more flexible then you can extract the UInputAction as a pass in variable for the function. You would probably need to change the function bind to a string then.

Updated version where you can pass in the input


void ADynBindCharacter::ModifyCombo(UInputAction * Action, bool AddInput,  FName FunctionName){ 
	if (EnhancedInputC) {
		if (AddInput) {			
			EnhancedInputC->BindAction(Action, ETriggerEvent::Started, this, FunctionName);
		}
		else {
			FInputActionValue IAV = EnhancedInputC->GetBoundActionValue(Action);

			for (int i = 0; i < EnhancedInputC->GetActionEventBindings().Num(); i++) {
				const UInputAction* CurrentAction = EnhancedInputC->GetActionEventBindings()[i].Get()->GetAction();

				if (CurrentAction == Action) {
					EnhancedInputC->RemoveBindingByHandle(EnhancedInputC->GetActionEventBindings()[i].Get()->GetHandle());					
					break;
				}
			}
		}
	}
}

Ok got it working. Just pass in the function name. If you are calling from blueprint then the target function needs to be blueprint callable.

2 Likes

Thank you for helping me with this code. I’ll give it a try later this week.

Follow up

Split out the functions to add and remove with specific trigger events

void ADynBindCharacter::AddCombo(UInputAction * Action, ETriggerEvent Event,  FName FunctionName){ //FunctionDelegate functor,
	if (EnhancedInputC) {		
		EnhancedInputC->BindAction(Action, Event, this, FunctionName);
	}
}

void ADynBindCharacter::RemoveCombo(UInputAction* Action, ETriggerEvent Event)
{
	FInputActionValue IAV = EnhancedInputC->GetBoundActionValue(Action);

	for (int i = 0; i < EnhancedInputC->GetActionEventBindings().Num(); i++) {
		const UInputAction* CurrentAction = EnhancedInputC->GetActionEventBindings()[i].Get()->GetAction();

		if (CurrentAction == Action && Event == EnhancedInputC->GetActionEventBindings()[i].Get()->GetTriggerEvent()) 
		{
			EnhancedInputC->RemoveBindingByHandle(EnhancedInputC->GetActionEventBindings()[i].Get()->GetHandle());
			break;
		}
	}
}

1 Like

This is fantastic, thank you. I am wondering if this setup can be used as “Ability Slot” as well. Let’s say, I have three generic Input Actions, Abilit1, Abilit2 and Ability3. I am thinking in using this setup to swap input actions (In Lyra will be linked to an input tag) and trigger different abilities.

Only downside that I haven’t overcome is that I can’t enforce a function name check for the unbind function. I can specify the specific action and event.

Also the function is limited to inside the character atm. If you’d want to call a function on another actor then you would need to change the “this” in the bindAction function (pass in a UObject in the function call for another target). All depends on the amount of elasticity required by the function.

Noted, thank you.
I’ll give it a try with the Lyra Character class from Lyra. I’ll have to check during runtime how the input events can affect the desired feature. Thank you so much.