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

Добрый день. У меня есть 4 переменные-префаба, которые рисуют линии с помощью LineRenderer, я хочу запускать 4 объекта по линиям (по цветам), а вернее по точкам Poistion который создаёт LineRenderer, чтобы каждый объект (цвет), передвигался по своей линии.
Делаю так:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DrawManager : MonoBehaviour
{
    private Camera _cam;
    [SerializeField] private Line1 LineYellow, LineBlue, LineGreen, LineRed;
    [SerializeField] private GameObject CarYellow, CarBlue, CarGreen, CarRed;
    private List<Vector3> linePointsBlue = new List<Vector3>(), linePointsYellow = new List<Vector3>(), linePointsRed = new List<Vector3>(), linePointsGreen = new List<Vector3>();

    public bool startDrive = false;
    public float speed = 10f, rotationSpeed = 20f;
    private int targetPointIndex;
    private Vector3 targetPoint;
    public const float RESOLUTION = .2f;
    private Line1 _currentLine;
    private bool _isDrawing = false, canDrawBlue = true, canDrawYellow = true, canDrawGreen = true, canDrawRed = true;
    private string carFlag = "";

    void Start()
    {
        _cam = Camera.main;
    }

    void Update()
    {
        Vector2 mousePos = _cam.ScreenToWorldPoint(Input.mousePosition);

        if (Input.GetMouseButtonDown(0))
        {
            Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
            RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction);

            if (hit.collider != null)
            {
                if (hit.collider.name.Contains("Blue") && canDrawBlue)
                {
                    _currentLine = Instantiate(LineBlue, mousePos, Quaternion.identity);
                    _isDrawing = true;
                    carFlag = "Blue";
                }
                else if (hit.collider.name.Contains("Yellow") && canDrawYellow)
                {
                    _currentLine = Instantiate(LineYellow, mousePos, Quaternion.identity);
                    _isDrawing = true;
                    carFlag = "Yellow";
                }
                else if (hit.collider.name.Contains("Green"))
                {
                    Debug.Log("You clicked on a Green car!");
                }
                else if (hit.collider.name.Contains("Red"))
                {
                    Debug.Log("You clicked on a Red car!");
                }
            }
            else
            {
                _isDrawing = false;
            }
        }

        if (Input.GetMouseButtonUp(0) && _isDrawing)
        {
            Ray ray = _cam.ScreenPointToRay(Input.mousePosition);
            RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction);

            if (carFlag == "Blue" && hit.collider != null && hit.collider.name.Contains("Blue") && hit.collider.CompareTag("Parking"))
            {
                Debug.Log("Ok! Blue Parking");
                canDrawBlue = false;

                GameObject lineObject = GameObject.Find("LineBlue [Prefab](Clone)");

                LineRenderer lineRenderer = lineObject.GetComponent<LineRenderer>();

                Vector3[] positions = new Vector3[lineRenderer.positionCount];
                lineRenderer.GetPositions(positions);

                foreach (Vector3 position in positions)
                {
                    // Add the position to the sheet (replace "sheet" with the name of your sheet variable)
                    linePointsBlue.Add(position);
                }
            } 
            else if (carFlag == "Yellow" && hit.collider != null && hit.collider.name.Contains("Yellow") && hit.collider.CompareTag("Parking")) 
            {
                Debug.Log("Ok! Yellow Parking");
                canDrawYellow = false;
            }
            else
            {
                _currentLine.ClearPositions();
                Destroy(_currentLine.gameObject);
            }

            _isDrawing = false;
        }

        if (Input.GetMouseButton(0) && _isDrawing)
        {
            _currentLine.SetPosition(mousePos);
        }

        if (startDrive) {
            Drive(linePointsBlue, CarBlue);
        }

    }

    private void Drive(List<Vector3> linePoints, GameObject Car) {

        targetPointIndex = 1;      

        targetPoint = linePoints[targetPointIndex];

        Quaternion targetRotation = Quaternion.LookRotation(Vector3.forward, targetPoint - Car.transform.position);
        Car.transform.rotation = targetRotation;

        Car.transform.rotation = Quaternion.Lerp(Car.transform.rotation, targetRotation, rotationSpeed * Time.deltaTime);

        Vector3 direction = (targetPoint - Car.transform.position).normalized;
        Car.transform.position += direction * speed * Time.deltaTime;

        if (Vector3.Distance(Car.transform.position, targetPoint) < 0.1f)
        {
            targetPointIndex++;
            if (targetPointIndex < linePoints.Count)
            {
                targetPoint = linePoints[targetPointIndex];
            }
        }

    }

}

И соответственно:
[SerializeField] private Line1 LineYellow, LineBlue, LineGreen, LineRed; // Линии с ЛайнРендерер из скрипта Line 1
    [SerializeField] private GameObject CarYellow, CarBlue, CarGreen, CarRed; // Объекты, которые нужно двигать

Скрипт Line1.cs:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Line1 : MonoBehaviour
{
    [SerializeField] private LineRenderer _renderer;

    private readonly List<Vector2> _points = new List<Vector2>();

    public void SetPosition(Vector2 pos)
    {
        if (!CanAppend(pos)) return;

        _points.Add(pos);

        _renderer.positionCount++;
        _renderer.SetPosition(_renderer.positionCount - 1, pos);
    }

    public void ClearPositions()
    {
        _points.Clear();
        _renderer.positionCount = 0;
    }

    private bool CanAppend(Vector2 pos)
    {
        if (_renderer.positionCount == 0) return true;

        return Vector2.Distance(_renderer.GetPosition(_renderer.positionCount - 1), pos) > DrawManager.RESOLUTION;
    }
}

В итоге для начала пытаюсь запустить Синий объект он начинает движение по первой точке буквально и на второй останавливается и ничего не происходит. Помогите пожалуйста решить проблему.
  • Вопрос задан
  • 131 просмотр
Решения вопроса 1
@Ezekiel4
Охотник на пиратов и сборщик монолитов
Я не знаю, будет ли работать нормально сам код движения, но ваша проблема связана больше с логикой вызова кода движения. Сами посудите, сначала вызывается Update (каждый раз, когда обновляется экран), затем в нём вызывается метод Drive. Напоминаю, каждое обновление экрана, т.е. много раз в секунду.
Сам же метод сходу берёт и обнуляет прогресс движения:
targetPointIndex = 1;
Всё, что ниже, уже просто не имеет смысла.

Лично я рекомендую вам воспользоваться принципом SRP и делегировать функционал движения отдельному классу. Что-то типа такого:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class LineRendererFollower : MonoBehaviour {

	public LineRenderer lineRenderer;
	public float speed;
	public int nextPointIndex;

	Vector3[] positions;

	void Start() {
		positions = new Vector3[lineRenderer.positionCount];
		lineRenderer.GetPositions(positions);
	}

	void FixedUpdate() {
		if (Vector3.Distance(transform.position, positions[nextPointIndex]) > 0) {
			transform.position = Vector3.MoveTowards(transform.position, positions[nextPointIndex], speed * Time.fixedDeltaTime);
		} else if (nextPointIndex + 1 < positions.Length) {
			nextPointIndex++;
			transform.right = (positions[nextPointIndex] - transform.position);
		} else {
			// то, что должно случится в конце пути
		}
	}
}
Ответ написан
Комментировать
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы