如何在不留空隙的情况下为线条渲染器形状设置动画

我正在使用下面的代码根据点数创建具有线渲染器的形状。 对于大于3的点(三角形等),第一个和最后一个点不会像其他点那样关闭形状。

1.如何在没有任何可见间隙的情况下关闭超过3个点的形状?

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.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); } } 

如果确保LineRenderer的最后一个点与第一个点相同,则应始终关闭任何给定的形状。 像这样运行for循环for (int i = 0; i < Points - 1; i++) (所以每个点但最后一个,也是<而不是<= )。 然后用lineRenderer.SetPosition(Point - 1, lineRenderer.GetPosition(0));关闭形状lineRenderer.SetPosition(Point - 1, lineRenderer.GetPosition(0)); 当for循环完成时。

请注意,Arrays从0开始,这就是Point - 1是lineRenderer的最后一个点的原因。

对于动画,我不知道一个简单的方法。 我会做的是使用协程将每个点移动到最终目的地。 例如,您首先添加第一个点,然后在第一个点的顶部添加第二个点。 然后你(在协程中随着时间的推移)移动第二个点朝向它的最终位置(使用SetPosition移动它)。 当它到达它的最终位置时,在它上面添加第三个点,并将其移动到它的最终位置。 重复每一点。

第一个(可能是显而易见的)解决方案是在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.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's 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()循环,如示例所示。 我希望这有帮助 ;)

因此,我们的想法是增加将顶点连接到顶点的线渲染器。

下面的解决方案是一个立方体,但我添加了一个额外的顶点,它很好。 我唯一无法测试的是循环设置,因为我在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 vertices = null; private LineRenderer line = null; private void Start() { // This creates a square this.vertices = new List() { 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(); 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; } } }