Is there any way to make the SetPosition of a LineRenderer smoother. I'm making a 2D game, and I'm making a chameleon tongue, where it pops out of the mouth to a point and then comes back, but this makes the animation very fast, is there any way to make it slower and smoother?
My question is is there a way to smooth the setposition of a linerenderer? As I have in my script.
EdgeCollider2D edgeCollider;
LineRenderer myLine;
public Transform pointOne;
public Transform pointfinalZero;
public Transform pointfinal;
public bool isTongue;
void Start()
{
edgeCollider = this.GetComponent<EdgeCollider2D>();
myLine = this.GetComponent<LineRenderer>();
}
void Update()
{
SetEdgeCollider(myLine);
myLine.SetPosition(0, pointOne.position);
if(isTongue)
{
myLine.SetPosition(1, pointfinal.position);
}
if(!isTongue)
{
myLine.SetPosition(1, pointfinalZero.position);
}
}
void SetEdgeCollider(LineRenderer lineRenderer)
{
List<Vector2> edges = new List<Vector2>();
for(int point = 0; point<lineRenderer.positionCount; point )
{
Vector3 lineRendererPoint = lineRenderer.GetPosition(point);
edges.Add(new Vector2(lineRendererPoint.x, lineRendererPoint.y));
}
edgeCollider.SetPoints(edges);
}
It's working fine, but I wanted to make it smoother to see the tongue stick out.
CodePudding user response:
Smooth movement to the target point in Unity
non-physical movement
1. Transform. Translate. For example: Transform.Translate(Vector3.zero*Time.deltaTime). Move towards (0, 0, 0) at a speed of one meter per second.
2.Vector3.lerp Vector.Slerp, Vector3.MoveTowards.
Vector3.lerp(transform.position,targetposition,Time.deltaTime) . //Slerp is mainly used for the interpolation operation of angle radian. MoveTowards has increased the maximum speed limit on the basis of Lerp.
3. Vector3.SmoothDamp
This method can smoothly move from point A to point B, and can control the speed. The most common usage is that the camera follows the target.
physical movement:
The Rigidbody.MovePosition method in Righdbody is used to move to the target point.
CodePudding user response:
How about using Coroutine? You could use all sorts of Tween libs, but I prefer barebone Coroutines.
timespan is how many seconts it takes to animate.
[ExecuteAlways] is for tests in Editor. Same with ContextMenu("StickTongueOut")] you can right click script in inspector to run animations.
Initiating tongue variable in OnEnabled because after the assembly hot reload, OnEnabled is fired and reinitiates it's value, thus you can write code that would still be alive after editing your script while playing. Not necessary, but oh how convinient.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[ExecuteAlways]
[RequireComponent(typeof(LineRenderer))]
public class TongueAnimator : MonoBehaviour
{
public Transform target;
public Transform origin;
public float timespan = 1f;
private LineRenderer tongue;
private void OnEnable()
{
tongue = GetComponent<LineRenderer>();
}
private IEnumerator _tongueLoopCoroutine;
/// <summary>
/// This will restart tongue animation coroutine even if it is still out
/// </summary>
public void AnimateTongue(bool direction)
{
if (_tongueLoopCoroutine != null)
StopCoroutine(_tongueLoopCoroutine);
_tongueLoopCoroutine = TongueLoop(direction);
StartCoroutine(_tongueLoopCoroutine);
}
[ContextMenu("StickTongueOut")]
public void StickTongueOut() => AnimateTongue(true);
[ContextMenu("RetractTongue")]
public void RetractTongue() => AnimateTongue(false);
public IEnumerator TongueLoop(bool direction)
{
var startTime = Time.time;
while (startTime timespan > Time.time)
{
float t = (Time.time - startTime) / timespan;
if (!direction) { t = 1 - t; }
SetPositions(t);
yield return null;
}
SetPositions(direction ? 1 : 0);
//Reusing same code. Local Methods might not be supported in older Unity versions like 2019
void SetPositions(float t)
{
tongue.SetPosition(0, origin.position);
var pos = Vector3.Lerp(origin.position, target.position, t);
tongue.SetPosition(1, pos);
}
}
}
If you nee EaseInOut you could remap t before changing direction with something like this:
using UnityEngine;
public static class Utility
{
public static float SmoothStep(this float t) => t * t * (3f - 2f * t);
public static float SmootherStep(this float t) => t * t * t * (t * (t * 6 - 15) 10);
public static float InverseSmoothStep(this float t) => .5f - Mathf.Sin(Mathf.Asin(1f - 2f * t) / 3f);
public static float SinStep(this float t) => Mathf.Sin(Mathf.PI * (t - .5f)) / 2 .5f;
/// <summary>
///
/// </summary>
/// <param name="t"></param>
/// <param name="p">When equals to 2 returns similar results as Smoothstep</param>
/// <returns></returns>
public static float SmoothStepParametric(this float t, float p = 2f)
{
var tp = Mathf.Pow(t, p);
return tp / (tp Mathf.Pow(1 - t, p));
}
}
This utility let you do this
t = t.SmoothStep();
t = Utility.SmoothStep(t);
Just be careful messing your project with such Utilities without namespaces, you'll get into collisions. Better use namespaces.