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?
Comments
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.
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?
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.
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?
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 ();
}
}
}
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!
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 ();
}
}
}
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.
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.
Thanks a lot!
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 ();
}
}
}
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."
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.:
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
{
}