0

I am building a 3d game in Unity3D, where the use can draw on the ground when he is in top view.

The lines are drawn using the LineRenderer component.

I want to give the use the ability to select the lines he draw so he can delete them. But unfortunately I didn't find a good way to do it. If I am using 3D colliders, the only one that fits is a BoxCollider, but it's too big (I want the collider only on the line).

And I can't use the 2D colliders because they only work on XY plane.

I tried to convert the line into a mesh and just use MeshCollider but the line was too complex and the MeshCollider couldn't fit it self properly on the line.

Do you have any idea how can I do it¿

P.S.

I am selecting objects in the game with Ray casts.

SagiZiv
  • 932
  • 1
  • 16
  • 38

1 Answers1

0

if a MeshCollider is too complex, but a BoxCollider is not precise enough, try using multiple BoxColliders along your line segments.

An implementation can be found here:

https://answers.unity.com/questions/1546512/detect-mouse-click-on-line-renderer.html

If the link ever breaks, here is the code:

 using UnityEngine;
 using System.Collections;
 using System.Collections.Generic;

 [RequireComponent(typeof(LineRenderer))]
 public class LineCollider : MonoBehaviour
 {
     LineRenderer line;
     public void Start() {
         AddCollider(6); //Increase the count of parts(6) if you want to get more detailed collider
     }
     public void AddCollider(int part)
     {
         try
         {
             line = GetComponent<LineRenderer>();
             var start = line.GetPosition(0);
             var end = line.GetPosition(line.positionCount - 1);
             var a = (line.positionCount - 1) / part;
             for (int i = 1; i<=part; i++)
             {
                 if (i == 1)
                     AddColliderToLine(start, line.GetPosition(Mathf.CeilToInt(a * 1)));
                 else if (i == part)
                     AddColliderToLine(line.GetPosition(Mathf.CeilToInt(a * (i - 1))), end);
                 else
                     AddColliderToLine(line.GetPosition(Mathf.CeilToInt(a * (i - 1))), line.GetPosition(Mathf.CeilToInt(a * i)));
             }            
         }
         catch
         {
             Destroy(gameObject);
         }
     }

     private void AddColliderToLine(Vector3 start, Vector3 end)
     {
         var startPos = start;
         var endPos = end;
         BoxCollider col = new GameObject("Collider").AddComponent<BoxCollider>();
         col.transform.parent = line.transform;
         float lineLength = Vector3.Distance(startPos, endPos);
         col.size = new Vector3(lineLength, 0.175f, 0.25f);
         Vector3 midPoint = (startPos + endPos) / 2;
         col.transform.position = midPoint;
         float angle = (Mathf.Abs(startPos.y - endPos.y) / Mathf.Abs(startPos.x - endPos.x));
         if ((startPos.y < endPos.y && startPos.x > endPos.x) || (endPos.y < startPos.y && endPos.x > startPos.x))
         {
             angle *= -1;
         }
         angle = Mathf.Rad2Deg * Mathf.Atan(angle);
         col.transform.Rotate(0, 0, angle);
     }
 }

As an alternative, more performant but harder to implement: Write the lines into a texture and sample the pixels you clicked - each line should have a distinct color. This also assures you have some z-order when lines are drawn overlapping.

See my answer here to get an idea: How does Java / OS detect click co-ordinates on a viewport?

KYL3R
  • 3,877
  • 1
  • 12
  • 26
  • Won't it be less efficient to use so mush colliders¿ Because there might be a lot of lines in the scene – SagiZiv Nov 21 '19 at 08:50
  • Also this is not accurate as well, to make it precise I need to create a lot of colliders (the positions count-1) – SagiZiv Nov 21 '19 at 09:21
  • 2
    many Boxcolliders are very performance compared to few meshcolliders. – KYL3R Nov 21 '19 at 09:33
  • As an alternative: Draw the lines again (internally into a texture) and use a specific color for each line. have a map where you store the dependency of color to line. Colors act as an id. #05Af02 is "line 5" for example. Then you can write your own "raycast" that samples the texture at the pixel you clicked and it gives you the id of your line. This would be the most performant way. – KYL3R Nov 21 '19 at 09:36
  • I know that, but it can easily get to hundreds of colliders, and the target hardware is to weak anyway – SagiZiv Nov 21 '19 at 09:44
  • 1
    That sounds interesting, I would try to search more about that – SagiZiv Nov 21 '19 at 09:45