Подтвердить что ты не робот

Как анимировать формы рендеринга линии, не оставляя пробела

Я использую приведенный ниже код для создания фигур с помощью средства визуализации линии на основе количества точек. Для точек больше 3 (форма треугольника и т.д.) Первая и последняя точки не закрывают форму так, как это делают другие точки.

1. Как закрыть фигуры с более чем тремя точками без видимых пробелов?

2. Как я могу анимировать фигуру, чтобы рисовать линии в течение определенной продолжительности (возможно, используя сопрограмму)?

public class CircleDrawing : MonoBehaviour
{

    [Tooltip("The radius of the circle, measured in world units.")]
    public float Radius = 2;

    [Tooltip("The number of vertices in the circle.")]
    public int Points = 5;

    [Tooltip("The color of the circle.")]
    public Color Color;

    private LineRenderer lineRenderer;

    public void Awake()
    {
        lineRenderer = gameObject.AddComponent<LineRenderer>();
        lineRenderer.material = new Material(Shader.Find("Sprites/Default"));
        lineRenderer.material.color = Color;
        lineRenderer.startWidth = lineRenderer.endWidth = 0.5f;
        lineRenderer.positionCount = Points + 1;    //+1 to close the shape
        Draw();
    }

    private void Draw()
    {
        float angle = 0f;
        for (int i = 0; i <= Points; i++)
        {
            float x = Radius * Mathf.Cos(angle) + transform.position.x;
            float y = Radius * Mathf.Sin(angle) + transform.position.y;
            lineRenderer.SetPosition(i, new Vector3(x, y, 0.01f)); //Z is slightly behind the paddle so it draws in front
            angle += (2f * Mathf.PI) / Points;
        }
    }

    private void OnDestroy()
    {
        Destroy(lineRenderer.material);
    }
}
4b9b3361

Ответ 1

Если вы убедитесь, что последняя точка вашего LineRenderer совпадает с первой точкой, она всегда должна закрывать любую данную фигуру. Запустите цикл for следующим образом for (int i = 0; i < Points - 1; i++) (поэтому каждая точка, но последняя, ​​также <, а не <=). Затем закройте форму с помощью lineRenderer.SetPosition(Point - 1, lineRenderer.GetPosition(0));, когда цикл for сделан.

Обратите внимание, что массивы начинаются с 0, поэтому Point - 1 - это последняя точка вашего lineRenderer.

Для анимации я не знаю простого способа сделать это. То, что я сделал бы, это использовать сопрограмму для перемещения каждой точки в сторону конечного пункта назначения с течением времени. Например, вы начинаете с добавления первой точки, и вы добавляете вторую точку поверх первой точки. Затем вы перемещаете (со временем в сопрограмме) вторую точку к ее окончательной позиции (используйте SetPosition для ее перемещения). Когда он достигнет конечной позиции, добавьте третью точку поверх нее и переместите ее в конечную позицию. Повторите для каждой точки.

Ответ 2

Первым (возможно, очевидным) решением было бы установить опцию loop на LineRenderer. Однако во многих случаях это не дает визуально приятных результатов.

Я бы исправил проблему просто так, что дает приятные визуальные результаты:

lineRenderer.positionCount = Points + 2;    //+2 to close the shape and create one more piece to extend over the gap.

и

for (int i = 0; i <= Points + 1; i++) // one more piece

Нарисуйте полную форму, затем просто создайте еще одну фигуру, которая возвращается назад. Это может не выглядеть элегантно, но это так просто и выглядит так, как я думаю, он должен выглядеть.

Что касается анимации, попробуйте что-то вроде этого:

using UnityEngine;
using System.Collections;

public class CircleDrawing : MonoBehaviour
{
    public float Radius = 2f;
    public int Points = 5;
    public Color Color = Color.red;
    public float DrawSpeed = 1f;

    private LineRenderer lineRenderer;
    private float progress; // [0..1] animated value.

    public void Awake()
    {
        lineRenderer = gameObject.AddComponent<LineRenderer>();
        lineRenderer.material = new Material(Shader.Find("Sprites/Default"));
        lineRenderer.material.color = Color;
        lineRenderer.startWidth = lineRenderer.endWidth = 0.5f;
        lineRenderer.positionCount = Points + 2;    //+2 to close the shape and create one more piece to extend over the gap.
        progress = 0;
        StartCoroutine(Draw());
    }

