Forum rules - please read before posting.

Showing Inventory Images on hover

edited January 2018 in Technical Q&A
Hi there,

For my game, I want a separate, enlarged image of an object in my inventory, alongside a small blerb, to appear on the GUI when the mouse hovers over it. I imagine that I'd have to make a GUI image/object in the canvas that is only enabled on hover, but I have no idea how to code this at all.

Can I get some help making this work?
«1

Comments

  • You'll certainly need coding for it, but it'll be easier to use a Unity UI-based Menu because it can more easily be scripted.

    Start by creating Inventory properties to store the blurb text - see the "Inventory properties" chapter of the Manual.

    Also see "Inventory scripting": the item currently being hovered over can be read with:

    KickStarter.runtimeInventory.hoverItem;

    You can check for this in an Update() function to see what the cursor is hovering over, and retrieve that item's properties, i.e.:

    if (KickStarter.runtimeInventory.hoverItem != null)
    {
      string blurb = KickStarter.runtimeInventory.hoverItem.GetProperty (0).textVal;
      Debug.Log ("Blurb for " + KickStarter.runtimeInventory.hoverItem.label + " is " + blurb);
    }

    That gets the text for property 0 of the item being hovered over (assuming its a String property), and prints it to the Console.

    Putting things in a UI is another complication, so let's start with that for now.  Place that in the update function of a new script, and add it to your scene.  Once you get blurb texts showing in the Console, we can move onto the next step.
  • edited January 2018
    Deleted. Misread instructions.
  • edited January 2018
    Okay, I tried your method and put the script on the GameEngine as the Kickstarter property recommended (Can you please explain the Kickstarter call to me, I don't understand) and added a new Inventory Property. It worked.

    At the moment it just says "Blurb for *item* is" It doesn't complete the sentence, as I imagine blurb is undefined. I'm sure that can be rectified. My Inventory property, currently named Test1, is a string However there's nowhere I can input information besides its name.

    So what are the next steps?
  • Once you've defined the "Blurb" property in the "Properties" tab of the Inventory Manager, go bac to the "Items" tab.  When editing a given item, you can set the values of any defined properties for it.

    The script doesn't need to be placed on the KickStarter, but you do need to have:

    using AC;

    at the top of your script so that it can access the AC API.  The "KickStarter" script provides static references to all of AC's scripts, making it easy to access them (in this case, RuntimeInventory).  For further explanation and example, see the front page of the Scripting Guide.

    For the image, you'll want to do this through Unity's Resources.Load method, which can load in textures placed in a Resources folder by filename.  Therefore, you'll need another String property for your inventory items that takes the filename you want to load.  Make sure each item's "enlarged" sprite is a unique filename and placed in a Resources folder (can be a subfolder), and enter that filename as each item's "Filename" property.  Then try this:

    if (KickStarter.runtimeInventory.hoverItem != null)
    {
      string blurb = KickStarter.runtimeInventory.hoverItem.GetProperty (0).textVal;

      string filename = KickStarter.runtimeInventory.hoverItem.GetProperty (1).textVal;
      Sprite itemSprite = Resources.Load (filename) as Sprite;

      Debug.Log ("Hovering over " + KickStarter.runtimeInventory.hoverItem.label + "; Blurb = " + blurb + ", Sprite: " + itemSprite);
    }


    Assuming property "0" is the blurb, and property "1" is the filename, that should get the blurb and sprite names showing up in the Console.
  • edited January 2018
    Alright, I added another File Name property and this worked. However, the way your code is written, the debug.log reads out "Hovering over Book7; Blurb = An Anatomy book by someone, Sprite:" again, ignoring the new variable. This time, I actually did fill in both the Blurb and FileName (both with and without ".jpg") properties. I'm not sure if you made an error, but because the itemSprite is a sprite perhaps it can't be logged in text? I added + Filename and it did get put into the log.

    To clear up what I'm doing, I have a book (for example Anatomy.jpg in my Resources folder) that, when I hover over it in my inventory, I want an enlarged version of that book (does it have to be a different image than the inventory sprite?) to appear on the centre of my screen, with the blurb beneath it showing information about the item.

    Additionally, I do appreciate you walking me through this step by step over the nights, but I am coming closer to my deadline. Not to be pushy, but can you describe the rest of the steps I need?
  • You can use the same image as the icon if you like.  That would remove the need for the second property / Resources stuff:

    if (KickStarter.runtimeInventory.hoverItem != null)
    {
      string blurb = KickStarter.runtimeInventory.hoverItem.GetProperty (0).textVal;

      string filename = KickStarter.runtimeInventory.hoverItem.GetProperty (1).textVal;

     
    Debug.Log ("Hovering over " +
    KickStarter.runtimeInventory.hoverItem.label + "; Blurb = " + blurb + ", Texture " + KickStarter.runtimeInventory.hoverItem.tex);
    }

    You then want to create a new Unity UI based Menu that has child components to hold both the image and the blurb text.  I'd recommend using the RawImage component instead of Image as with that you can use Texture2D fields, as opposed to just Sprites.

    Link the UI Canvas to the Menu, along with its RectTransform boundary (see this tutorial) but don't link the Elements.  Set the Menu's Appear type to Manual but make sure Enabled by default? is off.

    You'll then need a script that fills in the fields, positions the Menu correctly, and turns it on when the item hovers over something.  Something like this should do it:

    using UnityEngine;
    using UnityEngine.UI;
    using AC;

    public class HoverItemProperties
    {

        public Text blurbBox;
        public RawImage largeImage;
        public string menuName;

        private InvItem hoverItem;


        private void Update ()
        {
            if (KickStarter.runtimeInventory.hoverItem != hoverItem)
            {
                SetHoverItem (KickStarter.runtimeInventory.hoverItem);
            }
        }


        private void SetHoverItem (InvItem item)
        {
            hoverItem = item;

            Menu menu = PlayerMenus.GetMenuWithName (menuName);
            if (hoverItem == null)
            {
                menu.TurnOff ();
            }
            else
            {
                blurbBox.text = item.GetProperty (0).textVal;
                largeImage.texture = item.tex;

                menu.SetCentre (Input.mousePosition);
                menu.TurnOn ();
            }
        }

    }


  • edited February 2018
    Okay so, unfortunately I didn't get this feature done in time for my showcase, but I've re-appraoched this feature since and while I got it to kinda work, it has a few bugs.

    1. The Panel from the tutorial appears around where the mouse hovers over the item than in the centre of the screen like it should. Is the Panel needed? I deleted it from the rectTransform part and nothing seems to have been negatively impacted. I would like the Panel to be a small backdrop around the item & information appearing in the centre behind the image/info instead of off in the corner.

    2. An Image of an Inventory item and Info appears when it's hovered over, however, it's not necessarily the right item. There's a weird bug where, if I'm testing it for the first time since opening Unity, it will only show the first item obtained. After I stop playing the game, it will self-insert all the information saved about the first or last object into the actual prefab's data. Then, upon testing again, it will always show the last object I obtained in my last test when triggered on any inventory object. This will then consistently change and carry on in subsequent tests. Why is this? How do I fix it?

    3. The image scales in accordance to the raw Image size. This can lead to some odd slight stretching issues on each inventory image. Is there any way to make it so it will scale to the raw image component size without distorting its proportions?

    4. Is there a way to disable the function where you can click an inventory item and drag it to wherever? I didn't think much of it at first, but a bunch of my playtesters at my prototype showcase were doing it, so I'd like to disable that. I don't want them clickable.

    Thank you for your help!
  • 1. AC positions Unity UI-based Menus by adjusting the manipulating the assigned "RectTransform boundary".  It's generally good practice to have this assigned, but if you don't want the menu to be repositioned, just remove the "menu.SetCentre" method call in the script.

    2. My guess is that you've assigned the prefab asset itself in the Inspector's "Blurb Box" and "Large Image" fields, which means they'll be update as opposed to the runtime instance.  If the Unity UI is a prefab, and spawned at runtime, then you'll need to set these fields at runtime as well.  One way to do that is to attach Constant ID numbers to the two components in the prefab, and refer to them in the script.  I'll post an updated script below.

    3. You can adjust the largeImage's rectTransform component in the script (after setting the texture), or play around with the various content size components that Unity provides.  That won't involve AC, but you should be able to get some good resources on the Unity forums.

    4. If you still want items to be interactive, just not "selectable", you can create an Use interaction to override the default behaviour when left-clicking.

    using UnityEngine;
    using UnityEngine.UI;
    using AC;

    public class HoverItemProperties : MonoBehaviour
    {

        public string menuName;
        public int blurbBoxConstantID;
        public int largeImageConstantID;

        private Text blurbBox;
        private RawImage largeImage;
        private Menu menu;
        private InvItem hoverItem;


        private void Update ()
        {
            if (KickStarter.runtimeInventory.hoverItem != hoverItem)
            {
                SetHoverItem (KickStarter.runtimeInventory.hoverItem);
            }
        }


        private void SetHoverItem (InvItem item)
        {
            hoverItem = item;

            if (menu == null)
            {
                menu = PlayerMenus.GetMenuWithName (menuName);
                blurbBox = (Text) Serializer.GetGameObjectComponent <Text> (blurbBoxConstantID, menu.canvas.gameObject);
                largeImage = (RawImage) Serializer.GetGameObjectComponent <RawImage> (largeImageConstantID, menu.canvas.gameObject);
            }

            if (hoverItem == null)
            {
                menu.TurnOff ();
            }
            else
            {
                blurbBox.text = item.GetProperty (0).textVal;
                largeImage.texture = item.tex;

                //menu.SetCentre (Input.mousePosition);
                menu.TurnOn ();
            }
        }

    }

  • Hey Chris,

    Thanks a lot. Got the hover feature working now. I actually found a different way to centre the menu by making a Vector2D variable and defining its x & y as screen.width & screen.height divided by 2. Seems to work, even without the RectTransform.

    Could you clarify what you mean by your solution to the 4th problem? I don't want the inventory items selectable at all. The only thing I want is for you to be able to hover your cursor over them, which will trigger the menu we've been talking about to show the image and blurb. Nothing should happen if the player clicks/selects the inventory item.
  • The script works by reading the recorded "hoverItem", which is only set if the InventoryBox element is clickable.  If you don't want items to be clickable, but have "hover" properties, then you have two options:

    1) Make the element clickable (as set in the Menu Manager) and then assign an empty ActionList into each item's Use interaction so that clicking it effectively does nothing.

    2) Make the element non-clickable, and hook into the OnMouseOverMenu event to update your UI when mouse-overing the element.  This would be a bit more tricky because you'd have to check the element is correct, then find the item associated with the element's slot.  For more on this topic, see the "Custom events" and "Menu scripting" chapters of the Manul.  If the first option doesn't work out let me know and I can advise on this further.
  • Looks like making empty Use ActionLists works like a charm. Hoping that's the end of this issue.

    Thanks a lot!
  • Okay so one last issue with this feature and then we'll hopefully be done with it. I'm making my game for HTML5/WebGL. Just tested some builds and found a weird issue. The first time I'll hover over an inventory item, the menu will be misaligned, but it will fix itself after I hover over another item. This consistently happens on the first item I hover over at any time during the game.

    Here are some images describing what I'm talking about.
    https://imgur.com/a/Rzxgo

    I've pasted my version of the code here. What should I change? Might it have something to do with my ScreenCentre variable?

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

    public class HoverItemProperties: MonoBehaviour {

        private Text blurbBox;
        private RawImage largeImage;
        public string menuName;

        public int blurbBoxConstantID;
        public int largeImageConstantID;

        private Menu menu;
        private Vector2 screenCentre;
        private InvItem hoverItem;

        private void Update ()
        {
            screenCentre.x = Screen.width / 2;
            screenCentre.y = Screen.height / 2;

            if (KickStarter.runtimeInventory.hoverItem != hoverItem)
            {
                SetHoverItem (KickStarter.runtimeInventory.hoverItem);
            }
        }
           
        private void SetHoverItem (InvItem item)
        {
            hoverItem = item;


            //Menu menu = PlayerMenus.GetMenuWithName (menuName);

            if (menu == null)
            {
                menu = PlayerMenus.GetMenuWithName (menuName);
                blurbBox = (Text) Serializer.GetGameObjectComponent <Text> (5588554, menu.canvas.gameObject);
                largeImage = (RawImage) Serializer.GetGameObjectComponent <RawImage> (5542272, menu.canvas.gameObject);
            }

            if (hoverItem == null)
            {
                menu.TurnOff ();
            }
            else
            {
                blurbBox.text = item.GetProperty (0).textVal;
                largeImage.texture = item.tex;

                //menu.SetCentre (Input.mousePosition);
                menu.SetCentre (screenCentre);
                menu.TurnOn ();
            }
        }

    }

  • If the menu's always supposed to be in the same place, then you don't need to reposition it with SetCentre - just configure its RectTransform components(s) so that it's in the correct position to begin with.
  • Hi.
    I'm trying to get this code to work but I keep getting "error CS0122: 'Menu.canvas' is inaccessible due to its protection level."

  • edited January 2022
    Replace the script's mentioning ".canvas" with ".RuntimeCanvas" for newer AC versions.
  • Much obliged. That fixed that, but now I keep getting this error when hovering over inventory items:

    NullReferenceException: Object reference not set to an instance of an object
    HoverItemProperties.SetHoverItem (AC.InvItem item) (at Assets/GUI/TooltipUnity/HoverItemProperties.cs:34)
    HoverItemProperties.Update () (at Assets/GUI/TooltipUnity/HoverItemProperties.cs:21)

  • What is on line 34 of your script?

    The ".textVal" will need to be replaced with ".TextValue" as well.

  • Line 34 is: largeImage = (RawImage) Serializer.GetGameObjectComponent (4896362, menu.RuntimeCanvas.gameObject);

    I'm just trying to use it for the RawImage component, so there's no ".textVal" in the script.

  • Is the menu involved on at the time? It needs to be turned on at least once for it to have a RuntimeCanvas. Otherwise, you'll need to wrap a check around it, i.e.:

    if (menu.RuntimeCanvas)
    {
        largeImage = (RawImage) Serializer.GetGameObjectComponent (4896362, menu.RuntimeCanvas.gameObject);
    }
    
  • edited January 2022

    I'm afraid I don't understand what you mean by "Is the menu involved on at the time?". I tried what you suggested above, but it keeps returning a Null Reference again. I probably put it in the wrong place as I'm not really scripting savvy. Here's the full code:

    using UnityEngine;
    using UnityEngine.UI;
    using AC;

    public class HoverItemProperties : MonoBehaviour
    {

    private RawImage largeImage;
    public string menuName;
    
    public int largeImageConstantID;
    
    private Menu menu;
    private InvItem hoverItem;
    
    
    private void Update ()
    {
        if (KickStarter.runtimeInventory.hoverItem != hoverItem)
        {
            SetHoverItem (KickStarter.runtimeInventory.hoverItem);
        }
    }
    
    
    private void SetHoverItem (InvItem item)
    {
        hoverItem = item;
    
        if (menu.RuntimeCanvas)
        {
            menu = PlayerMenus.GetMenuWithName (menuName);
    
            largeImage = (RawImage) Serializer.GetGameObjectComponent <RawImage> (4896362, menu.RuntimeCanvas.gameObject);
        }
    
        if (hoverItem == null)
        {
            menu.TurnOff ();
        }
        else
        {
            largeImage.texture = item.tex;
            menu.TurnOn ();
        }
    }
    

    }

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.