AND4011002849
AND4011002849

Reputation: 2001

How to draw a sine wave using line renderer from point A to point B

Following this tutorial, I'm trying to use Line Renderer component to draw a sine wave from point A to B.I'm using the input mouse position. However what I did so far is not working, it just draw the sine wave along the x axis, I need to draw it from the start point to the input mouse position.

private void Update()
{
    if (Input.GetMouseButtonDown(0))
    {
        Vector3 newPos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        newPos.z = 0;
        CreatePointMarker(newPos);
        GenerateNewLine();
    }
}

private void CreatePointMarker(Vector3 pointPosition)
{
    Instantiate(linePointPrefab, pointPosition, Quaternion.identity);
} 

private void GenerateNewLine()
{
    GameObject[] allPoints = GameObject.FindGameObjectsWithTag("PointMarker");
    Vector3[] allPointPositions = new Vector3[allPoints.Length];
    var pointList = new List<Vector3>();
    for (int i = 0; i < 50; i ++)
        {
            var dir = allPoints[0].transform.position - allPoints[1].transform.position;
            float x = dir.x * i;
            float y = Mathf.Sin(x * Time.time);
            var sine = new Vector3(x, y, 0f);
            var tangentLine = allPoints[0].transform.position + sine;

            pointList.Add(tangentLine);
        }
        SpawnLineGenerator(pointList.ToArray());
    }
}

private void SpawnLineGenerator(Vector3[] linePoints)
{
    GameObject newLineGen = Instantiate(lineGeneratorPrefab);
    LineRenderer lRend = newLineGen.GetComponent<LineRenderer>();

    lRend.positionCount = linePoints.Length;
    lRend.SetPositions(linePoints);
}

Upvotes: 0

Views: 2644

Answers (1)

derHugo
derHugo

Reputation: 90714

As an alternative I would suggest to instead use

lineRenderer.useWorlsSpace = false;

so the points are no longer set in worldspace but in the local space relative to the linerenderer transform.

Now you can simply rotate the linerenderer transform to point towards the latest user input position.

I couldn't use your code example since I don't know what your prefabs are and do so I created my own from the code in the given Video. I hope you can reuse/recreate the parts necessary

public class SinusWave : MonoBehaviour
{
    public Vector3 initalPosition;
    public int pointCount = 10;
    public LineRenderer line;

    private Vector3 secondPosition;
    private Vector3[] points;
    private float segmentWidth;

    private void Awake()
    {
        line = GetComponent<LineRenderer>();

        line.positionCount = pointCount;

        // tell the linerenderer to use the local 
        // transform space for the point coorindates
        line.useWorldSpace = false;

        points = new Vector3[pointCount];
    }

    private void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            // Camera.main.ScreenToWorldPoint needs a value in Z
            // for the distance to camera
            secondPosition = Camera.main.ScreenToWorldPoint(Input.mousePosition - Vector3.forward * Camera.main.transform.position.z);
            secondPosition.z = 0;

            var dir = secondPosition - initalPosition;
            // get the segmentWidth from distance to end position
            segmentWidth = Vector3.Distance(initalPosition, secondPosition) / pointCount;

            // get the difference angle in the Z axis between the current transform.right
            // and the direction
            var angleDifference = Vector3.SignedAngle(transform.right, dir, Vector3.forward);
            // and rotate the linerenderer transform by that angle in the Z axis
            // so the result will be that it's transform.right
            // points now towards the clicked position
            transform.Rotate(Vector3.forward * angleDifference, Space.World);
        }

        for (var i = 0; i < points.Length; ++i)
        {
            float x = segmentWidth * i;
            float y = Mathf.Sin(x * Time.time);
            points[i] = new Vector3(x, y, 0);
        }
        line.SetPositions(points);
    }
}

enter image description here


Btw I just assume here that GameObject.FindGameObjectsWithTag("PointMarker"); actually retuns all the so far spawned linePointPrefab objects.

It would be better to store them right away when you spawn them like

private List<Transform> allPoints = new List<Transform>();

...

allPoints.Add(Instantiate(linePointPrefab, pointPosition, Quaternion.identity).transform);

then you can skip the usage of FindObjectsWithType completely


For adopting this local space position also for the line point prefabs you instantiate simply instantiate them as child of the linerenderer transform or spawn them and the linerenderer under the same parent so the relative positions are the same. In this case you wouldn't rotate the linerenderer but the entire parent object so the spawned linepoints are rotated along with it

Upvotes: 2

Related Questions