Forum rules - please read before posting.

Clicking inventory item inconsistency (Unity UI menu)

I followed this (great) tutorial on how to swap out the built in inventory menu for a custom Unity UI one:
https://adventurecreator.org/tutorials/creating-inventory-bar-unity-ui

One thing I haven't been able to fix though:
When you click an inventory item using the built-in InventoryBox (and the player is currently in a Speech action), it cancels the speech action. But when I do this with my custom one it immediately replaces the current Speech action with a new one.

Any ideas of how to mimic the build in functionality?

Thanks!

Comments

  • In what AC version?

    I'll need you to elaborate on this. Is your ActionList running in the background, and what is your Inventory menu's "Appear type" set to?

    Please provide steps on how to recreate this. The New Game Wizard can be used to create a default AC interface, and those menus already have Unity UI counterparts that you can switch to via their "Source" fields.

  • AC version 1.66.8
    Unity: 2018.3.9f1

    I put together a package that contains a scene using both the default in AC inventory menu and the default Unity UI inventory menu that illustrates the point:
    https://1drv.ms/u/s!Amz_vh8OYDX3u4QBDN-CoesqjR6jxw

    Let me know if you need anything else.

  • What must I do to see the behaviour?

    1. Click the inventory item on the top menu
    2. While the player is talking, click it again - notice that it cancels the speech action
    3. Do the same thing with the bottom menu - notice that the speech action is not only canceled but also restarted
  • This is a complicated issue, because it involves two separate input systems: one using Unity's Input API (for the speech skipping check), another using Unity's EventSystem (for the UI click checks).

    This is somewhat of an edge-case, because you're inventory menu is set to appear at all times, which isn't the default behaviour.

    At the root of the issue is the fact that the speech-skipping occurs on the mouse-down, while the UI reacts to the mouse-up. Therefore, a single click will trigger both.

    Making heavy changes to AC's core to try to combat this automatically is messy and prone to further issues when custom input systems etc are also accounted for. I've tried a number of approaches, and the best results for me come when using an override script to cause speech-skipping to react to mouse-ups as well.

    In your Speech Manager, uncheck Can skip with mouse clicks? so that only the SkipSpeech input is relied upon. The following script, attached to a GameObject in your scene, will then rely on mouse-ups to skip speech:

    using UnityEngine;
    using System.Collections;
    using AC;
    
    public class SkipSpeechOnUp : MonoBehaviour
    {
    
        private bool canSkip;
    
    
        private void Start ()
        {
            KickStarter.playerInput.InputGetButtonDownDelegate = My_GetInputButtonDown;
            EventManager.OnStartSpeech += My_OnStartSpeech;
        }
    
    
        private void LateUpdate ()
        {
            if (!Input.GetMouseButton (0)) canSkip = true;
        }
    
    
        private void My_OnStartSpeech (Char speaker, string messageText, int lineID)
        {
            canSkip = false;
        }
    
    
        private bool My_GetInputButtonDown (string axisName)
        {
            if (axisName == "SkipSpeech")
            {
                return canSkip && Input.GetMouseButtonUp (0);
            }
    
            try
            {
                return Input.GetButtonDown (axisName);
            }
            catch {}
            return false;
        }
    
    }
    
  • Thank's for looking into this, two questions:

    1. your solution causes skipping to be done on mouseup rather than mousedown though, any way to fix this?

    2. If not I'm looking at an alternative solution that involves placing a script directly on the Unity UI Button itself, but it require a way to skip speech through script - is such an API available?

    Thanks!

    1. Skipping on mouseup is the solution - or at least the most reliable I could find, at least.
    2. Speech skipping can be done by invoking the "SkipSpeech" input button, but input itself can also be simulated through script, via the SimulateInputButton function:

      AC.KickStarter.playerInput.SimulateInputButton ("SkipSpeech");

  • Glad to hear about the SimulateInputButton, that cleaned up my code in a couple of other places :)

    I'm trying only to work with the actual inventory buttons and leave the rest av AC's speech skipping intact (so that onmousedown keeps working and to avoid unforeseen conflicts in the future).

    I haven't gotten it to work yet, but here's the script I'm using on my inventory buttons right now - perhaps you can see a clean solution:
    https://pastebin.com/vdeu0Kty

    Thanks!

  • Is there a need for an Update() call? What would be the effect of resetting the input and simulating the click directly within OnPointerDown?

  • You're probably right but I'm not sure what you mean by "resetting" the input (I'm new to Unitys UI system).

    I tried to disable the button in order to re-enable it on the next update), but for some reason changing the buttons interactable property have no effect.

    I also tried to temporarily empty the listeners of the buttons onclick property, only to re-add them after the mouseup, but it seems the way that AC hooks up to the button isn't done through the onclick property.

  • You're probably right but I'm not sure what you mean by "resetting" the input

    I'm referring to your own code, where you call AC's ResetClick method.

    it seems the way that AC hooks up to the button isn't done through the onclick property.

    AC adds a listener, which avoids the need to have a property script attached to the Button itself.

    If you want to override the way your InventoryBox element reacts to input, you can set it's Inventory box type property to Custom Script. This'll allow you to add in onclick properties manually, and script interactions to suit. AC's API provides ways to retrieve a clicked inventory item based on the UI Button:

    int clickedSlotIndex = 0; // Set this to the index of the array of "item slot" UI Buttons that was clicked
    MenuInventoryBox inventoryBox = PlayerMenus.GetElementWithName ("MyInventoryMenu", "MyInventoryBox") as MenuInventoryBox;
    InvItem clickedItem = inventoryBox.GetItem (clickedSlotIndex);
    

    For an example on how to run inventory item interactions, see the provided "CustomInteractionExample.cs" script file.

  • edited March 2019

    I have tried moving the call to AC's ResetClick to OnPointerDown but I get the same effect as when doing it on Update (nu luck).

    Setting the Inventory box type to "Custom script" means we loose all the beautiful logic of drag n dropping items to combine and with each other and on hotspots etc.

    Here's what I tried so far to temporarily ignore the mouse-up (in the script attached to the inventory button itself). I tried it on mousedown, mouseup, update and lateupdate:

    // Inactivate the click throug AC (does not work)
    KickStarter.playerInput.ResetClick();
    KickStarter.playerInput.ResetMouseClick();
    KickStarter.playerInput.SimulateInputButton("SkipSpeech");

    // Remove the listeners added to the button by AC (does not work)
    var button = gameObject.GetComponent<UnityEngine.UI.Button>();
    button.onClick.RemoveAllListeners();

    // Simply disable the button (does not work)
    button.interactable = false;

    I also tried to just disaable all the buttons in the inventory UI on the EventManager.OnStartSpeech event, but setting the buttons interactive prop has no effect.

  • It's a complicated issue, to be sure - hence my suggested workaround above.

    An alternative solution may be to turn on a full-screen, invisible menu when speech plays - and that has a Button set to simulate the SkipSpeech input button.

  • I just tried it - I added a new AC Menu with a button that completely covers the inventory items in the menu below. Believe it or not but the inventory buttons underneath it is still responsive :open_mouth:

    I tried all the above mentioned tricks in the new buttons mouseup and mousedown - no luck.

    I admit that me preferring to keep "skip speech" on mousedown rather that mouseup might seem a bit picknicky :) But surely it would be great if there was some way to disable an AC menu button?

    BTW: If one adds a button element to an AC menu, a "Responds to" option is available, if it would be possible to add the same logic to the linked buttons of an inventory box, that could possibly fix my original issue.

  • Believe it or not but the inventory buttons underneath it is still responsive

    I will attempt the menu overlay trick myself - admittedly it was only a thought.

    But surely it would be great if there was some way to disable an AC menu button?

    If it's an "AC menu", it will be - the issue is that this involves Unity UI, which is totally separate. If your whole interface uses Unity UI, then such conflicts are rare - but invoking AC inputs is still a separate system.

    If one adds a button element to an AC menu, a "Responds to" option is available

    That was one of my first attempts at a workaround, but it brought on more issues as a result. There's a lot of hidden complexities going on in the background to get Unity UI to behave with the inventory, so I'm wary of opening such a can of worms.

    I may have another idea, which I'll try out.

  • Much appreciated, Chris!

  • All right, try this:

    using UnityEngine;
    using System.Collections;
    using AC;
    
    public class SkipSpeechWait : MonoBehaviour
    {
    
        private void OnEnable ()
        {
            EventManager.OnStopSpeech_Alt += OnStopSpeech;
        }
    
        private void OnDisable ()
        {
            EventManager.OnStopSpeech_Alt -= OnStopSpeech;
        }
    
        private void OnStopSpeech (Speech speech)
        {
            if (Input.GetMouseButtonDown (0))
            {
                StartCoroutine (WaitForMouseUp ());
            }
        }
    
        private IEnumerator WaitForMouseUp ()
        {
            KickStarter.stateHandler.StartCutscene ();
    
            while (Input.GetMouseButton (0))
            {
                yield return new WaitForEndOfFrame ();
            }
    
            yield return new WaitForEndOfFrame ();
    
            KickStarter.stateHandler.EndCutscene ();
        }
    
    }
    

    This script (SkipSpeechWait.cs) will place the game in a scripted cutscene while the mouse is held after skipping speech, forcing the inventory to be unresponsive during this time.

  • Does the trick - thanks man!

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.