Draw squiggly line with finger.

I can’t seem to find a recent guide on how to draw lines. The top searches in this forum lead to missing links.

I’m not new to C#, but I am new to Unity so the namespaces all are foreign to me. Does anyone have a good article on drawing random lines with the mouse/finger? This will eventually be used as a path for a sprite.

Thanks!

I would assume the simplest way is to catch when the person puts a finger down, that you start “recording” per frame where the finger is. store that in a list. (maybe optimize the list so it doesn’t get too long) Then use that list as a set of way points for a sprite to move.

If you are looking for somewhere to start. Start with the following:

Follow the first finger placed, and every frame, simply add it’s position to the list. When the player lifts his finger, then you start the animation following that path.

There are two parts to this: detecting and tracking the touch, and drawing the line. You didn’t specify which one you’re having trouble with. @bigmisterb has given you a good start on the first, though.

For the second, drawing decent lines in Unity is surprisingly difficult out of the box. I use a third-party asset called Vectrosity. It performs really well and is not too hard to use.

For the sake of optimization, I would say to only add a position to the list if the finger has moved X pixels since the last position. This is much easier and faster than after-the-fact optimization of the line points. Drawing the line is fairly easy through either Vectrosity as JoeStrout suggested or the builtin LineRenderer, which recently received a major upgrade in 5.5 so it won’t look like crap.

As far as using the points to move a sprite, that’s fairly easy. If you are given a distance along a path, you can crawl along the path from the beginning, adding the distance from each point to the next to a distance variable. (Recommended optimization here: cache the distances as you calculate them.) When you reach a point where the cumulative distance up to point Y (let’s call it Ydist) is >= the requested difference, take one step back and use Vector3.Lerp(X,Y,T), where T = (requestedDist - Xdist) / (Ydist - Xdist).

Awesome! Thanks everyone. I pulled down Vectrosity and I’m getting to work tonight. Will report back in a day or three on my success.

d

1 Like

Okie dokie, I have all of the basic pieces working. I’m getting touch input, moving around the bits that are supposed to move while keeping the others in place.

I got the squiggly line going with vectrosity, very simple, just as you said. I am having two problems and I feel like they are related, but maybe not. First, in the middle of any squiggly line, I get random segments going back to 0,0 like in the attached pic.

Second, I am having trouble tracking distance the mouse moved since last point. My debug UI element always stays at “no movement” and you can see in the code here where it should be tracking it.

Thanks for taking the time to look.
David

(This is just the drawing bits for the purpose of this post.)

using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Vectrosity;

public class DrawLine : MonoBehaviour {

    private VectorLine squiggle;
    private Vector3 oldPosition;
    private Vector3 curPosition;
    private bool clear;
    public float moveSpeed = 0.1f;
    public Text mousePos;
    public Text click;
    public Text distance;

    void Start ()
    {
        clear = false;
        mousePos.text = "No movement";
        click.text = "Not clicked";
        distance.text = "no movement";


        squiggle = new VectorLine("Line", new List<Vector2>(), 2.0f, LineType.Continuous, Joins.Fill);
        squiggle.lineWidth = 3f;
    }

    void Update ()
    {

        if (Input.GetMouseButton(0))
        {
            if (clear)
            {
                clearPath();
            }

            clear = false;
            click.text = "Yes clicked";
            curPosition = Input.mousePosition;
            squiggle.points2.Add(curPosition);
            oldPosition = curPosition;
            Vector3 travel = curPosition - oldPosition;
            distance.text = travel.magnitude.ToString() + "\n" + mousePos.text;
            mousePos.text = curPosition.ToString() + "\n" + mousePos.text;

        }
        else
        {
            click.text = "Not clicked";
        }

        if(Input.GetMouseButtonUp(0))
        {
            squiggle.points2.Add(squiggle.points2[0]);
            clear = true;
        }

        squiggle.Draw();
    }

    void clearPath()
    {
        VectorLine.Destroy(ref squiggle);

        squiggle = new VectorLine("Line", new List<Vector2>(), 2.0f, LineType.Continuous, Joins.Fill);
        squiggle.lineWidth = 3f;
    }
}

Well… for the second problem first… check out just lines 43-44 in isolation:

            oldPosition = curPosition;
            Vector3 travel = curPosition - oldPosition;

I bet you can predict what the value of ‘travel’ is after these two lines execute. No matter what oldPosition and curPosition are. :slight_smile: (Please be careful when slapping your forehead; there are delicate components behind there!)

Not sure what’s going on with the occasional return to origin, though. I might suggest logging your points as you add them with Debug.Log, rather than (or in addition to) using an on-screen text, so you can go back carefully afterwards and see if there’s any 0,0’s in there. If so, then you can work backwards to try to figure out why.

Oh.
My.
God.

The shame, it burns.

3 Likes

Great success! I can draw squiggly lines. I made it so that when the finger was lifted I added the first point to the list again so that it made a continuous loop. Then as soon as the finger goes down again the first one disappears and you can draw again.

Now I have hit another roadblock, the textures aren’t working the way I thought after reading the Vectrosity documentation. Is there a way to use a texture .png to tile the texture along the line? Imagine drawing a long snake and you want the scales to be a repeating pattern. Is this possible?

Thanks

david

Sounds like a whole new can of worms :slight_smile:

I’d say, that vectrocity probably offers some built in way to get points along the line drawn, and perhaps you could get points along the line, measure some spacing, and instantiate some sprites where you want them.

If what your ultimately wanting visually is to draw patterns of sprites though - you don’t necessarily need vectrocity for that, but you could just spawn sprites on a grid, and if where the finger is touching at doesn’t have a sprite spawned, spawn one at that point in the grid.

Or if I’m misunderstanding, and you want to draw a “ribbon” of a patterned sprite, you might look at some procedural generation tutorials that show how to create geometry and texture it with a pattern…

Well, think of drawing a freeform road, then using that for a car path. I’m using the line for the fine-grained path points to move the car, but right now it’s just a line. I need to put the pavement under the car.

Ok, you might look at some of the assets which serve that type of purpose, such as easy roads, and probably other similar assets could do that too. Though it seems those are geared for 3d games and I get the impression your going 2d, but even if so, you might be able to at least draw some inspiration from how they do it.

1 Like

Yeah, I spent some time looking through those, but I haven’t been able to find one that does it at runtime. I just want to draw a squiggly 2d cartoon road. :frowning:

Wait, I’m pretty certain Vectrosity can do exactly what you describe. You give it a texture and it repeats that over and over. There’s an example of it in the manual. Suggest you go give that another read. :slight_smile:

Great success! I was missing attaching the texture file to the public variable I used for the texture in my script. After that it was just a matter of tweaking.

2 Likes