Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Duplicating Unity's mystic Interface power

Tags:

unity3d

Unity3D has an interface like this, for any Component on a MonoBehavior you just do this:

public class LaraCroft:MonoBehaviour,IPointerDownHandler
  {
  public void OnPointerDown(PointerEventData data)
        {
        Debug.Log("With no other effort, this function is called
        for you, by the Unity engine, every time someone touches
        the glass of your iPhone or Android.");
        }

You do not have to register, set a delegate or anything else. OnPointerDown (the only item in IPointerDownHandler) gets called for you every single time someone touches the screen.

Amazing!

Here's a similar interface I wrote ...

public interface ISingleFingerDownHandler
    {
    void OnSingleFingerDown();
    }

Now, I want consumers to be able to do this...

public class LaraCroft:MonoBehaviour,ISingleFingerDownHandler
    {
    public void OnSingleFingerDown(PointerEventData data)
        {
        Debug.Log("this will get called every time
        the screen is touched...");
        }

Just to recap, using Unity's interface, the function gets called automatically with no further effort - the consumer does not have to register or anything else.

Sadly, I can achieve that only like this:

I write a "daemon" ..

public class ISingleFingerDaemon:MonoBehaviour
    {
    private ISingleFingerDownHandler needsUs = null;
    // of course that would be a List,
    // just one shown for simplicity in this example code

    void Awake()
        {
        needsUs = GetComponent(typeof(ISingleFingerDownHandler))
                                       as ISingleFingerDownHandler;
        // of course, this could search the whole scene,
        // just the local gameobject shown here for simplicity
        }

    ... when something happens ...

        if (needsUs != null) needsUs.OnSingleFingerDown(data);


    }

And I get that daemon running somewhere.

If you're not a Unity user - what it does is looks around for and finds any of the ISingleFingerDownHandler consumers, keeps a list of them, and then appropriately calls OnPointerDown as needed. This works fine BUT

  • the consumer-programmer has to remember to "put the daemon somewhere" and get it running etc.

  • there are obvious anti-elegancies whenever you do something like this (in Unity or elsewhere), re efficiency, placement, etc etc

• this approach fails of course if a consumer comes in to existence at a time when the daemon is not searching for them (Unity's magic interfaces don't suffer this problem - they have more magic to deal with that)

(PS, I know how to write an automatic helper that places the daemon and so on: please do not reply in that vein, thanks!)

Indeed, obviously the developers at Unity have some system going on behind the scenes, which does all that beautifully because "their" interfaces are perfectly able to call all the needed calls, regardless of even items being created on the fly etc.

What's the best solution? Am I stuck with needing a daemon? And perhaps having to register?

(It would surely suck - indeed generally not be usable in typical Unity projects - to just make it a class to inherit from; that type of facility is naturally an interface.)

So to recap, Unity has this:

public class LaraCroft:MonoBehaviour,IPointerDownHandler

Surely there's a way for me to make a replacement, extension, for that...

public class LaraCroft:MonoBehaviour,ISuperiorPointerDownHandler

which can then be used the same way / which shares the magic qualities of that interface? I can do it fine, but only my making a daemon.

Update

Full solution for "ISingleFingerHandler" "IPinchHandler" and similar concepts in Unity is here: https://stackoverflow.com/a/40591301/294884

like image 555
Fattie Avatar asked Mar 10 '23 16:03

Fattie


1 Answers

You say you don't want to do a daemon but that is exactly what Unity is doing. The StandaloneInputModule class that is automatically added when you add a UI component is that daemon.

enter image description here

What you can do is create a new class derived from one of the classes derived from BaseInputModule (likey PointerInputModule for your case) that can handle listening to trigger and raising your extra events then add that new class to the EventSystem object.

See the Unity manual section on the Event System for notes on how to create your custom events and more details on what the input module does.

like image 185
Scott Chamberlain Avatar answered Mar 28 '23 11:03

Scott Chamberlain