Forum rules - please read before posting.

Unity UI Cursor Help

I have a Unity Prefab Cursor that I am using that animates out when hovering over a hotspot. It is working well but has a few issues I need your help with please.

When I go to click on an inventory item nothing happens and I get this error:

NullReferenceException: Object reference not set to an instance of an object
InventoryOnlyHotspot.OnInventorySelect (AC.InvItem item) (at Assets/Sleepytime Village/Scripts/InventoryOnlyHotspot.cs:24)
AC.EventManager.Call_OnChangeInventory (AC.InvCollection invCollection, AC.InvInstance invInstance, AC.InventoryEventType inventoryEventType, System.Int32 amountOverride) (at Assets/AdventureCreator/Scripts/Managers/EventManager.cs:1458)
AC.RuntimeInventory.SelectItem (AC.InvInstance invInstance, AC.SelectItemMode _mode) (at Assets/AdventureCreator/Scripts/Inventory/RuntimeInventory.cs:218)

Also, the Cursor not changing on menus for UI even though ‘Change cursor when over’ is ticked.

Plus, once the hotspot is clicked I would like for either the clicked interaction icon (use, examine etc) to pulse, and then the cursor to do the close animation.

I have created a detailed PDF document showcasing all code and videos in this folder, be really cool if you can help!:

https://www.dropbox.com/sh/zi5taggcayh2rz9/AACJmtS-Swigg-d1l3Ww1f4Ua?dl=0

«13

