- Home /
how to make a game object follow a drawn path at run time?
hey guys , so im using the script down below to a cast ray on a collider to draw a line at run-time. i got 2 questions: how do i make the line look smoother (it has some sharp edges now)? and second question : how can i make a regular game object follow the line i have drawn? (by the way i dont want to use Navmesh agents)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using System;
public class path : MonoBehaviour
{
LineRenderer lineRender;
private List<Vector3> pionts = new List<Vector3>();
public Action<IEnumerable<Vector3>> onnewpathcreat = delegate { };
// Start is called before the first frame update
private void Awake()
{
lineRender = GetComponent<LineRenderer>();
}
void Start()
{
}
// Update is called once per frame
void Update()
{
if (Input.GetKeyDown(KeyCode.Mouse0))
pionts.Clear();
if (Input.GetKey(KeyCode.Mouse0)) {
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
RaycastHit hit;
if (Physics.Raycast(ray, out hit))
{
if (Distancetolastpiont(hit.point) > 1f) {
pionts.Add(hit.point);
lineRender.positionCount = pionts.Count;
lineRender.SetPositions(pionts.ToArray());
}
}
}else if (Input.GetKeyUp(KeyCode.Mouse0))
{
onnewpathcreat(pionts);
}
}
public float Distancetolastpiont(Vector3 pioint)
{
if (!pionts.Any())
return Mathf.Infinity;
return Vector3.Distance(pionts.Last(), pioint);
}
}
Answer by DCordoba · May 08, 2019 at 03:34 AM
to be honest, improve this small piece took me 6 hours, I took several (quadratic functions) paths, but... I like that kind of simple, but unusual, questions, thanks, I enjoy it a lot
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/*
* this script follow the points of the line renderer attached to it
* drag & drop the line renderer component to the field, or use GetComponent at start
* disable script to stop from other script component
*/
public class LineFollower : MonoBehaviour {
/// <summary>
/// Current main speed
/// </summary>
public float speed;
/// <summary>
/// The line that this follow.
/// </summary>
public LineRenderer lineToFollow;
/// <summary>
/// So, we have to stop after the first lap?
/// </summary>
public bool justOnce = true;
/// <summary>
/// Internal variable, is the first lap completed?
/// </summary>
bool completed = false;
/// <summary>
/// Follow a smooth path.
/// </summary>
public bool smooth = false;
/// <summary>
/// the number of iterations that split each curve
/// </summary>
public int iterations = 10;
public float radius = 0;
/// <summary>
/// The points of the line
/// </summary>
Vector3 [] wayPoints;
/// <summary>
/// The Current Point
/// </summary>
int currentPoint = 0;
// Use this for initialization
void OnEnable () {
Vector3 [] temp = new Vector3[500];
int total = 0;
if (lineToFollow != null){
//get the verts from LineRenderer is a headache, warning, not far of 500 verts, or you'll need to increase the numbre above
total = lineToFollow.GetPositions(temp);
wayPoints = new Vector3[total];
for(int i = 0; i< total; i++)
wayPoints[i] = temp[i];
}
completed = false;
}
void Start(){
Vector3 [] temp = new Vector3[500];
int total = 0;
if (lineToFollow != null){
total = lineToFollow.GetPositions(temp);
wayPoints = new Vector3[total];
for(int i = 0; i< total; i++)
wayPoints[i] = temp[i];
}
completed = false;
}
// Update is called once per frame
void Update () {
if (completed){
return;
this.enabled = false;
}
if(0 < wayPoints.Length){
if (smooth)
FollowSmooth ();
else {
FollowClumsy ();
}
}
}
// Small methods to make job easy to read
// about the array of points
/// <summary>
/// Prevoius the specified Index, the points.Length must be > 0.
/// </summary>
/// <param name="Index">index on array points.</param>
Vector3 Prevoius(int index){
if (0 == index) {
return wayPoints [wayPoints.Length - 1];
} else {
return wayPoints [index - 1];
}
}
/// <summary>
/// Current at the specified Index.
/// </summary>
/// <param name="Index">index on array points.</param>
Vector3 Current(int index){
return wayPoints [index];
}
/// <summary>
/// Next of the specified index.
/// </summary>
/// <param name="Index">index on array points.</param>
Vector3 Next(int index){
if (wayPoints.Length == index+1) {
return wayPoints [0];
} else {
return wayPoints [index + 1];
}
}
void IncreaseIndex(){
currentPoint ++;
if (currentPoint == wayPoints.Length) {
if (justOnce)
completed = true;
else
currentPoint = 0;
}
}
//about 3d geometry
/// <summary>
/// Non smooth following
/// </summary>
void FollowClumsy(){
transform.LookAt (Current (currentPoint));
transform.position = Vector3.MoveTowards (transform.position, Current (currentPoint), speed*Time.deltaTime);
//if is close to the waypoint, pass to the next, if is the last, stop following
if ((transform.position-Current (currentPoint)).sqrMagnitude < (speed*Time.deltaTime) * (speed*Time.deltaTime) ) {
IncreaseIndex ();
}
}
int i = 1;
//the function try, just try, to apply the quadratic beizer algorithm, but thos is based on number of subdivisions, not by speed, so,
//the speed varies, usually on closed trurns so, to minimize it I put the splits dependig of speed, but, still is a problem
void FollowSmooth(){
Vector3 anchor1 = Vector3.Lerp (Prevoius (currentPoint), Current (currentPoint), .5f);
Vector3 anchor2 = Vector3.Lerp (Current (currentPoint), Next (currentPoint), .5f);
if (i < iterations) {
float currentProgress = (1f / (float)iterations) * (float)i;
transform.LookAt (Vector3.Lerp (anchor1, Current (currentPoint), currentProgress));
transform.position = Vector3.Lerp (Vector3.Lerp (anchor1, Current (currentPoint), currentProgress), Vector3.Lerp (Current (currentPoint), anchor2, currentProgress), currentProgress);
i++;
} else {
i = 1;
IncreaseIndex ();
Vector3 absisa = Vector3.Lerp (Vector3.Lerp (anchor1, Current (currentPoint), .5f), Vector3.Lerp (Current (currentPoint), anchor2, .5f), .5f);
float it = (((anchor1-absisa).magnitude + (anchor2 - absisa).magnitude)/(speed*Time.deltaTime));
iterations = (int)it;
}
}
/// <summary>
/// you can also split the vertexs of the LineRenderer, and you know how to assign it, with setvertex
/// </summary>
/// <returns>The vertex.</returns>
/// <param name="numSplit">Number split.</param>
Vector3[] SplitVertex(int numSplit){
Vector3[] ret = new Vector3[numSplit*wayPoints.Length];
for(int oldPoint = 0; oldPoint <wayPoints.Length; oldPoint++) {
Vector3 anchor1 = Vector3.Lerp (Prevoius (oldPoint), Current (oldPoint), .5f);
Vector3 anchor2 = Vector3.Lerp (Current (oldPoint), Next (oldPoint), .5f);
for (int j = 1; j < numSplit; j++) {
float currentProgress = (1f / (float)iterations) * (float)i;
ret[oldPoint*numSplit + j] = Vector3.Lerp (Vector3.Lerp (anchor1, Current (oldPoint), currentProgress), Vector3.Lerp (Current (oldPoint), anchor2, currentProgress), currentProgress);
}
IncreaseIndex ();
}
return ret;
}
}
here the object (white capsules) following diffetent paths (pink LineRenderers) using the smooth interpolation (white TrailRenderers)
wow (: , i don't know how to thank you man. i think your solution pretty much works.but i don't know how to set up the scene to make work like you did could you please upload the scene you have created?
is weird that the answers forum dont let you upload small .unitypackages directly to the server, just pdf, tar.gz....
so after try upload a tar.gz here and fail several times... a external file, hope they accept this
thanks man really appreciate it.so i tried your scene but your line renderers were pre set up.so i make a simple scene in which you can draw a line renderer on a plane .the problem is the object doesn't know when i draw a new line and to get it work i have to manually disable and enable line follower script. and by the way i when check "just once" box and draw a new line i get an error and the object won't move again at all here https://www.mediafire.com/file/b57z29najb1k7f6/draw+line.unitypackage
Answer by darkStar27 · May 08, 2019 at 07:11 AM
Really Good Answer @DCordoba
But just for everyone else that comes here,
you can also use LeanTween or any of the other Tweeners to work around this problem..
A much simpler way to define a path.
can it draw a smooth line and make a normal game object follow the line with some kinda speed and delay variables?
Absolutely, its made for the same..
And with tweening you can do this in a much simpler way.
Just download the asset and try, it also has many examples that you can refer from.
so which scene is about drawing lines at run time?