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

OnMouseEnter Hoverable LinePoint Inefficiencies

Discussion in 'Scripting' started by hotshotiguana, Sep 14, 2012.

  1. hotshotiguana

    hotshotiguana

    Joined:
    Aug 1, 2012
    Posts:
    34
    I am creating multiple charts with multiple lines and about 70 points per line using Vectrosity (see attached image). My current solution for creating "hoverable" points (using OnMouseEnter and OnMouseExit to identify hovering) is to instantiate a prefab GameObject with a scale of about (.1, .1, .1) and a BoxCollider for each point. This certainly works, but I have a feeling it is extremely inefficient because for the four charts in the image I am instantiating 840 game objects, where a maximum of one of them is shown at each time.

    $Screen shot 2012-09-14 at 10.01.36 AM.png

    Is there a more efficient way to look at this problem? Maybe saving the world position of each of these points in an array and then in the Update function check if the mouse is within x radius of the point and then create a hover box?

    Any thoughts on this would be greatly appreciated because this inefficiency is only going to get worse as I scale to more lines and more charts.

    Thanks!
     
  2. avidesk

    avidesk

    Joined:
    Sep 12, 2011
    Posts:
    62
    Here is what I do. I think it should be more efficient than your current method, but I'm not 100% sure because I don't use very many lines.

    "Wire" is a class of mine, but that's really not important. wire.points is just my VectorLine point array. (Continuous VectorLine) CheckWire loops through all points in a particular line, distance to wire calculates distance to the line segment made of points l1,l2. What I am looking for is the first line segment I can find that is less than 2px from my mouse cursor, but you could easily adjust this code to measure to individual points instead and return the nearest point.

    Code (csharp):
    1. public int CheckWire(Wire wire)
    2.     {
    3.         for (int i = 1; i < wire.points.Length; i++)
    4.         {
    5.             Vector2 l1 = Camera.mainCamera.WorldToScreenPoint(wire.points[i - 1]);
    6.             Vector2 l2 = Camera.mainCamera.WorldToScreenPoint(wire.points[i]);
    7.             Vector2 point = Input.mousePosition;
    8.  
    9.             float Distance = DistanceToWire(l1, l2, point);
    10.  
    11.             if (Distance < 2)
    12.             {
    13.                 return i;
    14.             }
    15.         }
    16.         return -1;
    17.     }
    18.  
    19.     public float DistanceToWire(Vector2 l1, Vector2 l2, Vector2 p)
    20.     {
    21.         float lSquared = Mathf.Pow(Vector2.Distance(l1, l2), 2);
    22.         float t = Vector2.Dot(p - l1, l2 - l1) / lSquared;
    23.         Vector2 projection = l1 + t * (l2 - l1);
    24.  
    25.         if (lSquared == 0) { return Vector2.Distance(l1, p); }
    26.  
    27.         if (t < 0) { return Vector2.Distance(p, l1); }
    28.         else if (t > 1) { return Vector2.Distance(p, l2); }
    29.  
    30.         return Vector2.Distance(p, projection);
    31.     }
     
    Last edited: Sep 15, 2012
  3. hotshotiguana

    hotshotiguana

    Joined:
    Aug 1, 2012
    Posts:
    34
    avidesk,

    Thanks for the quick reply. Are these functions that you have in the Update() function of a script that you attach as a component to each wire/line that you create?

    If I have a bunch of lines with 70 points each, I wonder if it would be more efficient to store the global position of each point in an array and then at each frame calculate the distance from the mouse cursor until a match is found.

    Chris