Comments

  • When I go to click on an inventory item nothing happens and I get this error

    The script you have posted is not the script the error is coming from.

    Cursor not changing on menus for UI even though ‘Change cursor when over’ is ticked.

    Since your "Unity UI cursor" component does not have the "RawImage to control" field assigned, you must update the cursor image by hooking into either:

    Once the hotspot is clicked I would like for either the clicked interaction icon (use, examine etc) to pulse, and then the cursor to do the close animation.

    You can hook into the OnHotspotInteract event to update the Animator when a Hotspot interaction is run. Use Animator an transition with "Has Exit Time" to automatically play another animation once the "pulse" animation has ended.

  • The script you have posted is not the script the error is coming from.

    Which script do I need to show you?

    Since your "Unity UI cursor" component does not have the "RawImage to control" field assigned, you must update the cursor image by hooking into either:

    My scripting skills are not good enough to understand how to do this, I was given help on the initial script, are you able to help my update?

    You can hook into the OnHotspotInteract event to update the Animator when a Hotspot interaction is run. Use Animator an transition with "Has Exit Time" to automatically play another animation once the "pulse" animation has ended.

    And how would I go about this exactly? Would this need scripting too? Sorry, but it would be much appreciated if you could help!

  • Which script do I need to show you?

    InventoryOnlyHotspot.cs

    My scripting skills are not good enough to understand how to do this

    An easier approach would be to read the value of the GetElementOverCursorID function in your Update loop. This could be mapped to a new Integer parameter in the Animator, e.g. "MenuOverrideID":

    int menuOverrideID = KickStarter.playerMenus.GetElementOverCursorID ();
    _animator.SetInteger ("MenuOverrideID", menuOverrideID);
    

    And how would I go about this exactly?

    Create a Trigger parameter named "Interaction", subscribe to the OnHotspotInteract event and use this implementation:

    private void OnHotspotInteract (Hotspot hotspot, AC.Button button)
    {
        _animator.SetTrigger ("Interaction");
    }
    
  • edited May 2022
    Thanks I’ll try the above.
  • Here is InventoryOnlyHotpot.cs

    Using AC;
    using UnityEngine;
    
    public class InventoryOnlyHotspot : MonoBehaviour
    {
    
        public Hotspot hotspot;
    
        private void OnEnable ()
        { 
            EventManager.OnInventorySelect += OnInventorySelect;
            EventManager.OnInventoryDeselect += OnInventoryDeselect;
            hotspot.TurnOff ();
        }
    
        private void OnDisable ()
        { 
            EventManager.OnInventorySelect -= OnInventorySelect;
            EventManager.OnInventoryDeselect -= OnInventoryDeselect;
        }
    
        private void OnInventorySelect (InvItem item)
        {
            hotspot.TurnOn ();
        }
    
        private void OnInventoryDeselect (InvItem item)
        {
            hotspot.TurnOff ();
        }
    
    }
    
  • Apologies, I also am not quite sure how to implement this either:

    An easier approach would be to read the value of the GetElementOverCursorID function in your Update loop. This could be mapped to a new Integer parameter in the Animator, e.g. "MenuOverrideID":

    int menuOverrideID = KickStarter.playerMenus.GetElementOverCursorID ();
    

    _animator.SetInteger ("MenuOverrideID", menuOverrideID);
    And how would I go about this exactly?

    Create a Trigger parameter named "Interaction", subscribe to the OnHotspotInteract event and use this implementation:

    private void OnHotspotInteract (Hotspot hotspot, AC.Button button)
    

    {
    _animator.SetTrigger ("Interaction");
    }

  • Here is InventoryOnlyHotpot.cs

    The issue is that you have an instance of the script in your scene with no Hotspot assigned in its Inspector.

    Apologies, I also am not quite sure how to implement this either:

    They will need to be incorporated into your exising custom script, so how you do so exactly will depend on the specific needs of your project.

    Approach them separately. Start with the first one, adding the code to your Update loop.

    For the second, you need to paste the new function in as well as subscribe to the OnHotspotInteract event. This'll be a case of adding the following to your OnEnable function:

    EventManager.OnHotspotInteract += OnHotspotInteract;
    

    And the following to your OnDisable function:

    EventManager.OnHotspotInteract -= OnHotspotInteract;
    
  • edited May 2022

    The issue is that you have an instance of the script in your scene with no Hotspot assigned in its Inspector.

    This error doesn;t seem to come up now when trying to click on an inventory item. But with my new cursor the hotspot highlight happens when the UI Cursor is over the inventory item, but I cannot click on it or select it.

    UPDATE

    i think that I do select it, but it does not show on the cursor, as I had the original AC cursor set up so that when you clicked on the inventory item the cursor becomes the inventory item. What do I need to do to make sure the item becomes the cursor in my UI Cursor set up? Thanks

  • If you add a new Integer parameter named "CursorID", you can have it set to the active cursor's ID value by adding the following in your script's Update loop:

    _animator.SetInteger ("CursorID", KickStarter.playerCursor.GetSelectedCursorID ());
    
  • Ok, so apologies for my interpretation, but this is now my script:

    using System.Collections;
    

    using System.Collections.Generic;
    using UnityEngine;
    using AC;

    public class CursorScript : MonoBehaviour
    {
    public Animator _animator;
    public string useIconIDParameter = "UseIconID";
    public string hasLookIconParameter = "HasLookIcon";
    public string speechParameter = "IsSpeaking";
    public string conversationParameter = "InConversation";

    private void OnEnable ()
    {
        EventManager.OnStartSpeech_Alt += StartSpeech;
        EventManager.OnStopSpeech_Alt += StopSpeech;
        EventManager.OnStartConversation += StartConversation;
        EventManager.OnEndConversation += EndConversation;
        EventManager.OnClickConversation += ClickConversation;
      EventManager.OnHotspotInteract += OnHotspotInteract;
    
    }
    
    private void OnDisable ()
    {
        EventManager.OnStopSpeech_Alt -= StopSpeech;
        EventManager.OnStartSpeech_Alt -= StartSpeech;
        EventManager.OnStartConversation -= StartConversation;
        EventManager.OnEndConversation -= EndConversation;
        EventManager.OnClickConversation -= ClickConversation;
      EventManager.OnHotspotInteract -= OnHotspotInteract;
    
    }
    
    private void StartSpeech (Speech speech)
    {
        _animator.SetBool (speechParameter, true);
    }
    
    private void StopSpeech (Speech speech)
    {
        _animator.SetBool (speechParameter, false);
    }
    
    private void StartConversation (Conversation conversation)
    {
        _animator.SetBool (conversationParameter, true);
    }
    
    private void EndConversation (Conversation conversation)
    {
        
    }
    
    private void ClickConversation (Conversation conversation, int optionId)
    {
        _animator.SetBool (conversationParameter, false);
    }
    
    private void Update ()
    {
        bool hasLookIcon = false;
        int useIconID = -1;
    
        if (AC.KickStarter.stateHandler.IsInGameplay ())
        {
            AC.Hotspot hotspot = AC.KickStarter.playerInteraction.GetActiveHotspot ();
            if (hotspot)
            {
                hasLookIcon = hotspot.HasContextLook ();
                if (hotspot.HasContextUse ())
                {
                    useIconID = hotspot.GetFirstUseButton ().iconID;
                }
            }
        }
    
        _animator.SetInteger (useIconIDParameter, useIconID);
        _animator.SetBool (hasLookIconParameter, hasLookIcon);
      _animator.SetInteger ("CursorID", KickStarter.playerCursor.GetSelectedCursorID ());
    
    }
    

    }

    But I am now getting this error:

    Assets/CursorScript.cs(32,37): error CS0103: The name 'OnHotspotInteract' does not exist in the current context

    Here is a picture of my animator set up with new parameters added:

    https://www.dropbox.com/s/5wa3yhpxzrgpj5i/Cursor parameters.png?dl=0

  • UPDATE

    I have added all the additions you made earlier so now my script has no errors, but the inventory object is still not being picked up from my inventory. It remains in the inventory also. Also none of the other asks are currently working.

    The Cursor not changing on menus for UI even though ‘Change cursor when over’ is ticked.

    Once the hotspot is clicked I would like for either the clicked interaction icon (use, examine etc) to pulse, and then the cursor to do the close animation.

    Am I missing something else that I need to do to make the above three asks work?

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using AC;
    
    public class CursorScript : MonoBehaviour
    {
        public Animator _animator;
        public string useIconIDParameter = "UseIconID";
        public string hasLookIconParameter = "HasLookIcon";
        public string speechParameter = "IsSpeaking";
        public string conversationParameter = "InConversation";
    
        private void OnEnable ()
        {
            EventManager.OnStartSpeech_Alt += StartSpeech;
            EventManager.OnStopSpeech_Alt += StopSpeech;
            EventManager.OnStartConversation += StartConversation;
            EventManager.OnEndConversation += EndConversation;
            EventManager.OnClickConversation += ClickConversation;
            EventManager.OnHotspotInteract += OnHotspotInteract;
    
        }
    
        private void OnDisable ()
        {
            EventManager.OnStopSpeech_Alt -= StopSpeech;
            EventManager.OnStartSpeech_Alt -= StartSpeech;
            EventManager.OnStartConversation -= StartConversation;
            EventManager.OnEndConversation -= EndConversation;
            EventManager.OnClickConversation -= ClickConversation;
            EventManager.OnHotspotInteract -= OnHotspotInteract;
    
        }
    
        private void OnHotspotInteract (Hotspot hotspot, AC.Button button)
        {
            _animator.SetTrigger ("Interaction");
        }
    
    
        private void StartSpeech (Speech speech)
        {
            _animator.SetBool (speechParameter, true);
        }
    
        private void StopSpeech (Speech speech)
        {
            _animator.SetBool (speechParameter, false);
        }
    
        private void StartConversation (Conversation conversation)
        {
            _animator.SetBool (conversationParameter, true);
        }
    
        private void EndConversation (Conversation conversation)
        {
    
        }
    
        private void ClickConversation (Conversation conversation, int optionId)
        {
            _animator.SetBool (conversationParameter, false);
        }
    
        private void Update ()
        {
            bool hasLookIcon = false;
            int useIconID = -1;
    
            if (AC.KickStarter.stateHandler.IsInGameplay ())
            {
                AC.Hotspot hotspot = AC.KickStarter.playerInteraction.GetActiveHotspot ();
                if (hotspot)
                {
                    hasLookIcon = hotspot.HasContextLook ();
                    if (hotspot.HasContextUse ())
                    {
                        useIconID = hotspot.GetFirstUseButton ().iconID;
                    }
                }
            }
    
            _animator.SetInteger (useIconIDParameter, useIconID);
            _animator.SetBool (hasLookIconParameter, hasLookIcon);
            _animator.SetInteger ("CursorID", KickStarter.playerCursor.GetSelectedCursorID ());
    
        }
    }
    
  • Your approach to controlling the cursor is entirely Animator-based, meaning the script will affect Animator parameter values rather than the cursor's appearance directly.

    Adding the parameters is not enough: you must also create transitions that rely on them and their values to get the effects you want. "CursorID" will relate to the current cursor ID, and "Interaction" will fire when using a Hotspot.

    You have not implemented either of my suggestions for the "mouse over" cursor, i.e.:

    int menuOverrideID = KickStarter.playerMenus.GetElementOverCursorID ();
    _animator.SetInteger ("MenuOverrideID", menuOverrideID);
    

    "MenuOverrideID" will relate to the ID of the cursor when over a menu (and -1 otherwise).

    The following will update an Integeter parameter named "InvID" to the ID of the currently-selected item (and -1 otherwise):

    _animator.SetInteger ("InvID", (KickStarter.runtimeInventory.SelectedItem != null) ? KickStarter.runtimeInventory.SelectedItem.id : -1);
    

    These should be placed in the Update function.

    How you make use of these parameters will be down to you - but check that their values are updating correctly before moving on.

  • ok I have updated the script and now nothing works, am I completely redefining how my animator is set up then?

    And is my code now correct?

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using AC;
    
    public class CursorScript : MonoBehaviour
    {
        public Animator _animator;
        public string useIconIDParameter = "UseIconID";
        public string hasLookIconParameter = "HasLookIcon";
        public string speechParameter = "IsSpeaking";
        public string conversationParameter = "InConversation";
    
        private void OnEnable ()
        {
            EventManager.OnStartSpeech_Alt += StartSpeech;
            EventManager.OnStopSpeech_Alt += StopSpeech;
            EventManager.OnStartConversation += StartConversation;
            EventManager.OnEndConversation += EndConversation;
            EventManager.OnClickConversation += ClickConversation;
            EventManager.OnHotspotInteract += OnHotspotInteract;
    
        }
    
        private void OnDisable ()
        {
            EventManager.OnStopSpeech_Alt -= StopSpeech;
            EventManager.OnStartSpeech_Alt -= StartSpeech;
            EventManager.OnStartConversation -= StartConversation;
            EventManager.OnEndConversation -= EndConversation;
            EventManager.OnClickConversation -= ClickConversation;
            EventManager.OnHotspotInteract -= OnHotspotInteract;
    
        }
    
        private void OnHotspotInteract (Hotspot hotspot, AC.Button button)
        {
            _animator.SetTrigger ("Interaction");
        }
    
    
        private void StartSpeech (Speech speech)
        {
            _animator.SetBool (speechParameter, true);
        }
    
        private void StopSpeech (Speech speech)
        {
            _animator.SetBool (speechParameter, false);
        }
    
        private void StartConversation (Conversation conversation)
        {
            _animator.SetBool (conversationParameter, true);
        }
    
        private void EndConversation (Conversation conversation)
        {
    
        }
    
        private void ClickConversation (Conversation conversation, int optionId)
        {
            _animator.SetBool (conversationParameter, false);
        }
    
        private void Update ()
        {
            bool hasLookIcon = false;
            int useIconID = -1;
    
            if (AC.KickStarter.stateHandler.IsInGameplay ())
            {
                AC.Hotspot hotspot = AC.KickStarter.playerInteraction.GetActiveHotspot ();
                if (hotspot)
                {
                    hasLookIcon = hotspot.HasContextLook ();
                    if (hotspot.HasContextUse ())
                    {
                        useIconID = hotspot.GetFirstUseButton ().iconID;
                    }
                }
            }
            int menuOverrideID = KickStarter.playerMenus.GetElementOverCursorID ();
            _animator.SetInteger ("MenuOverrideID", menuOverrideID);
            _animator.SetInteger (useIconIDParameter, useIconID);
            _animator.SetBool (hasLookIconParameter, hasLookIcon);
            _animator.SetInteger ("CursorID", KickStarter.playerCursor.GetSelectedCursorID ());
            _animator.SetInteger ("InvID", (KickStarter.runtimeInventory.SelectedItem != null) ? KickStarter.runtimeInventory.SelectedItem.id : -1);
    
    
        }
    }
    
  • How correct it is overall will be down to what you need it to do - but the additions since the last post are right.

    Again, though, the approach you're taking is to rely on Animator parameters to control appearance. You will need to update your Animator to account for the parameter values the script controls.

  • edited May 2022
    Thanks Chris. I appreciate your points above, but considering the main issue is the inventory items not appearing in the cursor or being selected and not then being in the inventory, I don’t quite understand how a parameter in the animator will fix this. I therefore need a step by step guide of what actually to do to make this work.


    The other elements like pulsing and other subtle animations I will work out.

    I’d really appreciate specific help with the above as it’s a blocker in my game progression. Thanks again.
  • the main issue is the inventory items not appearing in the cursor or being selected and not then being in the inventory, I don’t quite understand how a parameter in the animator will fix this

    Items are being selected, but the cursor won't update visually unless you have a means for it to do so.

    The "InvID" parameter is one such way - this parameter will be set to the currently-selected item's ID number. If you created an animation for each item, that caused the cursor to change its graphic to that item, then this parameter could be used to transition to the appropriate animation.

    Alternatively, if you had no need for animation while an inventory item is selected, you could disable animation and update the cursor's RawImage component with the inventory item's graphic directly:

    if (rawImageToControl)
    {
        if (KickStarter.runtimeInventory.SelectedItem != null)
        {
            _animator.enabled = false;
            rawImageToControl.texture = KickStarter.runtimeInventory.SelectedItem.tex;
        }
        else
        {
            _animator.enabled = true;
        }
    }
    

    Add the above to your Update function, and then this to your variables:

    public RawImage rawImageToControl;
    
  • Thanks Chris, updated script but getting this error

    Assets/Sleepytime Village/Scripts/CursorScript.cs(13,9): error CS0246: The type or namespace name 'RawImage' could not be found (are you missing a using directive or an assembly reference?)
    

    This is my updated code:

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using AC;
    
    public class CursorScript : MonoBehaviour
    {
        public Animator _animator;
        public string useIconIDParameter = "UseIconID";
        public string hasLookIconParameter = "HasLookIcon";
        public string speechParameter = "IsSpeaking";
        public string conversationParameter = "InConversation";
        public RawImage rawImageToControl;
    
    
        private void OnEnable ()
        {
            EventManager.OnStartSpeech_Alt += StartSpeech;
            EventManager.OnStopSpeech_Alt += StopSpeech;
            EventManager.OnStartConversation += StartConversation;
            EventManager.OnEndConversation += EndConversation;
            EventManager.OnClickConversation += ClickConversation;
            EventManager.OnHotspotInteract += OnHotspotInteract;
    
        }
    
        private void OnDisable ()
        {
            EventManager.OnStopSpeech_Alt -= StopSpeech;
            EventManager.OnStartSpeech_Alt -= StartSpeech;
            EventManager.OnStartConversation -= StartConversation;
            EventManager.OnEndConversation -= EndConversation;
            EventManager.OnClickConversation -= ClickConversation;
            EventManager.OnHotspotInteract -= OnHotspotInteract;
    
        }
    
        private void OnHotspotInteract (Hotspot hotspot, AC.Button button)
        {
            _animator.SetTrigger ("Interaction");
        }
    
    
        private void StartSpeech (Speech speech)
        {
            _animator.SetBool (speechParameter, true);
        }
    
        private void StopSpeech (Speech speech)
        {
            _animator.SetBool (speechParameter, false);
        }
    
        private void StartConversation (Conversation conversation)
        {
            _animator.SetBool (conversationParameter, true);
        }
    
        private void EndConversation (Conversation conversation)
        {
    
        }
    
        private void ClickConversation (Conversation conversation, int optionId)
        {
            _animator.SetBool (conversationParameter, false);
        }
    
        private void Update ()
        {
            bool hasLookIcon = false;
            int useIconID = -1;
    
            if (AC.KickStarter.stateHandler.IsInGameplay ())
            {
                AC.Hotspot hotspot = AC.KickStarter.playerInteraction.GetActiveHotspot ();
                if (hotspot)
                {
                    hasLookIcon = hotspot.HasContextLook ();
                    if (hotspot.HasContextUse ())
                    {
                        useIconID = hotspot.GetFirstUseButton ().iconID;
                    }
                }
            }
            int menuOverrideID = KickStarter.playerMenus.GetElementOverCursorID ();
            _animator.SetInteger ("MenuOverrideID", menuOverrideID);
            _animator.SetInteger (useIconIDParameter, useIconID);
            _animator.SetBool (hasLookIconParameter, hasLookIcon);
            _animator.SetInteger ("CursorID", KickStarter.playerCursor.GetSelectedCursorID ());
            _animator.SetInteger ("InvID", (KickStarter.runtimeInventory.SelectedItem != null) ? KickStarter.runtimeInventory.SelectedItem.id : -1);
    
            if (rawImageToControl)
        {
            if (KickStarter.runtimeInventory.SelectedItem != null)
        {
            _animator.enabled = false;
            rawImageToControl.texture = KickStarter.runtimeInventory.SelectedItem.tex;
        }
            else
        {
            _animator.enabled = true;
        }
    }
    
    
        }
    }
    
  • Hi Chris, fixed the error, but the above script isn't doing anything different. I don;t need the inventory item to animate, just the cursors. But as I say, I fixed the script and nothing has changed.

    I get this in my console if that shed any light?

    Parameter 'CursorIsVisible' does not exist.
    
  • Assign the RawImage field in the Inspector.

  • Ok so I assigned the cursor, but still nothing happens

    see screenshot

    https://www.dropbox.com/s/tjdnjttu8wt20td/CursorProblem.png?dl=0

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.