Search Unity

How to draw lines on a canvas in real/game time?

Discussion in '2D' started by LurchUSA, Sep 11, 2018.

  1. LurchUSA

    LurchUSA

    Joined:
    Sep 20, 2017
    Posts:
    21
    This is what I am trying to achieve:



    On a canvas, hovering over a raw image object, I need to do the following steps:
    1. Mouse down to start the line.
    2. Mouse drag to stretch the line out from its origin, to the current cursor position.
    3. Mouse up, set the line and instantiate a boarded text box to the left/right of the line depending on the lines direction. the at the origin of the line, instantiate an arrow head point in the direction of the line.
    From all the unity help articles I'm viewing, about drawing in real time, I am not seeing anything trying to do what I need to do.

    I would appreciate any pointers on what would be considered "best practice" way to doing this. Please let me know of game-objects, functions and drawing options I should look into, please.
     
  2. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    I'd probably do it with Vectrosity (a line-drawing plug-in).

    But you could also do it with Image components, if you're sufficiently clever with the math. You could, for example, set up the anchor point to be the tip of the arrow; then you'd position that where you want to point, set the width to the desired length, and the angle to the desired angle (updating all the relevant properties in the RectTransform).
     
  3. LurchUSA

    LurchUSA

    Joined:
    Sep 20, 2017
    Posts:
    21
    As much as I would love to try out Vectrosity, my boss won't approve the expenditure for a proof of concept project.

    However I have been able to dynamical scale an UI raw image, to render the line, over the base photo raw image which more or less achieves the desired result. Not my preferred solution, but since its a UI object it works with the scroll view port that the base photo raw image is rendered within.
     
    JoeStrout likes this.
  4. roykoma

    roykoma

    Joined:
    Dec 9, 2016
    Posts:
    176
    For the line-drawing part of this you could also look into LineRenderer if thats a more preferred solution.

    Downside: this only works if you are working with a Canvas that is set to "Screen Space - Camera". So if that is not an option, don't bother with LineRenderers.

    An example of how you could archive that with LineRenderer:

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. public class LineDrawingExample : MonoBehaviour
    4. {
    5.     /// <summary>
    6.     /// Starting position of the created line
    7.     /// </summary>
    8.     Vector3 startPosition;
    9.  
    10.     /// <summary>
    11.     /// GameObject of the created line
    12.     /// </summary>
    13.     GameObject currentLineObject;
    14.  
    15.     /// <summary>
    16.     /// lineRenderer of the created line
    17.     /// </summary>
    18.     LineRenderer currentLineRenderer;
    19.  
    20.     /// <summary>
    21.     /// Material of the drawn line.
    22.     /// For my example I used a new Material with "UI/Default" shader
    23.     /// </summary>
    24.     public Material lineMaterial;
    25.  
    26.     /// <summary>
    27.     /// thickness of the drawn line
    28.     /// </summary>
    29.     public float lineThickness;
    30.  
    31.     /// <summary>
    32.     /// Canvas that you want to draw on
    33.     /// </summary>
    34.     public Canvas parentCanvas;
    35.  
    36.     void Update()
    37.     {
    38.         if (Input.GetMouseButtonDown(0)) {
    39.             StartDrawingLine();
    40.         }
    41.         else if (Input.GetMouseButton(0)) {
    42.             PreviewLine();
    43.         }
    44.         else if (Input.GetMouseButtonUp(1)) {
    45.             EndDrawingLine();
    46.         }
    47.     }
    48.  
    49.     /// <summary>
    50.     /// Returns the current mouseposition relative to the canvas.
    51.     /// Modifies the z-value slightly so that stuff will be rendered in front of UI elements.
    52.     /// </summary>
    53.     /// <returns></returns>
    54.     Vector3 GetMousePosition() {
    55.         Vector2 movePos;
    56.         RectTransformUtility.ScreenPointToLocalPointInRectangle(
    57.             parentCanvas.transform as RectTransform,
    58.             Input.mousePosition, parentCanvas.worldCamera,
    59.             out movePos);
    60.         Vector3 positionToReturn = parentCanvas.transform.TransformPoint(movePos);
    61.         positionToReturn.z = parentCanvas.transform.position.z - 0.01f;
    62.         return positionToReturn;
    63.     }
    64.  
    65.     /// <summary>
    66.     /// Starts drawing the line
    67.     /// Creates a new GameObject at the startPosition and adds a LineRenderer to it
    68.     /// The LineRenderer also gets modified with material and thickness here
    69.     /// </summary>
    70.     void StartDrawingLine() {
    71.         startPosition = GetMousePosition();
    72.         currentLineObject = new GameObject();
    73.         currentLineObject.transform.position = startPosition;
    74.         currentLineRenderer = currentLineObject.AddComponent<LineRenderer>();
    75.         currentLineRenderer.material = lineMaterial;
    76.         currentLineRenderer.startWidth = lineThickness;
    77.         currentLineRenderer.endWidth = lineThickness;
    78.     }
    79.  
    80.     /// <summary>
    81.     /// Updates the LineRenderer Positions
    82.     /// </summary>
    83.     void PreviewLine() {
    84.         currentLineRenderer.SetPositions(new Vector3[]{ startPosition, GetMousePosition()});
    85.     }
    86.  
    87.     /// <summary>
    88.     /// Cleans up the used variables as the LineRenderer will not be modified anymore
    89.     /// </summary>
    90.     void EndDrawingLine() {
    91.         startPosition = Vector3.zero;
    92.         currentLineObject = null;
    93.         currentLineRenderer = null;
    94.     }
    95. }
    Please notice that if you are using LineRenderer you are not working with UI-Elements. You will therefore have to compensate for scrolling and stuff like that yourself.
    Also notice that this is just a quick example that I wrote out of my head and therefore needs a good bit of polishing, just use it as a starting point as to how it works.
     
    Last edited: Sep 14, 2018
    Ultroman likes this.
  5. TheDevloper

    TheDevloper

    Joined:
    Apr 30, 2019
    Posts:
    69

    Thank you so much you saved my life