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 arrows following a path described points

Discussion in 'Scripting' started by Antidote, Feb 12, 2010.

  1. Antidote

    Antidote

    Joined:
    Dec 28, 2009
    Posts:
    36
    Hello,

    I want to draw arrows or lines by clicking 2 times or 3 times on a plane. The path is following these 2 points or these 3 points. The idea is to chosse between several type of arrows or lines.
    These lines or arrows are deformed by the path described by the 2 or 3 points.

    Regards,
     
  2. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    When you say "deformed", do you mean you want a smooth curved path going through the points?
     
  3. Antidote

    Antidote

    Joined:
    Dec 28, 2009
    Posts:
    36
    Yep Andeeee,

    The best would be to have :
    1st point = end of the arrow or begin of the smooth curve path,
    2nd point = middle of the arrow or the smooth path,
    3rd point = begin or head of the arrow or end of the smooth curve path,
    Possibilty to change the model (arrow or line or ...)

    Please have a look at the attachment.

    Regards,
     

    Attached Files:

  4. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    There's a script in this thread that implements a few different types of curve. The easiest curve to use would be the quadratic Bezier curve (the QuadBez class), but with this, the curve won't go through the middle point, just near it. If the curve needs to go through all the points, the Catmull-Rom spline is what you need, but you will have to supply an extra two points, one at the start and another at the end, to show which direction the curve should be pointing at the ends. You can use a function like the following as a simple way to supply these extra points:-
    Code (csharp):
    1. function MakeCurve(firstPoint: Vector3, secondPoint: Vector3, thirdPoint: Vector3) {
    2.     var startPt: Vector3 = 2.0 * firstPoint - secondPoint;
    3.     var endPt: Vector3 = 2.0 * thirdPoint - secondPoint;
    4.     return new CRSpline(startPt, firstPoint, secondPoint, thirdPoint, endPt);
    5. }
    Then, you could use a LineRenderer component to render the curve. The idea is that you break the curve up into maybe ten short segments and use the LineRenderer to draw them as straight lines. The code will look something like:-
    Code (csharp):
    1. var curve: CRSpline = MakeCurve(firstPoint, secondPoint, thirdPoint);
    2.     ...
    3.    
    4. var lr: LineRenderer = GetComponent(LineRenderer);
    5. lr.SetVertexCount(10);
    6.  
    7. for (i = 0; i < 9; i++) {
    8.     var pt: Vector3 = curve.Interp(i / 10.0);
    9.     lr.SetPosition(i, pt);
    10. }
    11.  
    12. lr.SetPosition(9, thirdPoint);
    I think you will have to add the arrowhead on the end yourself using an object with a texture. You can get the direction of the arrowhead as a vector using:-
    Code (csharp):
    1. var arrowDir: Vector3 = curve.Velocity(1.0);
     
  5. Antidote

    Antidote

    Joined:
    Dec 28, 2009
    Posts:
    36
    Hi Andeeee,

    Sorry to disturb you again but I don't know how to use all these pieces of code ... How to attach this or these scripts to the different objects.
    May you explain the process please ?
    Is that possible to control the line width ?

    Regards,

    -----------------------------------
     
  6. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    It's OK, I was awake ;-)

    You need to start by creating a new JavaScript file. You can add this to an object simply by dragging it onto the inspector when the object is selected. You can then put whatever code you like into the new file and it will be applied to the object where appropriate. Check out this manual page for more detail about creating and using scripts.

    The LineRenderer has a SetWidth function that you can use to control the width of the line at the start and the end.
     
  7. greg767

    greg767

    Joined:
    Nov 6, 2009
    Posts:
    113
    Hi andeeee,

    I am trying to use your Curves class and I am not sure if I get the right results.
    So here is how I am trying to use it:
    With this I am preparing a Vector3 with all the points I have on the sphere.
    Code (csharp):
    1.  
    2.  private Vector3[] populatePointArray()
    3.     {
    4.         pointList = new Vector3[markerList.Count];
    5.  
    6.         for (int i = 0; i < markerList.Count; i++)
    7.         {
    8.             pointList[i] = (markerList[i] as GameObject).transform.position;
    9.            
    10.         }
    11.         return pointList;
    12.     }
    13.  
    Here I instantiate the curve:

    Code (csharp):
    1.  
    2. private CRSpline makeCurve(Vector3[] points)
    3.     {
    4.         Vector3 firstPoint = points[0];
    5.         Vector3 secondPoint = points[1];
    6.         Vector3 endPoint = points[points.Length - 1];
    7.         Vector3 beforeEndPoint = points[points.Length - 2];
    8.  
    9.         Vector3 startPt = 2.0f * firstPoint - secondPoint;
    10.         Vector3 endPt = 2.0f * endPoint - beforeEndPoint;
    11.  
    12.         intermedPoints = new Vector3[points.Length + 2];
    13.  
    14.         for (int i = 0; i < intermedPoints.Length; i++)
    15.         {
    16.             if (i == 0)
    17.                 intermedPoints[i] = startPt;
    18.             else if (i == intermedPoints.Length - 1)
    19.                 intermedPoints[i] = endPt;
    20.             else
    21.                 intermedPoints[i] = points[i - 1];
    22.         }
    23.         return new CRSpline(intermedPoints);
    24.     }
    25.  
    And displaying the result:
    Code (csharp):
    1.  
    2. private void showSpline()
    3.     {
    4.         GameObject go = GameObject.Find("spliner");
    5.         LineRenderer liner = go.GetComponent("LineRenderer") as LineRenderer;
    6.         if (!liner)
    7.         {
    8.             liner = go.AddComponent("LineRenderer") as LineRenderer;
    9.             liner.SetWidth(0.05f, 0.05f);
    10.             liner.SetVertexCount(1000);
    11.  
    12.             for (int i = 0; i < 999; i++)
    13.             {
    14.                 Vector3 pt = curve.Interp(i / 1000.0f);
    15.                 liner.SetPosition(i, pt);
    16.             }
    17.             liner.SetPosition(999, pointList[pointList.Length - 1]);
    18.         }
    19.         else
    20.         {
    21.             liner.SetWidth(0.05f, 0.05f);
    22.             liner.SetVertexCount(1000);
    23.  
    24.             for (int i = 0; i < 999; i++)
    25.             {
    26.                 Vector3 pt = curve.Interp(i / 1000.0f);
    27.                 liner.SetPosition(i, pt);
    28.             }
    29.             liner.SetPosition(999, pointList[pointList.Length - 1]);
    30.         }
    31.     }
    32.  
    The grey dots are the ones that the user puts on the sphere, the smaller red ones are created automatically to approximate the curvature of the sphere.
    So every time the user puts a grey dot the whole array is re-fed into the makeCurve method, but I don't really see any splines here.
    Code (csharp):
    1.  
    2. curve = makeCurve(populatePointArray());
    3.         showSpline();
    4.  
     

    Attached Files:

  8. greg767

    greg767

    Joined:
    Nov 6, 2009
    Posts:
    113
  9. andeeeee

    andeeeee

    Joined:
    Jul 19, 2005
    Posts:
    8,768
    This is very odd because I've pasted the functions you've posted into a C# file (and added the appropriate variables, etc) and it has drawn a curve correctly through the points. Can you post the whole of the script or attach the source file? I guess there could be something else in the code that is causing problems. Or is it possible you've got another line renderer in the scene somewhere with the wrong data?