    private void Update_Disabled() // Regular Update() loop
    {
        float angle = 0f;
        for (int i = 0; i <= Points + 1; i++) // one more piece
        {
            float x = Radius * Mathf.Cos(angle) + transform.position.x;
            float y = Radius * Mathf.Sin(angle) + transform.position.y;
            lineRenderer.SetPosition(i, new Vector3(x, y, 0.01f));
            angle += (2f * Mathf.PI) / Points;
            angle *= progress;
        }

        progress += DrawSpeed * Time.deltaTime;
        progress = Mathf.Clamp01(progress);
    }

    private IEnumerator Draw()
    {
        yield return new WaitForSeconds(1f); // Debug

        bool done = false;
        while(!done)
        {
            if(progress >= 1)
                done = true; // The done check can be handled better, but it late.

            float angle = 0f;
            for (int i = 0; i <= Points + 1; i++) // One additional piece to loop over start.
            {
                float x = Radius * Mathf.Cos(angle) + transform.position.x;
                float y = Radius * Mathf.Sin(angle) + transform.position.y;
                lineRenderer.SetPosition(i, new Vector3(x, y, 0.01f));
                angle += (2f * Mathf.PI) / Points;
                angle *= progress; // Animate progress turning.
            }
            progress += DrawSpeed * Time.deltaTime;
            progress = Mathf.Clamp01(progress);
            yield return null;
        }
    }
}

В основном у вас уже есть все на своем месте, анимируйте его, оживляя значения, которые вы уже используете. Конечно, существует множество способов достижения разных эффектов, но большинство из них будет применять анимированное значение прогресса к другому параметру вашего чертежа. Вы можете использовать сопрограмму или только обычный цикл Update(), как показано в примере. Надеюсь, это поможет;)

Ответ 3

Итак, идея состоит в том, чтобы увеличить рендеринг линии, соединяющий вершину с вершиной.

Решение ниже для куба, но я добавил дополнительную вершину, и все идет хорошо. Единственное, что я не мог проверить, это настройка цикла, поскольку я на 5.5... Я предполагаю, что это работает... Кроме того, я не передал никаких материалов, я думаю, у вас это есть.

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

public class Test : MonoBehaviour
{
    [SerializeField]
    private float step = 0.5f;  // How fast it draws
    private List<Vector3> vertices = null;
    private LineRenderer line = null;
    private void Start()
    {
        // This creates a square
        this.vertices = new List<Vector3>()
        {
            new Vector3(-1,-1,0), new Vector3(1,-1,0), new Vector3(1,1,0),new Vector3(-1, 1, 0)
        };
        StartCoroutine(Draw());
    }
    private IEnumerator Draw()
    {
        int index = 1;
        int vertexPos = 1;
        // Set the LineRenderer basics with 2 vertices
        this.line = this.gameObject.AddComponent<LineRenderer>();
        this.line.startWidth = this.line.endWidth= 0.1f;
        this.line.numPositions = 2; 
        // Set both point at same starting position   
        this.line.SetPosition(0,this.vertices[0]);
        this.line.SetPosition(1, this.vertices[0]);
        Vector3 temp = this.vertices[0];        // Get the current vertex position
        Vector3 target = this.vertices[index];  // Get the target vertex position
        while (true)
        {     
            // Move the current pos to the target pos                      
            temp = Vector3.MoveTowards(temp, target, Time.deltaTime * this.step);
            this.line.SetPosition(vertexPos, temp);
            // Is the target reached
            if (temp == target)
            {
                // This is for final run when closing the shape
                // It means we reach target and index is 0 so end of shape
                // Break the coroutine
                if(index == 0)
                {
                    this.line.loop = true;  // Could not test this one on 5.5
                    yield break;
                }
                // Increase the LineRenderer size by 1
                vertexPos++;
                this.line.numPositions++;
                // Place the new vertex at the position of the previous
                this.line.SetPosition(vertexPos, temp);

                // Increase the index and check if we reached the end of the vertex list
                // If end of vertex list, then we use the first one to close
                if (++index == this.vertices.Count)
                {
                    index = 0;
                }
                // Set new target
                target = this.vertices[index];
            }
            yield return null;
        }
    }
}