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

Creating custom event trigger

Discussion in 'UGUI & TextMesh Pro' started by The-Oddler, Aug 30, 2014.

  1. The-Oddler

    The-Oddler

    Joined:
    Nov 26, 2010
    Posts:
    133
    I've been trying to make my own event trigger since I only need the OnPointerUp event. So I made a class that implements the IPointerUpHandler interface and inherits from UIBehaviour (also tried a normal MonoBehaviour), but my OnPointerUp method doesn't get called...

    My code:
    Code (CSharp):
    1. public class SmartText : UIBehaviour, IPointerUpHandler {
    2.     public void OnPointerUp(PointerEventData eventData) {
    3.         Debug.Log(eventData.position);
    4.     }
    5. }
    I attached this to an object with also a Text script on it. What am I doing wrong?

    Thanks!
     
  2. rakkarage

    rakkarage

    Joined:
    Feb 3, 2014
    Posts:
    683
    Use MonoBehaviour instead of UIBehaviour.
     
  3. The-Oddler

    The-Oddler

    Joined:
    Nov 26, 2010
    Posts:
    133
    I tried that, same non-working result :(
     
  4. TeotiGraphix

    TeotiGraphix

    Joined:
    Jan 11, 2011
    Posts:
    145
    Hi,

    Seems to me it needs to be;

    Works for me setup with virtual.

    Mike
     
  5. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    557
    You need to specifically state that you are implementing the interface's OnPointerUp() method.

    Code (csharp):
    1. void IPointerUpHandler.OnPointerUp(PointerEventData eventData){
    2.     Debug.Log(...);
    3.  }
     
  6. TeotiGraphix

    TeotiGraphix

    Joined:
    Jan 11, 2011
    Posts:
    145
    Senshi, is that C# language construct? Still moving my brain from Java but what I did works as well.

    Is your way a construct for a non public interface implementation or something?

    Mike
     
  7. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    557
    @TeotiGraphix I'm actually quite surprised adding the virtual keyword makes it work! Virtual means that the method can be overridden in a derived class using the override keyword. For example:

    Code (csharp):
    1. public class Animal {
    2.     public virtual void MakeSound(){
    3.         Debug.Log("I'm an animal!");
    4.     }
    5. }
    6.  
    7. public class Cat {
    8.     public override void MakeSound(){
    9.         Debug.Log("Meow!");
    10.     }
    11. }
    12.  
    The construct I used is used to implement interface members, specifically. Unfortunately I don't work with C# enough to have a lot more knowledge on the subject that I can explain with any decent amount of certainty. I do know that by stating the interface name explicitly you can implement multiple interfaces that contains members with the same name. For example:

    Code (csharp):
    1. interface ITwitter {
    2.     void Post(string message);
    3. }
    4.  
    5. interface IFacebook {
    6.     void Post(string message);
    7. }
    8.  
    9. class SocialMedia : ITwitter, IFacebook {
    10.     void ITwitter.Post(string message){
    11.         //Twitter API stuff
    12.     }
    13.  
    14.     void IFacebook.Post(string message){
    15.         //Facebook API stuff
    16.     }
    17. }
    18.  
    19. SocialMedia sm = new SocialMedia();
    20. ((ITwitter)sm).Post("Hello world!"); //post to Twitter
    21. ((IFacebook)sm).Post("Hello world!"); //post to Facebook
    Hope this explained things at least somewhat, though I can't explain why your method worked as well.
     
  8. The-Oddler

    The-Oddler

    Joined:
    Nov 26, 2010
    Posts:
    133
    For me nothing works. Making the method virtual doesn't help, nor adding "IPointerUpHandler.". It does however show in the inspector that my SmartText component intercepts the OnPointerUp event. It always shows this, regardless of whether or not I make the method virtual or add "IPointerUpHandler." to it.

    I also tried adding a button to it, just to see if my EventSystem object was working properly, and the button works perfectly.

    Edit: Also tried it with an Image instead of text, doesn't work either.
     
  9. TeotiGraphix

    TeotiGraphix

    Joined:
    Jan 11, 2011
    Posts:
    145
    @Senshi Look at;



    at 25:00, for his OnPointerClick() he has virtual in there and is implementing IPointerClickHandler.

    Maybe sloppy code because he was in a hurry? But heh, I saw this yesterday and the memory led to my post today about virtual. But yeah, its kind of like the abstract word in Java. (It didn't seem right to me).

    But in his implementation of the ISubmitHandler, he just uses public void and no qualified interface name like you have! :)

    Need to brush up again on this language C# stuff.
     
  10. DESTRUKTORR

    DESTRUKTORR

    Joined:
    Jul 4, 2012
    Posts:
    22
    @The Oddler Are you using b18? I had some custom event handlers working in b17 that have stopped responding to pointer input, as well, and I believe they may have stopped working as soon as I updated to b18, but I still need to check my scene over a few more times to be sure.

    EDIT
    Also, if it inherits from UIBehaviour, I'm fairly certain it should be placed inside a Canvas, and you will need to ensure that you have a graphic raycaster, as well.

    If you go the MonoBehaviour route, you will need to add a collider to the object you want to receive the events with, and add a 3d or 2d raycaster (depending on what type of collider you use) to one of the cameras in the scene that receives input.

    Another thing that could be going wrong is that if another object receives the input first, like say, a collider that sits in front of the object your'e trying to click, your object won't receive the proper input, so you may want to set up a separate layer and only have the raycaster cast along that particular layer.

    Hope this helps!
     
    Last edited: Aug 30, 2014
  11. The-Oddler

    The-Oddler

    Joined:
    Nov 26, 2010
    Posts:
    133
    @DESTRUKTORR
    Nope, I'm at b17.
    This is what my hierarchy looks like at the moment. Only just set it up, so there's almost nothing there.

    Thanks for all the help already
     
    Last edited: Aug 30, 2014
  12. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    557
    @TeotiGraphix Huh, well whaddya know! I honestly don't know the rationale behind that to be honest. I might do a bit of digging tomorrow. If I end up finding anything I'll let you know! =)

    @The Oddler Have you tried setting it up with the editor's trigger system as well? I'm curious if it's even receiving the event at this point. I've tried it myself, but I have a custom EventSystem set up atm, so no conclusive results there.
     
  13. The-Oddler

    The-Oddler

    Joined:
    Nov 26, 2010
    Posts:
    133
    @Senshi
    I'm not really sure what you mean or how to set it up. Could you give a link to the documentation or some tutorial?

    Thanks a lot! :D
     
  14. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    557
    @The Oddler Unity has some tutorials up on the subject, but in short in boils down to this:

    - Create "public void Test()" inside your SmartText script and have it print something
    - Add a SmartText GameObject to the scene
    - Click Add Component > Event > Event Trigger
    - Inside that Component click Add New > Pointer Up
    - Next, click the + button
    - Drag your SmartText object (the one the Event Trigger is on) onto the new entry
    - From the dropdown select the SmartText > Test() function
    - Start the game and test the PointerUp event.

    If it works you should see a Log message. This will tell us if your object is even receiving any events to begin with. =)
     
  15. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    557
    I just saw this thread by @vexe describing a problem (possible bug) with OnPointer___ events. Could you try changing
    Code (csharp):
    1. public void OnPointerUp(PointerEventData eventData)
    to
    Code (csharp):
    1. public void OnPointerUp(BaseEventData eventData)
    and see if that fixes anything?
     
  16. The-Oddler

    The-Oddler

    Joined:
    Nov 26, 2010
    Posts:
    133
    @Senshi
    I tried the thing with the Test() method and the event trigger. When I do this, my Test method gets called perfectly. The weird thing though, is that now my OnPointerUp also gets called in the SmartText class... I don't have to add it to the event trigger. If I just add an empty EventTrigger my SmartText component gets the OnPointUp call...

    So it seems the EventTrigger does some setup code or something that I don't know about. Any ideas?

    Thanks!
     
  17. Senshi

    Senshi

    Joined:
    Oct 3, 2010
    Posts:
    557
    @The Oddler D'ow! I never realized this, but it seems an EventTrigger Component is indeed needed for it to work! From the docs:

    "Receives events from the EventSystem and calls regiostered functions for each event."

    Since I've been adding all my triggers through code, my elements already have one by default, so it never occured to me that it might be a prerequisite.
     
  18. Kylotan

    Kylotan

    Joined:
    Feb 17, 2011
    Posts:
    212
    I just found this myself, or at least something very similar : I added a component to my object that implements IPointerClickHandler, and although OnPointerClick does get called when I click the object, the PointerEventData object it gets is not initialised properly and I can't read it to find out what was clicked. Then I added an EventTrigger component to the object... and now the PointerEventData contains the right data!

    This is very weird and counterintuitive!
     
  19. superpig

    superpig

    Drink more water! Unity Technologies

    Joined:
    Jan 16, 2011
    Posts:
    4,649
    I'm going to hazard a guess that there's something happening here like 'OnPointerUp doesn't get called correctly unless the system was able to call OnPointerDown first' or something... by attaching the EventTrigger component, which has an OnPointerDown handler, the system is 'satisfied' and fires things off correctly even though the EventTrigger itself does nothing.

    I imagine the dev team would be highly appreciative if someone could make a little project demonstrating the problem and file a bug, then post the bug number here.
     
  20. Kylotan

    Kylotan

    Joined:
    Feb 17, 2011
    Posts:
    212
    To test that hypothesis, I removed the EventTriggers to see what happens, and I am still seeing OnPointerDown and OnPointerClick both fired, but the PointerEventData does not have 'selectedObject' set. Add the EventTrigger back on the object, and it sets 'selectedObject' correctly. Hope that helps...
     
  21. superpig

    superpig

    Drink more water! Unity Technologies

    Joined:
    Jan 16, 2011
    Posts:
    4,649
    What happens if you implement ISelectHandler or derive your component from Selectable instead of MonoBehaviour?

    From the decompiled code, It looks like 'selectedObject' just gives you whatever was last passed to EventSystem.SetSelectedGameObject() - and the mouse-down code specifically queries for ISelectHandler-providing objects when getting a thing to pass to that.
     
  22. superpig

    superpig

    Drink more water! Unity Technologies

    Joined:
    Jan 16, 2011
    Posts:
    4,649
    Note that I think PointerEventData.pointerPress is what you should use if you want to know 'the object being clicked on' - it's not necessarily going to be selected as a result of that click.
     
  23. Kylotan

    Kylotan

    Joined:
    Feb 17, 2011
    Posts:
    212
    Yeah, I was just guessing that selectedObject was the value I needed, since I was figuring this all out by trial and error. Probably not a bug after all then! I'll switch to .pointerPress, which I can confirm works without an EventTrigger attached - a simple public void OnPointerDown(PointerEventData ped) function in an IPointerDownHandler class works for me.
     
  24. fish-soluble

    fish-soluble

    Joined:
    Nov 8, 2014
    Posts:
    1
    Just wanted to thank DESTRUKTORR for this comment. Unlike the OP I wanted to use the event system interfaces (IPointerDownHandler, etc) with regular MonoBehavior scripts - no Canvas in the scene. This tip was the key.

    To sum up for anyone else who is trying to create a custom UI event trigger, I did the following:
    • Add an EventSystem to the scene.
    • Add a raycaster (I used Physics 2DRaycaster) to my main camera
    • On the object I want to be interactable (in my case a Sprite):
      • add a collider (I used a Box Collider) component
      • add my script:
        • inherit from MonoBehavior and the event interfaces (In my case IPointerDownHandler):
          • Code (csharp):
            1. public class MyScript : MonoBehaviour, IPointerDownHandler
        • implement the event interface:
    Code (csharp):
    1.  
    2.     void IPointerDownHandler.OnPointerDown(PointerEventData eventData)
    3.     {
    4.         Debug.Log("Hit IPointerDownHandler.OnPointerDown");
    5.     }
    6.  
     
    fffMalzbier likes this.