Forum rules - please read before posting.

A more seamless integration with the new Unity Input System... With some issues.

[Unity 2019.4.13f1 - AC v1.72.3]

Hi Chris!

I am working on a more seamless integration with the new Unity Input System and, although I know AC does not officially support it yet, I was wondering if you had any pointers according a specific issue. That said, feel free to ignore my request!

I want to make use of different ActionMaps, because I will inevitably share the same buttons with some of them. For example the 'Start' Button, linked to the 'Menu' input key, will be used elsewhere and I'd like to avoid to manually keep track of and disable the Menu action in the Input System integration every time.

So, what I did, was to create a reference to the InputAsset, a few helper functions to check whether a button was pressed or released, and changed the Custom_ functions accordingly.

public class GameInputManager : MonoBehaviour
{
    public MyGameInputAsset controls;

    // Singleton code

    private static GameInputManager _instance;
    public static GameInputManager instance
    {
        get
        {
            if (_instance == null)
            {
                _instance = FindObjectOfType<GameInputManager>();
                if (_instance == null)
                {
                    GameObject go = new GameObject();
                    go.name = "[GameInputManager]";
                    _instance = go.AddComponent<GameInputManager>();
                    DontDestroyOnLoad(go);
                }
            }
            return _instance;
        }
    }

    // Helper functions (these can easily be converted into extension methods)

    public bool ActionIsPressed(string actionName)
    {
        InputAction inputAction = controls.asset.FindAction(actionName);
        if (inputAction != null)
        {
            if (inputAction.ReadValue<float>() > 0f)
            {
                Debug.Log(actionName + " isPressed");
                return true;
            } 
        }

        return false;
    }

    public bool ActionWasPressedThisFrame(string actionName)
    {
        InputAction inputAction = controls.asset.FindAction(actionName);
        if (inputAction != null)
        {
            if (inputAction.triggered && inputAction.ReadValue<float>() > 0f)
            {
                Debug.Log(actionName + " wasPressedThisFrame");
                return true;
            }
        }

        return false;
    }

    public bool ActionWasReleasedThisFrame(string actionName)
    {
        InputAction inputAction = controls.asset.FindAction(actionName);
        if (inputAction != null)
        {
            if(inputAction.triggered && inputAction.ReadValue<float>() == 0f)
            {
                Debug.Log(actionName + " wasReleasedThisFrame");
                return true;
            }
        }

        return false;
    }
}

This script enables me to change the Input System Integration Custom_GetButton\Custom_GetButtonDown\Custom_GetButtonUp like so:

private bool Custom_GetButton(string axisName)
{
    return GameInputManager.instance.ActionIsPressed(axisName);
}

private bool Custom_GetButtonDown(string axisName)
{
    return GameInputManager.instance.ActionWasPressedThisFrame(axisName);
}

private bool Custom_GetButtonUp(string axisName)
{
    return GameInputManager.instance.ActionWasReleasedThisFrame(axisName);
}

This works just fine, but I'm experiencing strange (to me, at least) behaviour when it comes to, for instance, the Menu toggle input key.

I have two ActionMaps, one for when the game is in the "Play" state:

and one when is in the "Pause" state:

I switch between states by using AC's OnMenuTurnOn\OnMenuTurnOff events and when I switch to a different state I make sure that the ActionMap I need is the only one active.

This works as long as I don't have a "Menu" action in both. When I do, the Menu Input Key doesn't trigger at all, regardless of the state the game is in.

I initially assumed it triggered twice (as some people experience here), but I noticed that the Debug.Log() lines I included in the input checks don't seem to execute at all.

If I rename the action in the Pause ActionMap to something different - like "Close" - it works as intended when I want to pause the game but, of course, it doesn't work both ways, since "Close" is not the given Input Key for that menu.

I'm not sure what the problem is, because InteractionA and InteractionB work just fine and I use them in both menus.

Do you have any suggestions?

Apologies for the long winded post, but I tried to explain the issue as thoroughly as possible!

Thank you, as always!

