Hey folks and @Rene-Damm
(Using Unity 2019.3.2f1 and Input System: preview.6 - 1.0.0)
in the last couple of days I spent lots of time on structuring my Inputhandling with the new input system and although there are apparently still some bugs here and there generally I’m very happy with the whole input system and how fast and easy I can setup different maps and actions, well done. Looking forward to future versions of this
But, let’s tackle a problem I have. I can’t pinpoint if this is something I have to deal with on my end or if this maybe even a bug and/or missing feature. So here it goes:
I have a control scheme, called PC_Scheme. This PC_Scheme has a bunch of ActionMaps. My idea is:
Only one action map can be active at a time. So I have a dedicated InputHandler class responsible for handling this with a Stack
Then I have so called InputBehaviours which implement the generated interfaces of the respective InputActionMap. For example this one:
public class PlayerEntityDialogueInputBehaviour : MonoBehaviour,
IInputBehaviour,
TestInputActions.IPlayerDialogue_MapActions
{
[SerializeField]
private PlayerEntityDialogueInput playerEntityDialogueInput = new PlayerEntityDialogueInput();
private PlayerEntityInputRegistrator playerEntityInputRegistrator;
public void InitInputRegistrator(AGameInputRegistrator gameInputRegistrator)
{
playerEntityInputRegistrator = (PlayerEntityInputRegistrator) gameInputRegistrator;
}
public void RegisterInputCallbacks()
{
playerEntityInputRegistrator.GameInputActions.PlayerDialogue_Map.SetCallbacks(this);
}
public void StartInputBehaviour()
{
playerEntityDialogueInput.OnStart(playerEntityInputRegistrator.PlayerEntity);
}
public void OnProgressDialogue(InputAction.CallbackContext context)
{
playerEntityDialogueInput.OnProgressDialogue(context);
}
public void OnEnterMainMenu(InputAction.CallbackContext context)
{
playerEntityDialogueInput.OnEnterMainMenu(context);
}
}
When specific conditions are met, like when the Player hits a key in front of an object to inspect it this is what happens:
- The current active actionmap (Peek in stack) gets disabled
- the new actionMap gets pushed and enabled
In this case, when the inspection is done/the dialogue is over this happens:
- The current active actionmap gets disabled
- The current active actionmap gets popped
- The peek in stack (which was the previous active map) gets enabled again
This works pretty great so far. There is only one tiny problem:
(For clarification, I’m using a Keyboard as a device to describe the problem)
Let’s assume the game is running and and the so called “PlayerGeneral_Map” is the active actionmap. This map allows for movement and different kinds of interactions with objects, entering the mainmenu and starting the pause screen and so on.
For now I’m using WASD and the ArrowKeys for movement. In order to interact with Objects in the scene I have to hit the “SPACE”-Key
Let’s say I hit and HOLD the “D”-Key in order to move to the right, since there is an object of interest.
Entering the Trigger of the Object I hit the “D”-key. In this very frame I STILL HOLD the “D”-Key.
Now the PlayerGeneralMap gets disabled and the PlayerDialogueMap is active. A Dialogue pops up and I have to hit the “SPACE”-Key again in order to progress the dialogue. Once done the PlayerGeneralMap gets activated once again. I STILL hold the “D”-Key but the player doesn’t move, which implies the Callback doesn’t get called. I have to release my finger from the key and hit it again in order to move again.
The Movement callback looks like this:
protected internal void OnMovement(InputAction.CallbackContext context)
{
Log.Info($"Is Action Enabled: {context.action.actionMap.enabled}");
Vector2 input;
switch (context.phase)
{
case InputActionPhase.Started:
break;
case InputActionPhase.Performed:
input = context.ReadValue<Vector2>();
SetPlayerDestination(input);
break;
case InputActionPhase.Canceled:
input = Vector2.zero;
SetPlayerDestination(input);
break;
case InputActionPhase.Disabled:
Log.Info("Movement is disabled");
break;
}
}
My desired behaviour is:
While holding the “D”-key once the DialogeMap gets disabled and the GeneralMap gets enabled the input gets basically picked up again.
What’s interesting, the moment I hit the “SPACE”-Key in the object of interest while holding the movement key the value of .enabled of the actionmap is still true. When I debug that and go through the stacktrace the code does traverse all the necessary steps:
InputActionMap.Disable()
InputActionState.DisableAllActions()
InputActionState.ResetActionState()
[…]
PlayerEntityMovement.OnMovement()
So .enabled being still true is kind of weird and InputActionPhase.Disabled in my OnMovement never gets called, the log is never printed. But InputActionState.DisableAllActions implies the phase should be called:
for (var i = 0; i < actionCount; ++i)
{
var actionIndex = actionStartIndex + i;
if (actionStates[actionIndex].phase != InputActionPhase.Disabled)
ResetActionState(actionIndex, toPhase: InputActionPhase.Disabled);
}
But in InputActionState.ResetActionState apparently the phase goes directly to “Canceled”?:
else
{
// No interactions. Cancel the action directly.
Debug.Assert(actionState->bindingIndex != kInvalidIndex, "Binding index on trigger state is invalid");
Debug.Assert(bindingStates[actionState->bindingIndex].interactionCount == 0,
"Action has been triggered but apparently not from an interaction yet there's interactions on the binding that got triggered?!?");
ChangePhaseOfAction(InputActionPhase.Canceled, ref actionStates[actionIndex]);
}
So my questions are basically:
-
Do I have to change my code to get the desired behaviour, like saving the last input I got before getting disabled? If so: How should I do that? I can’t trust the Cancel-Phase, since the phase is also called when I lift my finger from the keys and not only when I disable the current active map. I guess in order for this to better work it would great if there would be Eventcallbacks for Enabling/Disabling ActionMaps (and Controlschemes while we’re at it
)
-
If this is something I can do without changing my code but through Interactions or Processors in the InputAsset itself, how has the setup to look like?