Search Unity

Centralized Mouse Manager

Discussion in 'Input System' started by Gerrit_M, Aug 9, 2020.

  1. Gerrit_M

    Gerrit_M

    Joined:
    Aug 9, 2020
    Posts:
    1
    Hello Uniteers,

    I'm on my first Unity project. I have a bit of a programming background, with thusly acquired preconceptions, and may not approach Unity idiomatically. Consider this post to be a request for a sanity check.

    So I've written a central MouseManager, i.e. a MonoBehaviour that in its Update function checks Input for the various mouse states and reacts accordingly. Basically, when a GetMouseButtonDown is registered, a new (custom) MouseEvent is created, which tracks a few things, like the initial mousePosition, the initially hovered GameObject, the duration of the mouse press (through a Stopwatch), etc...


    The initial reason was because the built-in OnDrag method only reacts the left mouse button. I then decided to centralize all mouse handling - as opposed to attaching one or more handling scripts to GameObjects - because
    1. it's seemingly more tidy
    2. provides a central place to enable/disable user input
    3. makes certain actions superior to individual scripts, e.g. dragging one Sprite onto another Sprite and handling the result. I mean, it's possible to do this de-centralized, but the code I produced looked convoluted. And it seemed to violate the Single Responsibility Pattern, i.e. a GameObject should not care where it is dragged and how it might interact with the GameObject it was dropped on.

    I've created two versions of the MouseManager so far. One works with events, where the controller hooks into the MouseManager. The other works by hooking up the controller directly to the MouseManager. I prefer the event one, as it allows multiple controllers to tap into the MouseManager at the same time.

    THE CODE BELOW IS OBVIOUSLY SIMPLIFIED

    Code (CSharp):
    1.  
    2. public class MouseManager: MonoBehaviour
    3. {
    4.     public delegate void LeftMouseDown(MouseEvent e);
    5.     // + many more delegates
    6.  
    7.     public event LeftMouseDown OnLeftMouseDown;
    8.     // + many more events
    9.  
    10.     // custom class that tracks initial mousePosition,
    11.     // elapsed time, etc...
    12.     private MouseEvent e;
    13.  
    14.     void Update()
    15.     {
    16.         // The MouseEvent is finished then the MouseButton
    17.         // is released.
    18.         if (Input.GetMouseButtonUp(0))
    19.         {
    20.             e.Finish();
    21.             OnLeftMouseUp?.Invoke(e);
    22.             e = null;
    23.         }
    24.         // A new MouseEvent starts with the initial click.
    25.         else if (Input.GetMouseButtonDown(0))
    26.         {
    27.             e = new MouseEvent();
    28.             OnLeftMouseDown?.Invoke(e);
    29.         }
    30.         // Continued pressing might be a long press or
    31.         // a mouse drag.
    32.         else if (Input.GetMouseButton(0))
    33.         {
    34.             if (e.DragStatus == 0)
    35.             {
    36.                 if (!e.IsLongPress && e.ElapsedTime() > 1000f)
    37.                 {
    38.                     e.IsLongPress = true;
    39.                 }
    40.                 if (e.PositionDelta() > 100)
    41.                 {
    42.                     e.DragStatus = 1; // dragging. eg. selection rectangle
    43.                     // All sprites should include a WorldObject script
    44.                     // and one of its properties is bool isDraggable
    45.                     if (e.hoveredObj.IsDraggable == true)
    46.                     {
    47.                         e.DragStatus = 2; // dragging an object
    48.                     }
    49.                 }
    50.             }
    51.             else
    52.             {
    53.                 OnLeftMouseDrag?.Invoke(e);
    54.             }
    55.         }
    56.     }
    57. }
    58.  
    Code (CSharp):
    1.  
    2. public class MouseManager1 : MonoBehaviour
    3. {
    4.     // A controller to send MouseEvents to
    5.     [SerializeField] private IController controller;
    6.  
    7.     void Start()
    8.     {
    9.         // controller must either be linked in the editor, or
    10.         // be attached to the same GameObject
    11.         if (controller == null)
    12.         {
    13.             controller = gameObject.GetComponent<IController>();
    14.         }
    15.     }
    16.    
    17.     private MouseEvent e;
    18.  
    19.     void Update()
    20.     {
    21.         if (Input.GetMouseButtonDown(0))
    22.         {
    23.             e = new MouseEvent();
    24.             // DIRECT CALL to the CONTROLLER
    25.             controller.OnLeftMouseDown(e);
    26.         }
    27.     }
    28. }

    Sanity Check:

    Does the above approach make sense? It does work. But is this a way to handle mouse input that seasoned Unity users would approve of? How about the performance?
     
    unity_piRzcWp02ycaIg likes this.