Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

onhover?

Discussion in 'Scripting' started by rainbow_design, Feb 15, 2016.

  1. rainbow_design

    rainbow_design

    Joined:
    Aug 8, 2015
    Posts:
    108
    Hello,
    i have:
    Code (CSharp):
    1.  
    2. newbuild.GetComponent<Button> ().onClick.AddListener (delegate { showinfo(mybuilding); });
    I want somthing like:


    Code (CSharp):
    1.  
    2. newbuild.GetComponent<Button> ().onHover.AddListener (delegate { showinfo(mybuilding); });
    note the onHover.

    Now i know this does not work is there something similar to onHover i can use?
     
    Last edited: Feb 15, 2016
  2. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,741
  3. rainbow_design

    rainbow_design

    Joined:
    Aug 8, 2015
    Posts:
    108
    Hello, thankyou onPointerEnter looks good to me but i have no idea how to implement it in my context since there is no example or description in the documentation.
     
  4. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,741
    and what is your context if you are adding it from a script which is not on the same object you could just add the EventTrigger as a component to your button than do the exact same thing you are doing already for onClick but get the Event Trigger Component and use onPointerEnter.
     
  5. rainbow_design

    rainbow_design

    Joined:
    Aug 8, 2015
    Posts:
    108
    Well OnPointerEnter has no function AddListener...and without AddListener OnPointerEnter takes PointerEventData as Argument.so nothing in that terms would work:

    Code (CSharp):
    1.  
    2.        fmitem.GetComponent<EventTrigger> ().OnPointerEnter.AddListener (delegate { mapclicked (sub); });
    I have no idea how to get PonterEventData or how to use this... or how to get mapclicked executed this way...
     
  6. passerbycmc

    passerbycmc

    Joined:
    Feb 12, 2015
    Posts:
    1,741
    ah sorry thought the event trigger had events on it, since it lets you add events via the UI.

    well i guess you will want to do something like this than in a script on your button.
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.EventSystems;
    3.  
    4. public class BtnTest : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler {
    5.     public void OnPointerEnter(PointerEventData eventData) {
    6.         // do pointer enter stuff
    7.     }
    8.  
    9.     public void OnPointerExit(PointerEventData eventData) {
    10.         // do pointer exit stuff
    11.     }
    12. }
    13.  
    if you needed to add the listner from a other object your could just make your own events in the above script that other things can add listeners to.
    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Events;
    3. using UnityEngine.EventSystems;
    4.  
    5. public class BtnTest : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler {
    6.     public PointerEvent OnEnter = new PointerEvent();
    7.     public PointerEvent OnExit = new PointerEvent();
    8.  
    9.     public void OnPointerEnter(PointerEventData eventData) {
    10.         OnEnter.Invoke(eventData);
    11.     }
    12.  
    13.     public void OnPointerExit(PointerEventData eventData) {
    14.         OnExit.Invoke(eventData);
    15.     }
    16. }
    17.  
    18. public class PointerEvent : UnityEvent<PointerEventData> {}
    19.  
     
    Last edited: Feb 16, 2016
  7. rainbow_design

    rainbow_design

    Joined:
    Aug 8, 2015
    Posts:
    108
    So if i see it right... i should make a new button class?
    Now the button is an instance of a prefab. Can i still use this or do i need to change it?
    Also i need to pass a string to the function with the addlistener and delegate it is clear.
    On the first example it is clear how to call it for me but the second one i dont understand.
    would it look like

    Code (CSharp):
    1. public void OnPointerEnter(PointerEventData eventData,string mystring) {
    ?
    Indeed i would like to just call it like the onclick with a function to be executed with a parameter. So i could just recycle it in other situations.
     
    Last edited: Feb 16, 2016
  8. rainbow_design

    rainbow_design

    Joined:
    Aug 8, 2015
    Posts:
    108
    I just tried it and it does not work. so how can i pass atleast the string?

    Is there maybe a way to add a new function to make it work just like addlistener?
     
  9. xXGrime

    xXGrime

    Joined:
    Aug 19, 2014
    Posts:
    16
    The way I would do this is something like. Not sure if this is the best way to do it but works for me. The button needs a EventTrigger component added to it. Its late for me but this should work.

    Code (CSharp):
    1. using System.Collections.Generic;
    2. using UnityEngine.EventSystems;
    3. public class WhatEverClass : MonoBehaviour {
    4.  
    5.     private GameObject yourButtonObject;
    6.  
    7.  
    8.     // Use this for initialization
    9.     void Start ()
    10.     {
    11.         yourButtonObject = GameObject.Find ("Button Name");
    12.     }
    13.  
    14.     //Call method when needed
    15.     public void PointerHoverOnButton()
    16.     {
    17.         EventTrigger pointerHoverTrigger;
    18.         pointerHoverTrigger = yourButtonObject.GetComponent<EventTrigger> ();
    19.         EventTrigger.Entry yourNewEntry = new EventTrigger.Entry ();
    20.         yourNewEntry.eventID = EventTriggerType.PointerEnter;
    21.         pointerHoverTrigger.triggers.Add (yourNewEntry);
    22.        
    23.         yourNewEntry.callback.AddListener ((eventData) =>
    24.         {
    25.             //Do something when mouse is over button
    26.         });
    27.     }
    28.  
    29. //Call method when needed
    30.     public void PointerExitOnButton()
    31.     {
    32.         EventTrigger pointerExitTrigger;
    33.         pointerExitTrigger = yourButtonObject.GetComponent<EventTrigger> ();
    34.         EventTrigger.Entry yourNewEntry = new EventTrigger.Entry ();
    35.         yourNewEntry.eventID = EventTriggerType.PointerExit;
    36.         pointerExitTrigger.triggers.Add (yourNewEntry);
    37.        
    38.         yourNewEntry.callback.AddListener ((eventData) =>
    39.         {
    40.             //Do something when mouse is no longer over the button
    41.         });
    42.     }
    43.  
    44. }
    45.  
    46.  
    47.  
    48.  
     
    Last edited: Feb 16, 2016
    JDeyby and rainbow_design like this.
  10. rainbow_design

    rainbow_design

    Joined:
    Aug 8, 2015
    Posts:
    108
    I like your code.
    I have attached it to an object which has EventTrigger. and addet a debug entry.
    Sadly the code in
    public void PointerHoverOnButton()

    Seems to never be called...
     
  11. rainbow_design

    rainbow_design

    Joined:
    Aug 8, 2015
    Posts:
    108
    I attach more code so you can understand the context for me it looks terrible complicated

    Code (CSharp):
    1.  
    2.             foreach (string sub in subs) {
    3.                 GameObject mitem = menuitemlocate(folder, pos,g.menuitemsize,sub);
    4.  
    5.  
    6.         private GameObject menuitemlocate(string folder, Vector2 position, Vector2 size, string sub) {//locates a menu and creates one with buildmenu item
    7.            
    8.             if (g.menuobjects.ContainsKey (sub)) {
    9.                 GameObject mfitem = g.menuobjects[sub];
    10.                 mfitem.SetActive (true);
    11.                 mfitem.transform.localPosition = position;
    12.                 return mfitem;
    13.             }
    14.             else {
    15.                 GameObject mfitem = buildmenuitem(sub.Replace(folder, ""),g.menuprefab, size, sub);
    16.                 mfitem.SetActive (true);
    17.                 mfitem.transform.localPosition = position;
    18.                 g.menuobjects.Add (sub, mfitem);
    19.                 return mfitem;
    20.             }
    21.         public GameObject buildmenuitem(String name, GameObject menuprefab, Vector2 scales, string sub) {
    22.             GameObject fmitem = h.Instantiate2 (menuprefab);
    23.             name = name.Replace ("\\", "");
    24.             String image2= sub.Replace (".bui", "");
    25.             fmitem.GetComponent<Image> ().sprite = Resources.Load<Sprite> (image2.Replace (g.pgamesetpath, ""));
    26.             fmitem.name = name;
    27.             fmitem.GetComponent<Button> ().onClick.AddListener (delegate { mapclicked (sub); }); //todo right button handling
    28.             //fmitem.GetComponent<EventTrigger> ().OnPointerEnter.Invoke (delegate { mapclicked (sub); }); //todo right button handling
    29.             fmitem.transform.FindChild ("Text").GetComponent<Text> ().text = name;
    30.             fmitem.transform.localScale = (scales);
    31.             fmitem.transform.SetParent (g.uicanvas.transform, false);
    32.             return fmitem;
    33.         }
     
  12. xXGrime

    xXGrime

    Joined:
    Aug 19, 2014
    Posts:
    16
    I tested the code in a empty project and it seems to work fine for me. The script i posted above can be placed on any object in the scene.

    When the mouse is over fmitem it should print out.

    Code (CSharp):
    1.  
    2.  
    3.     EventTrigger pointerHoverTrigger =  fmitem.GetComponent<EventTrigger> ();
    4.     EventTrigger.Entry yourNewEntry = new EventTrigger.Entry ();
    5.     yourNewEntry.eventID = EventTriggerType.PointerEnter;
    6.     pointerHoverTrigger.triggers.Add (yourNewEntry);
    7.  
    8.     yourNewEntry.callback.AddListener ((eventData) =>
    9.         {
    10.         //Do something when mouse is over button
    11.         print("Mouse over button");
    12.     });
     
    rainbow_design likes this.
  13. rainbow_design

    rainbow_design

    Joined:
    Aug 8, 2015
    Posts:
    108
    Wow i just tested it its really great and works like a charm. You are definitively my Hero of the day :)

     
  14. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    916
    your making this harder than it needs to be. let interfaces be your savior


    take for example that you want a Menu button to show a tooltip when you hover over it.

    Code (CSharp):
    1. public interface ITooltip
    2. {
    3.     void OnHover(Vector2 position);
    4. }
    The interface is there mainly so that we can have wildly different types of classes implement the call to show a tooltip, not just the Building class listed below

    Code (CSharp):
    1. public class Building : MonoBehaviour, ITooltip
    2. {
    3.     public string tooltipDescription;
    4.  
    5.     public void OnHover(Vector2 position)
    6.     {
    7.         Tooltip.Display(position,tooltipDescription);
    8.     }
    9.  
    10.    //bunch of other stuff for the Building class
    11. }
    the Tooltip class I mentioned will be a singleton that instantiates a UI Text gameobject when the static method Display is called, with its box offset from the passed in position. The class will also have a static Clear method that destroys the UItext gameobject

    then your button just needs this MenuItem component attached and the data linked to a prefab with a component that implements a ITooltip
    Code (CSharp):
    1.  
    2. //UI items use the Image component as a "collider" for pointer events
    3. // so this class requires that the gameobject this attaches to also has an Image component
    4. // to properly raise the pointer events.
    5. [RequireComponent(typeof(UnityEngine.UI.Image)]
    6. public class MenuItem: MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
    7.   {
    8.       public GameObject itemPrefab;
    9.       ITooltip tooltipData;
    10.  
    11.       void Awake()
    12.       {
    13.           tooltipData = itemPrefab.GetComponent<ITooltip>();
    14.       }
    15.  
    16.       public void OnPointerEnter(PointerEventData eventData)
    17.       {
    18.            tooltipData.OnHover(eventData.position);
    19.       }
    20.  
    21.       public void OnPointerExit(PointerEventData eventData)
    22.       {
    23.            Tooltip.Clear();
    24.       }
    25.   }
    notice that I ONLY pass in position data inside the OnPointerEnter. The MenuItem class is messing with a ITooltip interface, NOT the Building class, so it doesn't know of any data that its not responsible for. its not supposed to manage the tooltipDescription, its not even allowed to know it even exists. so it never messes with it. this keeps the class extremely flexible, extremely clean, and most of all, decoupled.

    also notice that I'm not adding ANY listeners anywhere. all you need is to add is those two built-in interfaces IPointerEnterHandler, IPointerExitHandler and implement them. You'll also need an EventSystem in the scene (which Unity does automatically if you add any UI element in the scene) and a graphic raycaster on the Canvas (unity also does this automatically).

    with proper use of interfaces, you can not only keep your code very simple, but its also extremely easy to expand. with just the provided interface and Tooltip singleton, you can put a tooltip on nearly anything. buttons for spells, description explaining a stat, a tooltip for an image, or even tooltip pop-ups for looking at in-game 3d objects.
     
  15. rainbow_design

    rainbow_design

    Joined:
    Aug 8, 2015
    Posts:
    108
    To be honest i dont know anything about interfaces. I will have to look over your code several times again in the next time to fully understand it and read some tutorials about interfaces...
    I know my code is complicated or at least different from the standard way of writing. I just started with c# and unity i did use python and kivy before so i am still just happy when it works the way i want it to
     
  16. rainbow_design

    rainbow_design

    Joined:
    Aug 8, 2015
    Posts:
    108
    Does anyone know a good tutorial about using classes and interfaces to manage unity ui items with click and hover?
     
  17. Kiwasi

    Kiwasi

    Joined:
    Dec 5, 2013
    Posts:
    16,860