Search Unity

  1. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice
  2. Unity is excited to announce that we will be collaborating with TheXPlace for a summer game jam from June 13 - June 19. Learn more.
    Dismiss Notice
  3. Dismiss Notice

[Released] ProTips - Tooltip System for UGUI

Discussion in 'Assets and Asset Store' started by zangad, Aug 25, 2015.

  1. zangad

    zangad

    Joined:
    Nov 17, 2012
    Posts:
    361
    Hi @Derptastic,

    Thanks for the screenshots. I played around with our demo scene (#3, the World Object one) to see if I could reproduce the camera angle issue, but I wasn't able to reproduce it on my end. One question - is the canvas that's rendering your tooltips (the GuiCanvas in TooltipManager at runtime) set to ScreenSpace-Overlay, ScreenSpace-Camera, or ScreenSpace-World?

    One thing I would check is to see if the tooltip is visible somewhere in the scene, but maybe something is covering it up, or maybe its position is wrong and it's off the screen. First, set your tooltip to Stays Open (a checkbox on the TooltipTrigger script). Then, run your scene and hover over the tooltip trigger. Now, switch to Scene view and locate your tooltip in the heirarchy under the Tooltip Container object. The tooltip will be enabled like in the screenshot below if it is getting triggered correctly.



    Click in the scene window and press 'F' to quickly navigate to the currently selected game object (the tooltip in this case). Check to see if the tooltip is there and enabled/visible. If so, what is it's location? Is it off the screen or behind something where the camera can't render it?

    If it's positioned wrong, one thing to turn off is the Canvas Overflow Protection on the TooltipManager. This will simplify the troubleshooting because ProTips will skip the step where it makes a second pass to flip the position of the tooltip if it's determined to be off the screen.

    From this point, we should know (A) whether the tooltip was triggered properly and is visible in the scene but not in the game for some reason (like it's underneath/behind an object or it's positioned off the screen) or (B) the tooltip was not triggered properly (it is disabled under the Tooltip Container) for some reason. If (B) is found to be the case, I would put a breakpoint in the OnPointerEnter method of the TooltipTrigger.cs script and make sure it's firing when the camera angle is rotated. It could be that there's something blocking raycasts to your 3D object - maybe the camera clipping is too close?

    Anyway, I hope this helps. If you're still stuck after these steps and nothing jumps out as the culprit, feel free to send us a link to your project uploaded to OneDrive/DropBox/etc (send to modelsharkstudio@gmail.com) and we'll take a look at it.
     
  2. Derptastic

    Derptastic

    Joined:
    Mar 11, 2017
    Posts:
    15
    Hey, @zangad, thank you for the quick response!

    So in that order - My canvas is Screen Space - Overlay.
    As for the tooltip, it seems to be a case of B) Not showing up at all. And apparently, for 3D objects it's not OnPointerEnter, but OnMouseOver event that gets triggered. And here's the clutch, when at a certain angle, it doesn't get triggered at all.

    In that case, however, it's my problem, as it's a Unity event, and not a case of the tooltips misfiring, therefore I need to debug that on my end (when the event actually gets called, everything works fine). Thanks for the help!

    As a complete side note, and off topic of my question,
    and really my one grief with the asset - My use case is that the game is multiplayer and my Player's canvas spawns with him, rather than always being in the scene (on account of me not wanting the server to have one).
    This has forced me to make several small but crucial modifications to both TooltipTrigger and TooltipManager, to ensure that I'm calling Initialize manually when ready (and pass the correct canvas and camera), rather than the automatic one, which makes a lot of assumption. Additionally to make sure that the code properly waits for initialization to happen, because TooltipTrigger's Update for example, assumes everything is ready from the get go.

    Since I have all the source code, I've made it work for me, but in general, I would've loved if TooltipManager has a built-in option to be manually initialized (and disable the automatic) and for the TooltipTriggers to take that into account, since now I have to make sure I go through all changes when updating the asset, to make sure mine stay in.
     
    zangad likes this.
  3. zangad

    zangad

    Joined:
    Nov 17, 2012
    Posts:
    361
    Ah - the OnMouseOver() event, not OnPointerEnter() - sorry about that, I was trying to recall it from memory, I should have looked it up. But I'm glad to hear you are closer to finding the root cause of the issue.

    And thanks for the feedback. I agree that making the TooltipManager manually initialized (ie, not assuming it's always in the scene and ready to go) would be an improvement for ProTips. It would provide extra control and make it work for more types of games, but at the cost of another setup step.

    It's always a challenge to make an asset that "just works" out-of-the-box for every customer, but also still allows for extensive customization for each unique use-case. ProTips probably leans more towards "just works", but as you mentioned, that comes at the cost of making a lot of assumptions which just gets in the way when you have a more complex use-case.

    So I've put your suggestion on our to-do list:
    * TODO: Look at changing TooltipManager so it is manually initialized, and change the code so TooltipTriggers don't expect that everything is ready all the time.

    The trick will be figuring out how to do this without sacrificing the easy initial "getting started" setup instructions. Thanks again for your feedback! :)
     
    Derptastic likes this.
  4. PRfsJay

    PRfsJay

    Joined:
    Apr 22, 2021
    Posts:
    15
    Good evening, I have been attempting to use this in VR, but I assume for protips to work it needs to attach to a canvas, yes? so if I wanted tips to pop up on ingame objects in VR each one would need a canvas attached for the tips to work?

    Thank you for your help.
     
  5. zangad

    zangad

    Joined:
    Nov 17, 2012
    Posts:
    361
    Hi @PRfsJay

    Yes, a Canvas component is needed for tooltips to work, since the tooltips are RectTransforms.
     
  6. JimInNH

    JimInNH

    Joined:
    Apr 22, 2019
    Posts:
    6
    I'm using ProTips v1.7.6 with Unity 2021.3.4f1. I've attached tooltips to 3D objects that are added to an inventory when the mouse pointer is close to the 3D objects and then the F key is pressed. The good news is that the tooltips display just fine, and the 3D object disappears and is added to the inventory at the F keystroke, but the tooltip remains onscreen. Do you have a suggestion as to how the tooltip disappears when the 3d object does? Thank you-Jim
     
  7. zangad

    zangad

    Joined:
    Nov 17, 2012
    Posts:
    361
    Hi @JimInNH,

    I was able to reproduce the issue in our demo scene. Thanks for bringing it to our attention. Can you please add this function to your TooltipTrigger.cs script and see if it fixes the issue?

    Add this to \Assets\ProTips\Scripts\Behaviors\TooltipTrigger.cs:

    Code (CSharp):
    1. private void OnDisable()
    2. {
    3.     Tooltip?.Deactivate();
    4. }


    What this does is, if the tooltip trigger object is ever disabled or destroyed, it immediately deactivates the tooltip tied to it. This fix will be in future versions of ProTips.

    Please let me know if it doesn't solve the issue for you! :)
     
  8. JimInNH

    JimInNH

    Joined:
    Apr 22, 2019
    Posts:
    6
    Sorry for the delayed response - yes - it absolutely works. Thank you for the help.
    Jim
     
    zangad likes this.
  9. WizardGameDev

    WizardGameDev

    Joined:
    Jul 25, 2012
    Posts:
    62
    Greetings! I've had good luck with ProTips until I started trying to use it within prefabs. I have stat modifiers that I create dynamically from a prefab. Each one of them has a tooltiptrigger. When it creates them the first time all works fine. But when in my game I shift to another character and I have to destroy and the re-create the prefabs again I get MissingReference Exceptions. It is like the tooltiptrigger is tied up with instances of the manager and so when it is destroyed it isn't really destroyed. I've tried setting tooltip to null before destroying the component but it is like wack-a-mole.

    Can you give me a process for best how to use Protips within prefabs that are initalized and destroyed?
     
  10. WizardGameDev

    WizardGameDev

    Joined:
    Jul 25, 2012
    Posts:
    62
    I tried to edit my previous post but this forum is a bit buggy in chrome I think.

    So I ended up solving this by just using a simple pooling design so I never have to destroy the prefabs.

    Instead I just keep a list of gameobjects as I instantiate them and when clearing them instead of using destroy I simply set my data object on them to null and set active to false.

    I'd still like to know of how I could just destroy the gameobjects though as it makes it easier when prototyping not to have to setup a pooling system. I also could see a situation where I really would want to destroy them and not have them hanging around.
     
  11. zangad

    zangad

    Joined:
    Nov 17, 2012
    Posts:
    361
    Hi @WizardGameDev,

    I'm glad you were able to find a workaround to the issue.

    I tried to reproduce the issue in my project, but wasn't able to. I setup a simple script that creates tooltip triggers from a prefab, and it also destroys all the tooltip triggers under the gameobject it created them under.

    Here's a video of me creating and destroying TooltipTriggers from the buttons, and below is the script for the Add/Remove buttons.



    Code (CSharp):
    1. public void AddTooltipFromPrefab()
    2. {
    3.     // Load the button prefab from Resources.
    4.     GameObject buttonPrefab = Resources.Load<GameObject>("DynamicObjWithTooltip");
    5.     if (buttonPrefab != null)
    6.     {
    7.         // Assuming the prefab exists, instantiate the button and set its parent.
    8.         Instantiate(buttonPrefab, tooltipTriggerButtons.transform, false);
    9.     }
    10. }
    11.  
    12. public void DeleteTooltipFromPrefab()
    13. {
    14.     TooltipTrigger[] triggers = tooltipTriggerButtons.GetComponentsInChildren<TooltipTrigger>();
    15.     foreach (TooltipTrigger trigger in triggers)
    16.     {
    17.         Destroy(trigger.gameObject);
    18.     }
    19. }
    Since I can't seem to get the error to happen on my end, I'm thinking there must be something more to it. Is there perhaps a Canvas on your prefabs, that might cause the tooltip container object to attach itself under that canvas, and then it's getting deleted along with the prefab, or something like that? I'd probably need to see what all is included in the prefab, or know where the error is happening (the specific error and line number). Or if you could post the code you're using to instantiate and destroy the prefabs, that might help.

    Otherwise, please feel free to zip up your project and upload it to a cloud hosting service (like DropBox, Google Drive, OneDrive, etc) and send a link to modelsharkstudio@gmail.com, and I'll take a look at it and see if I can figure out what's going on. Or if there's some other way you can think of that I can reproduce the issue on my end (in our demo scene, for instance) that would help.
     
  12. WizardGameDev

    WizardGameDev

    Joined:
    Jul 25, 2012
    Posts:
    62
    Many thanks for the quick reply. I'm not sure why mine was breaking as I was doing exactly the same code as the DeleteTooltipFromPrefab you provided earlier. There will be other places in my project were I will need to initialize and delete the triggers so I'll try it again with that method. I'll check out the demo scene as well.
     
  13. zKici

    zKici

    Joined:
    Feb 12, 2014
    Posts:
    441
  14. zangad

    zangad

    Joined:
    Nov 17, 2012
    Posts:
    361
    Hi @zKici,

    Thanks for bringing the PDF issue to our attention. It turns out our whole website (www.modelshark.com) was down because of an SSL certificate issue. I re-installed the certificate and the PDF (and website) seem to be working fine now.

    Yes, ProTips is still being supported. We get multiple requests per week for support, most of which are handled through direct emails to modelsharkstudio@gmail.com. We are also very active on this forum and our ModelShark YouTube channel, so don't hesitate to reach out to us if you need assistance.

    Regarding updates, we only update ProTips when there are breaking bugs or when we have accumulated significant changes to make a large update. ProTips is fairly mature at this point and not much has changed with the way Unity UI and the Canvas works in the last year.
     
    zKici likes this.
  15. johnclearybl

    johnclearybl

    Joined:
    Jan 10, 2021
    Posts:
    3
    Hi there, just purchased your asset and liking it so far.
    I appreciate you don't appear to provide this functionality out of the box but was wondering if you had any tips for the most sensible way to go about extending your code to achieve the following:

    I want mullti-level tooltips on top of tooltips - so e.g. player mouse hovers UI image, gets a tooltip containing some info, which locks in place (say on middlemouse button click while tooltip 1 is displaying), allowing player to freely mouseover TMPro text links in tooltip 1, which themselves display e.g. tooltip2 and tooltip 3, (potentially containing even more TMP link text and leading to tooltips 4, 5 etc. (although for most of my purposes I will need at most one level of children) While at any stage, another mouse middle button input would unlock and resume fade behaviour for the original parent tooltip, and all the children.

    I want to maintain compatibility with the asset as far as possible so I've tried altering your demo TMPro links class implementing OnPointerClick like this, while passing in links with rich texts to the text of the scriptable object Tooltipdata so that the original data for tooltip 1 which is passed looks like this:
    This is a <color=green><link="primary">primary</link></color> link.
    This is another <color=orange><link="primarytwo">anotherprimary</link></color> one.

    then in the database the text for the primarytwo link is:
    which itself contains a <link="secondary"> secondary link</link>

    Code (CSharp):
    1.  
    2.         public void OnPointerClick(PointerEventData eventData)
    3.         {
    4.  
    5.             if (eventData.button == PointerEventData.InputButton.Middle)
    6.             {
    7.                 bool isHoveringOver = TMP_TextUtilities.IsIntersectingRectTransform(pTextMeshPro.rectTransform, Input.mousePosition, pCamera);
    8.                 bool isOverLink = TMP_TextUtilities.FindIntersectingLink(pTextMeshPro, Input.mousePosition, pCamera) != -1;
    9.                 if (isHoveringOver && !isOverLink && tooltipTrigger.Tooltip != null)
    10.                 {
    11.  
    12.                     tooltipTrigger.Tooltip.IsBlocking = false;
    13.                     tooltipTrigger.Tooltip.StaysOpen = true;
    14.                     GameObject go = new GameObject("childtooltipGO");
    15.                     go.transform.parent = tooltipTrigger.gameObject.transform;
    16.                     TooltipTrigger tooltiptrigger2 = go.AddComponent<TooltipTrigger>();
    17.                     tooltiptrigger2.tooltipStyle = defaultTooltipStyle;
    18.  
    19.                     // Set some extra style properties on the tooltip
    20.                     tooltiptrigger2.minTextWidth = 280;
    21.                     tooltiptrigger2.maxTextWidth = 400;
    22.                     tooltiptrigger2.backgroundTint = Color.white;
    23.                     tooltiptrigger2.tipPosition = TipPosition.MouseTopRightCorner;
    24.                     go.SetActive(true);
    25.  
    26.                     // This tooltip will be activated through code, so turn off the default OnMouseHover behavior.
    27.                     tooltiptrigger2.isRemotelyActivated = true;
    28.  
    29.                     LinkData linkData = GetLinkData();
    30.                     List<ToolTipData> ToolTipList = Vault.GetAll<ToolTipData>();
    31.                     for (int i = 0; i < ToolTipList.Count; i++)
    32.                     {
    33.                         if (linkData.Id == ToolTipList[i].Title)
    34.                         {
    35.                             ToolTipData toolTip = ToolTipList[i];
    36.                             tooltiptrigger2.SetText("BodyText", toolTip.Description);
    37.                             tooltiptrigger2.StartHover();
    38.                         }
    39.                     }
    40.                 }
    41.  
    42.  
    43.  
    44.  
    45.             }
    46.         }
    47. )
    At the back end I have a list of Tooltip textdata in a scriptable object database and I dont have an issue connecting the data to the tooltips, but its in between I am wondering what is the best way to proceed - particularly as it seems the asset currently assumes there will only be one tooltip active at any one time - any ideas? The code above does not produce a second tooltip on top of the first. It will lock the first tooltip but not produce children. Any help would be appreciated

    Thanks
     
    Last edited: Nov 4, 2022
  16. zangad

    zangad

    Joined:
    Nov 17, 2012
    Posts:
    361
    Hi @johnclearybl,

    I think I can help get you over this hump, the issue of multiple tooltips not showing at the same time.

    First off, there is a section of code in TooltipManager.cs that prevents multiple tooltips from being shown at the same time. You'll want to comment out that code so you can display more than one at a time.



    That alone won't fix the problem, because ProTips is designed to only instantiate one of each Tooltip Style and re-use that one instance over and over. So to get around that, you can just make copies of your Tooltip Style. So for example, if you want 4 of the same tooltip style to be visible at once, just copy that tooltip style 4 times and give it different names:



    And lastly, you just need to check "Stays Open" on your tooltip triggers, which you're already doing in your code. So you should be able to have multiple tooltips open at the same time after that. I wrote a quick script to create 4 dynamic tooltip triggers with an Add button. Each one points to a different copy of the TooltipStyle (above). Here's the results:



    Hopefully this gets you past that hurdle. If you can't get it working, let me know and I can send you the project I worked on for the illustration above.
     
  17. johnclearybl

    johnclearybl

    Joined:
    Jan 10, 2021
    Posts:
    3
    Thats great, thanks so much for the quick response. At work now but will dig into this tonight, if I can't get the hang of it I will come back to you. 5 star review coming your way on the asset store too!
     
  18. johnclearybl

    johnclearybl

    Joined:
    Jan 10, 2021
    Posts:
    3
    Hey, just a couple of more questions. And sorry I dint have the project on my laptop and wont get in front of it until this evening so may be misremembering how your classes work.

    Did you need to do anything special, e.g. with the sort order or layer of the dynamic tooltips in your example to ensure the latest tooltip displays on top of the previous one? Like, if you were to click the dynamic tooltip buttons right to left instead of left to right would the last one instantiated display on top or underneath the others?



    At runtime, plan is -as follows to get the child links/new tooltips to come themselves from TMPro links - if any of this doesnt make sense to you, or if you have any suggestions would really appreciate it.

    Pseudo:

    ,OnPointerClick:
    if trigger1.tooltip isactive and showing
    OnMiddlebuttonclick call MakeTrigger2

    MakeTrigger2
    set trigger1 or parent to staysopen.
    instantiate a new gameobject and add a tooltiptrigger to it
    make the new gameobject for trigger2 a child of the gameobject holding trigger1,
    .(maybe adding a horizontal layout group with child force expand to ensure that the newGO holding trigger2 is at least as big as trigger1)OR double the offset, override the display location?


    OnHoverTrigger2
    if
    trigger1.tooltip is active, trigger2.tooltip isnotactive, and TMP TextUtils intersecting link is true
    {
    Call TMP TextUtils Link intersectig and match with key in SO database
    Set text trigger2.tooltip to text from database
    begin Hover() trigger2
    }
    otherwise return

    OnPointerExit
    {
    set trigger1 to deactivate
    Maybe find all active trigger tooltips in the scene and call deactivate on them?
    End Hover trigger2
    }
     
  19. zangad

    zangad

    Joined:
    Nov 17, 2012
    Posts:
    361
    Hey @johnclearybl,

    You can control the sort order of the multiple open tooltips by adding the following line of code to the Tooltip Manager, in the Show() method. This will force the last tooltip triggered to be the one on top.

    TooltipManager.cs => Show() method


    Hope that helps!
     
  20. EpicMcDude

    EpicMcDude

    Joined:
    Apr 15, 2013
    Posts:
    117
    Hi Zangad,

    Does this asset only work with Buttons? I have some UI elements that are just text with the option next to them in a settings menu (toggle, dropdown, slider etc) but I would like to have the pop-up whenever the user hovers over the text UI element. Is this possible?
     
  21. zangad

    zangad

    Joined:
    Nov 17, 2012
    Posts:
    361
    Hi @EpicMcDude,

    ProTips works with more than buttons. As long as your canvas has a GraphicsRaycaster on it (it does by default), then anything under the canvas that blocks raycasts can be used as a tooltip trigger.

    For example, text and TextMeshPro elements block raycats, as well as images, including things like canvas panels and control elements such as buttons/toggles/etc. So, almost anything on the canvas can be used as a tooltip trigger.
     
    EpicMcDude likes this.
  22. nurhidayahhamri

    nurhidayahhamri

    Joined:
    Apr 1, 2023
    Posts:
    2
    Hi, I want to ask regarding the tooltip.

    How can I design my tooltip like in this video? so when I point to the different object it will popup different information in the tooltip
     
  23. zangad

    zangad

    Joined:
    Nov 17, 2012
    Posts:
    361
    Hi @nurhidayahhamri

    The data that populates the tooltip in that video comes from the EquipmentItem.cs script that is on the tooltip trigger object.

    If you look at the 2. ProTips Demo scene and click on the armor in Scene View, you will see the Equipment Item script (see image below).

    upload_2023-5-10_16-10-20.png

    The data for your tooltips may come from someplace different, like a database or a JSON file, but regardless of where the data comes from, there are really just two things you need to do to set the text on a tooltip dynamically:
    (1) Get a reference to the tooltip trigger you are interested in setting text on, and
    (2) Set the text for that tooltip trigger based on your data.

    If you look at the EquipmentItem.cs script, most of the work is done in these few lines of code:

    (1) Get a reference to the tooltip trigger on the current game object
    TooltipTrigger = gameObject.GetComponent<TooltipTrigger>();

    (2) Set the text on the tooltip trigger based on the data in the EquipmentItem script
    TooltipTrigger.SetText("TitleText", String.Format("{0} ({1})", itemName, itemType));
    TooltipTrigger.SetText("Stats", GetStatsText(this));
    TooltipTrigger.SetImage("ItemImage", Image.sprite);

    ... and so on

    So really how you accomplish this depends on where the data for your tooltip comes from. If you can give me some more details about your project and where your tooltip data is coming from, I can try to provide more specific assistance. I hope this helps!
     
    Duffer123 likes this.
  24. nurhidayahhamri

    nurhidayahhamri

    Joined:
    Apr 1, 2023
    Posts:
    2
    Hi @zangad , Thank you for the explanation.

    I want to display the image using a tooltip. So when I point to the 3d object, it will display the image that I already created. Right now I already set the sprite in the tooltip but I have an error in the function **HideToolTip**. In this function, I want to hide the image when the arrow/cursor is away from the object.

    **------TooltipManager Script-----**
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using TMPro;

    public class TooltipManager : MonoBehaviour
    {
    public static TooltipManager _instance;

    public Image imageComponent;

    //public SpriteRenderer imageComponent;
    // SpriteRenderer spriteRenderer = gameObject.GetComponent<SpriteRenderer>();

    private void Awake()
    {
    if (_instance != null && _instance != this)
    {
    Destroy(this.gameObject);
    }
    else
    {
    _instance = this;
    }
    }

    // Start is called before the first frame update
    void Start()
    {
    Cursor.visible = true;
    gameObject.SetActive(false);
    }

    // Update is called once per frame
    void Update()
    {
    transform.position = Input.mousePosition;
    }

    public void SetAndShowToolTip(Sprite Image)
    {
    gameObject.SetActive(true);
    imageComponent.sprite = Image;
    }

    public void HideToolTip()
    {
    gameObject.SetActive(false);
    imageComponent.sprite = Sprite.Destroy();
    }

    }
    Right now, I have an error in **HideToolTip** function.
    **------Tooltip Script-----**
    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;

    public class Tooltip : MonoBehaviour
    {
    public Sprite Image;

    private void OnMouseEnter()
    {
    TooltipManager._instance.SetAndShowToolTip(Image);
    }

    private void OnMouseExit()
    {
    TooltipManager._instance.HideToolTip();
    }
    }
     
  25. zangad

    zangad

    Joined:
    Nov 17, 2012
    Posts:
    361
    You mentioned you have an error in the HideToolTip function. What is the error you're getting?
     
  26. wechat_os_Qy07oG6LBuLwxrt0ao4ZkEwPc

    wechat_os_Qy07oG6LBuLwxrt0ao4ZkEwPc

    Joined:
    Jun 28, 2021
    Posts:
    22
    How to deal a Canvas on the prefabs? A case is the canvas on the Dropdown component. It's very common case.
     
  27. zangad

    zangad

    Joined:
    Nov 17, 2012
    Posts:
    361
    Hi there,

    I'm not sure I understand the question, but hopefully I can help. There is an example of how to use ProTips with a dropdown component in the "2. ProTips Demo" scene:

    upload_2023-7-24_12-39-45.png

    Please let me know if this isn't what you're asking about.
     
  28. dulinieck

    dulinieck

    Joined:
    May 27, 2021
    Posts:
    28
    Hi @zangad
    we already talked about idea I have in DestroyIt thread but here seems the better place to continue it.
    So my suggestion is that it would be great to have ProTips functionality for 3d objects (as in demo 3. 3D world object demo) not only based on cursor of mouse as is now but also i.e. if cursor is disabled and/or if additional "switch variable" is enabled in TooltipManager.
    Detection would be active for center of screen (maybe with additional Vector2 shift correction if in our game "center of screen" is not the same place as "crosshair" or "crosshair" is "floating" when i.e. steering the ship, seems like "Vector2 shift" would have to be also added in TooltipManager as public).
    I do not know how your asset works inside, but to me it looks like in place where you detect mouse position, you needed just add in some cases (when mouse cursor is disabled and/or when check in TooltipManager is enabled) switching to "center of screen + Vector2 shift" and then work as now, so check if any 3d object with ProTip is targeted (probably raycasted).

    What do you think about this idea?
    I think that this alternative way of detection when Tip should be triggered would add a lot of flexibillity to your asset. ProTips could be used as kind of functionality for any statuses in fps games as i.e. in no mans sky
     

    Attached Files:

    • nms.png
      nms.png
      File size:
      976.7 KB
      Views:
      54
    Last edited: Aug 18, 2023
  29. zangad

    zangad

    Joined:
    Nov 17, 2012
    Posts:
    361
    Hi @dulinieck,

    Thanks for posting your question here. Like I mentioned over on the DestroyIt thread, there is a demo scene in ProTips "10. Tooltip Position Override". In that demo, it demonstrates how to have the tooltip follow a transform or a vector. You would just assign your tooltip to follow the crosshair transform - you don't need to assign it to a mouse pointer.

    You just check "Override Position" on the TooltipTrigger component, and select what you want the tooltip to attach itself to.

    upload_2023-8-18_16-38-17.png

    So in the example above, the tooltip will appear anchored at vector X:1011, Y:508, Z:0. And this value can be assigned at runtime, so you can do some simple screen vector math (divide X and Y by 2) to find out what the center of the screen is, then plug that value into the TooltipTrigger component, and it will anchor the tooltip to that vector. Hope that helps! :)
     
  30. dulinieck

    dulinieck

    Joined:
    May 27, 2021
    Posts:
    28
    I understand how to use override to make i.e. "common/constat position" for tooltips.
    But I think you did not understand my question or I do not understand how your asset works.
    The question is how your asset works to detect that tooltip should be at all displayed?
    I understand it is handled by "TooltipManager", and it checks cursor position, but what if there is no cursor?
    The game runs in FPP mode and there is no cursor - there is only crosshair in the middle of screen, and 3d objects with assigned TooltipTrigger.
     
  31. zangad

    zangad

    Joined:
    Nov 17, 2012
    Posts:
    361
    Hi @dulinieck

    The way ProTips knows that a tooltip should be displayed is either through mouse events or invoked directly through code using the Popup() function. Both of these methods are handled in the TooltipTrigger component. So, a cursor is not necessary for displaying a tooltip.
     
  32. dulinieck

    dulinieck

    Joined:
    May 27, 2021
    Posts:
    28
    so I should invoke Popup() from script TooltipTrigger when I decide to show popup for 3d object - right?
     
  33. Theta_

    Theta_

    Joined:
    Jun 20, 2019
    Posts:
    12
    Hello,

    I'm using protips in a card game and used it to add tooltips at different places of my game without any issues.

    But when I tried to add tooltips to the in-game card objects, the positions where completly wrong.

    The problems seems to comes from the fact that I change the position of world space canvases at runtime.

    In your world space canvas test scene, when I change the tip position to right middle, start the game, then manually change the position and rotation of the world space canvas (the canvas itself, not the button inside the canvas), the same problem happens.

    In the scene view, the tooltips appears at the right world space position. But in the game view, its position in the overlay is wrong.



    Can you fix this bug? Or explain me how to workaround this problem?

    I tried displaying the tooltips in the cards canvases. It fixes the position problems. But swithching the manager's canvas at runtime doesn't seems to be fully supported and causes new issues.
     
    Last edited: Jan 25, 2024
  34. Theta_

    Theta_

    Joined:
    Jun 20, 2019
    Posts:
    12
    @zangad
    I experimented more with your world space canvas test scene.

    Actually, it doesn't works at all. The only reason it seems to work is because your world space canvas has the same coordinate as your orverlay canvas. As soon as the position of the world space canvas changes, the tooltips are not displayed at the correct position.

    Weirdly, when using a camera space canvas instead of an overlay, the tooltip position is correct (after adjusting the plane distance to get the right size). But then, the other tooltips don't work anymore (those with triggers in another overlay canvas).
     
  35. zangad

    zangad

    Joined:
    Nov 17, 2012
    Posts:
    361
    Hi @Theta_ ,

    I'm trying to reproduce the issue you're having, but maybe I'm not doing it exactly the same? It seems to work fine for me to change the transform of the World Space canvas at runtime and the tooltip seems to be in the right position. I recorded a video of what I did, so you can compare.

    In this video, I first remove the Overlay Canvas and change the Tooltip Manager so it is set to use the World Space canvas exclusively for tooltips. Then, I change the tooltip position on the button to Left Middle. Then I run the scene and adjust the rotation and position of the canvas.

     
  36. Theta_

    Theta_

    Joined:
    Jun 20, 2019
    Posts:
    12
    Thank you for answering.

    Yesterday I eventually managed to get what I wanted by switching the manager's canvas to the one containing the trigger. It's similar to what you did in your video.

    At first with this solution I had some problem with tooltips that got "stuck" and were not moved after changing the manager's canvas. Disabling "never rotate" fixed it. But in your video you didn't disabled it. I'm not sure why I got this problem and you don't. Anyway I got it working to this is not a big deal.

    The major problem here is the demo scene were the trigger is in a worldspace canvas and the tooltips in an overlay canvas. It does seems to work in your demo but that's because both canvases are at the same position. When they are not the tooltips are not displayed at the correct position.

    Video here:
    (link expires in 48h)
     
  37. tomzigza

    tomzigza

    Joined:
    Aug 4, 2017
    Posts:
    39
    I have an issue to share.
    I have the following elements.
    A UI Canvas
    A UI World View canvas
    UI Elements in the ui canvas
    UI Elements in the world view canvas (Problem guy)
    SpriteRenderers and the like in the world view itself.

    All tooltips work properly with the exception of UI elements inside the world view canvas. They are appearing, but they appear with a position relative to the component they are coming from and not in a relative position to the mouse/canvas that the tooltip Container object is in. Thus they are appearing way off screen. However sprite renderers that are right next to the problem guy but not UI elements have their tooltip show up in the proper place and not beside themself.

    My best guess is it should be using mouse position to position a tooltip and normally it does work but for some reason in this UI element on a canvas not on the same coordinate space as the tooltip container canvas, is failing that and just using the actual position of the object being moused over.
     

    Attached Files:

  38. zangad

    zangad

    Joined:
    Nov 17, 2012
    Posts:
    361
    Hi @tomzigza,

    You're probably right about the coordinate space issue with the tooltip container and multiple canvases. If you can send me your project, I'll take a look at it. Just zip your project up at the root folder level, remove the \Library, \obj, \Temp, \UserSettings, and \bin folders if they exist, and upload it to DropBox/Box/GoogleDrive/OneDrive/etc and send me the link at modelsharkstudio@gmail.com.
     
  39. tomzigza

    tomzigza

    Joined:
    Aug 4, 2017
    Posts:
    39
  40. TolNinef

    TolNinef

    Joined:
    Jan 8, 2024
    Posts:
    4
    Hey, I've send my question below to modelsharkstudio@gmail.com, but my email acts up sometimes and I'm unsure of whether or not the email actually arrived, therefore I'm copy/pasting my email below:

    Hey there,

    First off, I'd like to thank you making the ProTips Unity asset. It's been a great help to my project so far! I am however facing an issue I was hoping to get some help with (take note, I'm a clueless C# noob).

    I have around ~30 gameobjs in my scene active at all times, that also have both a tooltip trigger and auto update tooltip fields script attached to it. A single gameobj has 7 dynamic text fields/fields to update (TMP). So far all is fine and dandy. If I run the game I get around 600 FPS. When I hover over a gameobj that has the tooltip trigger and auto update tooltip fields script attached to it, my FPS drops to 60 FPS (so 1/10th of the normal FPS).
    I've been trying to use the built-in profiler to find the cause, and it looks like my problem is somewhere in the autoupdatetooltipfields script. I am suspecting this part:
    Code (CSharp):
    1. foreach (UpdateField field in fieldsToUpdate)
    2.                 {
    3.                     string pattern = $"<link id=\"{field.Name}\">(.*?)<\\/link>"; // look for a link in the tooltip text with the field name as the ID.
    4.                     string replacementTextData = "";
    5.                     replacementTextData = $"<link id=\"{field.Name}\">{field.tmpData.text}</link>";
    6.                     string replacementText = Regex.Replace(text, pattern, replacementTextData, RegexOptions.None);
    7.                     foreach (Match match in Regex.Matches(text, pattern, RegexOptions.IgnoreCase))
    8.                         text = replacementText;
    9.                 }
    If I comment out this part, the game's FPS is perfect. But because of my inexperience with programming in general, I can't make it work/optimize it.
    I was hoping for some help.
    Thanks!
     
  41. zangad

    zangad

    Joined:
    Nov 17, 2012
    Posts:
    361
    Hi @TolNinef

    I'm glad you posted your question here - I checked my email and didn't see anything from you, then checked my spam folder and bingo, there was your email from May 10th. I'm not sure why your email got marked as spam by Gmail, but yeah I probably wouldn't have ever seen it, so it's good you posted!

    I took a look at it and was able to recreate the issue on my end by duplicating the AutoUpdateTooltip script a bunch of times, plus added several more fields to update, so it would be similar to your situation.

    Reproduce Issue.png

    Then I took a Profiler snapshot of when the tooltip is opened and I could clearly see the issue. Basically, Update() runs every frame, so if you were getting around 600FPS, each of your 30 AutoUpdate scripts was trying to update 7 dynamic fields 600 times a second. Super inefficient, and most likely not needed.

    Here's the profiler baseline before any changes:

    Baseline Before.png

    So I modified the AutoUpdateTooltipFields.cs script with a new field UpdatesPerSecond:

    upload_2024-5-24_18-4-51.png

    So now the script only updates 10 times per second instead of once per frame. This drastically reduced the amount of work the script was doing. And it still seemed plenty responsive to me, but if you try this out and the update seems a little laggy, you can increase the updates per second to 20 and see if that feels better. Basically, the more times per second it updates, the worse performance will be but the more responsive it will seem.

    Here's the profiler after the modification:

    Baseline After.png

    Here's the modified AutoUpdateTooltipFields.cs script if you want to replace yours with this one and try it out. Hopefully it will fix your issue without you needing to change anything with your UI and tooltips. Just copy/paste this code over your version of the file and save:

    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using System.Text.RegularExpressions;
    4. using TMPro;
    5. using UnityEngine;
    6. using UnityEngine.UI;
    7.  
    8. namespace ModelShark
    9. {
    10.     /// <summary>
    11.     /// Put this script on a tooltip trigger. When the tooltip is active for that trigger,
    12.     /// this script will constantly update <link> fields in the tooltip, based on the IDs of the links
    13.     /// and the data fields specified for the link fields.
    14.     /// </summary>
    15.     [RequireComponent(typeof(TooltipTrigger))]
    16.     public class AutoUpdateTooltipFields : MonoBehaviour
    17.     {
    18.         [Tooltip("How many times per second this script should try to update tooltip fields.")]
    19.         public float updatesPerSecond = 10;
    20.  
    21.         [Tooltip("The fields you want to keep updated in your tooltip, along with the source data for the text to update them to. For each of these fields, you need one or more <link> fields in your tooltip text with a matching ID.")]
    22.         public List<UpdateField> fieldsToUpdate;
    23.  
    24.         private TooltipTrigger tooltipTrigger;
    25.         private float _timeSinceLastUpdate;
    26.         private float _updateFrequency;
    27.  
    28.         private void Awake()
    29.         {
    30.             _updateFrequency = 1f / updatesPerSecond;
    31.         }
    32.  
    33.         private void Start()
    34.         {
    35.             tooltipTrigger = gameObject.GetComponent<TooltipTrigger>();
    36.  
    37.             GameObject tooltipContainer = TooltipManager.Instance.TooltipContainer;
    38.             if (tooltipContainer == null)
    39.             {
    40.                 Debug.LogError("Could not find tooltip container. Make sure you have ProTips setup correctly.");
    41.                 Destroy(this);
    42.                 return;
    43.             }
    44.         }
    45.  
    46.         private void Update()
    47.         {
    48.             // Only run this code [updatesPerSecond] times per second.
    49.             _timeSinceLastUpdate += Time.deltaTime;
    50.             if (_timeSinceLastUpdate < _updateFrequency) return;
    51.  
    52.             // If the tooltip for our tooltip trigger is not active and visible, don't try to update it.
    53.             if (!tooltipTrigger.Tooltip.GameObject.activeInHierarchy) return;
    54.  
    55.             foreach (TextField textField in tooltipTrigger.Tooltip.TextFields)
    56.             {
    57.                 string text;
    58.                 if (textField.TextTMP != null)
    59.                     text = textField.TextTMP.text;
    60.                 else
    61.                     text = textField.Text.text;
    62.  
    63.                 if (string.IsNullOrEmpty(text)) continue; // if there is no text in the tooltip, exit.
    64.  
    65.                 foreach (UpdateField field in fieldsToUpdate)
    66.                 {
    67.                     string pattern = $"<link id=\"{field.Name}\">(.*?)<\\/link>"; // look for a link in the tooltip text with the field name as the ID.
    68.                     string replacementTextData = "";
    69.                     replacementTextData = $"<link id=\"{field.Name}\">{field.tmpData.text}</link>";
    70.                     string replacementText = Regex.Replace(text, pattern, replacementTextData, RegexOptions.None);
    71.                     foreach (Match match in Regex.Matches(text, pattern, RegexOptions.IgnoreCase))
    72.                         text = replacementText;
    73.                 }
    74.  
    75.                 if (textField.TextTMP != null)
    76.                     textField.TextTMP.text = text;
    77.                 else
    78.                     textField.Text.text = text;
    79.             }
    80.  
    81.             // Reset the time since last update
    82.             _timeSinceLastUpdate = 0f;
    83.         }
    84.     }
    85.  
    86.     [Serializable]
    87.     public class UpdateField
    88.     {
    89.         [Tooltip("The ID of the <link> field in your tooltip text.")]
    90.         public string Name;
    91.  
    92.         [Tooltip("The Text gameobject you want to use as the data source for this <link> field.")]
    93.         public Text textData;
    94.  
    95.         [Tooltip("The TextMeshPro gameobject you want to use as the data source for this <link> field. This one overrides the Text Data field if both are populated.")]
    96.         public TextMeshProUGUI tmpData;
    97.     }
    98. }
    Note that this isn't the only way to solve the issue. The best way performance-wise would be to change it so it uses events and event listeners, and it only updates the tooltip fields when a "changed" event fires. But that would be a lot of modifications on both the front-end and the code, plus it can be difficult to understand and deduce where updates are coming from, or which elements are listening to which events. But it is another option, and an event system scales really well, so if you're planning on adding a lot more of these auto update tooltips, you might need to go down that route eventually. Hope that helps!
     
    TolNinef likes this.
  42. TolNinef

    TolNinef

    Joined:
    Jan 8, 2024
    Posts:
    4
    WOW!

    Thanks for the incredibly detailed response. This reply had me drooling irl lmao. For a complete beginner like myself this is fully understandable. I implemented your solution and it instantly fixed any fps issues I had before! It also makes complete sense as to why the fps drops were happening in the first place.

    I can't thank you enough for your time. I salute you. *tips hat*
     
    zangad likes this.