Comments

  • So you're saying that Menu/Start works when paused if you remove it from the normal state?

    Sounds like the issue lies more on the Input System side of things, given that the Debug.Log statements don't register. What if you place a Debug.Log in between the null and triggered checks?

    You have InteractionA and B defined in both states - no issues there?

    You could certainly rely on a separate input (i.e. "Close") to close your menu if needed. Rather than setting your Menu's "Appear type" to "On Input Key", you could set it to "Manual", and rely on Active Inputs to run Menu: Change state Actions. One mapped to "Menu" when in the Normal state, another mapped to "Close" when in the Pause state.

    Also, if the "Pause" state inputs are meant to be active whenever the game is paused - not just when this specific menu is open - better to hook into the OnEnterGameState/OnExitGameState events instead.

  • edited October 2020

    Yes, the Menu input key works only if I have an action defined as "Menu" in the "Playing" ActionMap. If I have it in both, it doesn't.

    InteractionA and InteractionB are both defined in both ActionMaps and it doesn't give me any problem, but... I also have noticed that the Debug.Log() only executes if there is something "on the other side" that makes use of that specific action.

    For example: if I press InteractionA while I'm simply walking, nothing happens (that's not the case for "Run", which is still manually bound to the InputSystemIntegration), if I press it while the "Menu" is on, it will both click the selected button and execute the Debug.Log()

    This works also for, say, InteractionX that I use as an interaction key for Hotspots. If I am over an Hotspot, it will execute, otherwise it won't.

    This is what happens if I place a Debug.Log() between the null and trigger checks. No: the ActionWasReleasedThisFrame doesn't show up for any of those, apparently.

    Interestingly, InteractionA, InteractionB are always there (but not InteractionX and InteractionY) and Menu shows even if it's not in the currently active ActionMap. I assume because it's defined as an InputKey in one of the Menus (since other InputKeys are displayed as well, not included in the screenshot)

    This is how I switch between ActionMaps, by the way, for completion:

        void EnableActionMap(string actionMap)
        {
            controls.asset.FindActionMap(actionMap).Enable();
    
            foreach (InputActionMap map in controls.asset.actionMaps)
            {
                if (map.name != actionMap) map.Disable();
            }
        }
    
  • To be clear: "Menu" is what your Pause menu is specifically listening for - as it is with the default interface? AC will be listening for it all the time.

    Your EnableActionMap function looks fine - though perhaps you could swap things around by simple disabling all maps and then only enabling the one found via FindActionMap.

    Otherwise, it may be worth taking this up on the Unity forums - if you're getting a null return on FindAction it sounds like the issue lies on the Unity Input side of things.

  • Yes, "Menu" is the Input Key the Pause menu is listening for, as it is by default.

    I have swapped the code as you suggested in the EnableActionMap but, alas, no difference.

    I have, also included Debug.Log() lines in each of the steps from the Custom_GetButton-- functions in the InputSystemIntegration up to when the Input checks whether it has been triggered or not, like so:

    private bool Custom_GetButton(string axisName)
    {
        Debug.Log($"{axisName}: Custom_GetButton is looking for me");
        return GameInputManager.instance.ActionIsPressed(axisName);
    }
    
    
    private bool Custom_GetButtonDown(string axisName)
    {
        Debug.Log($"{axisName}: Custom_GetButtonDown is looking for me");
        return GameInputManager.instance.ActionWasPressedThisFrame(axisName);
    }
    
    
    private bool Custom_GetButtonUp(string axisName)
    {
        Debug.Log($"{axisName}: Custom_GetButtonUp is looking for me");
        return GameInputManager.instance.ActionWasReleasedThisFrame(axisName);
    }
    
    public bool ActionIsPressed(string actionName)
    {
        InputAction inputAction = controls.asset.FindAction(actionName);
        if (inputAction != null)
        {
            Debug.Log($"{actionName}: ActionIsPressed - action is not null");
            if (inputAction.ReadValue<float>() > 0f)
            {
                Debug.Log($"{actionName}: is pressed");
                return true;
            }
        }
        else
        {
            Debug.Log($"{actionName}: ActionIsPressed - action is null");
            return false;
        }
    
        Debug.Log($"{actionName}: ActionIsPressed - action is not null but was not triggered");
        return false;
    }
    
    public bool ActionWasPressedThisFrame(string actionName)
    {
        InputAction inputAction = controls.asset.FindAction(actionName);
        if (inputAction != null)
        {
            Debug.Log($"{actionName}: ActionWasPressedThisFrame - action is not null");
            if (inputAction.triggered && inputAction.ReadValue<float>() > 0f)
            {
                Debug.Log($"{actionName}: wasPressedThisFrame");
                return true;
            }
        }
        else
        {
            Debug.Log($"{actionName}: ActionWasPressedThisFrame - action is null");
            return false;
        }
    
        Debug.Log($"{actionName}: ActionWasPressedThisFrame - action is not null but was not triggered");
        return false;
    }
    
    public bool ActionWasReleasedThisFrame(string actionName)
    {
        InputAction inputAction = controls.asset.FindAction(actionName);
        if (inputAction != null)
        {
            Debug.Log($"{actionName}: ActionWasReleasedThisFrame - action is not null");
            if (inputAction.triggered && inputAction.ReadValue<float>() == 0f)
            {
                Debug.Log($"{actionName}: wasReleasedThisFrame");
                return true;
            }
        }
        else
        {
            Debug.Log($"{actionName}: ActionWasReleasedThisFrame - action is null");
            return false;
        }
    
        Debug.Log($"{actionName}: ActionWasReleasedThisFrame - action is not null but was not triggered");
        return false;
    }
    
    

    Not sure if it's any help, but here's how things unfold (again, only for keys that are already defined in the AC list of Available Inputs) when I'm idle.

    Then, to make things easier I displayed only the results for the Menu action. This is when the InputAction is available in both ActionMaps:

    In this case, if I try to trigger the action, nothing changes: it is never null, but it's never triggered either.

    The following is, instead, what happens the moment I trigger the InputAction when it's only available in the "Playing" ActionMap.

  • AC is doing it's job - Menu is being requested. The problem does indeed look to be on the Unity side of things.

  • edited October 2020

    I will check with the Unity forums!

    Regardless, thanks a lot, Chris!

  • Update!

    Without me making any manual tweaks to the above code, apparently the new 1.1.0-preview.2 package of the new Input System seems to have fixed the issue.

    Here's the changelog.

    They have also introduced, as promised, "native" .IsPressed(), .WasPressedThisFrame(), etc. checks!

    Will update further if this proves to break something else, but so far everything seems to be working!

Sign In or Register to comment.

Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Welcome to the official forum for Adventure Creator.