короче на юнити сделай систему арров систем типо стрелочки, она нужна мне для того чтобы показывать пользователю определенные элементы. тоесть типо есть метод в системе принимающей список геймобжектов и на каждом геймобжекте она создает стрелочку из префаба ну тоесть позиция на каждом. а и до этого она очищает текущие стрелочки если они есть. и вот где стрелочки буду использоваться. во время того как показался этап сборки и вот на посмотреть все блюпринты спарсить какие у них там имя детали и найти все эти детали на сцене с таким же именем и указать на них стрелку. 2 случай когда я схватил определенную деталь нужно посмотреть её имя и найти все блюпринты куда подходит эта деталь! вот кода using System.Collections.Generic;
using AYellowpaper.SerializedCollections;
using EasyButtons;
using UnityEngine;
using UnityEngine.Events;

public class BlueprintManager : StaticInstance<BlueprintManager>
{
    public List<Blueprint> blueprints;
    public UnityEvent onAllBlueprintsFilled;

    public int currentStageIndex = 0;

    public SerializedDictionary<int, List<Blueprint>> blueprintsByStage =
        new SerializedDictionary<int, List<Blueprint>>();

    private int totalStages = 0;

    public void ClearAll()
    {
        blueprints.Clear();
        blueprintsByStage.Clear();
        currentStageIndex = 0;
        BlueprintUIManager.Instance.SetUIActive(false);
    }

    public void SubscribeAllBlueprints(List<DronePart> droneParts, bool showUI)
    {
        ClearAll();

        // Подписываемся на события заполнения каждого блюпринта
        foreach (var dronePart in droneParts)
        {
            if (dronePart.TryGetComponent(out Blueprint blueprint))
            {
                if (blueprint.stageIndex == -1)
                {
                    Debug.LogError("Not signet blueprint", blueprint);
                }
                
                if (!blueprintsByStage.ContainsKey(blueprint.stageIndex))
                {
                    blueprintsByStage[blueprint.stageIndex] = new List<Blueprint>();
                }

                blueprintsByStage[blueprint.stageIndex].Add(blueprint);

                // Подписываемся на событие заполнения блюпринта
                blueprint.OnBlueprintFilled += OnBlueprintFilled;

                // Устанавливаем видимость блюпринта в зависимости от текущего этапа
                if (blueprint.stageIndex == currentStageIndex)
                {
                    blueprint.gameObject.SetActive(true);
                }
                else
                {
                    blueprint.gameObject.SetActive(false);
                }

                blueprints.Add(blueprint);
            }
        }

        // Определяем общее количество этапов
        totalStages = blueprintsByStage.Keys.Count;

        BlueprintUIManager.Instance.SetUIActive(showUI);
        UpdateUI();
    }

    private void OnBlueprintFilled(Blueprint bp)
    {
        NotifyExamManager();
        // Проверяем, заполнены ли все блюпринты текущего этапа
        bool stageCompleted = true;
        foreach (Blueprint blueprint in blueprintsByStage[currentStageIndex])
        {
            if (!blueprint.IsFilled)
            {
                stageCompleted = false;
                break;
            }
        }

        
        UpdateUI();

        if (stageCompleted)
        {
            ProceedToNextStage();
        }
    }

    [Button]
    private void ProceedToNextStage()
    {
        // Скрываем блюпринты предыдущего этапа
        foreach (Blueprint bp in blueprintsByStage[currentStageIndex])
        {
            bp.gameObject.SetActive(false);
        }

        currentStageIndex++;

        // Проверяем, есть ли следующий этап
        if (blueprintsByStage.ContainsKey(currentStageIndex))
        {
            // Показываем блюпринты нового этапа
            foreach (Blueprint bp in blueprintsByStage[currentStageIndex])
            {
                bp.gameObject.SetActive(true);
            }

            UpdateUI();
        }
        else
        {
            Debug.Log("Сборка завершена!");
            onAllBlueprintsFilled.Invoke();

            BlueprintUIManager.Instance.SetUIActive(false);
        }
    }

    private void NotifyExamManager()
    {
        ExamManager.Instance?.IncrementDetailCount();
    }

    private void Start()
    {
        onAllBlueprintsFilled.AddListener(OnAllBlueprintsFilled);
    }

    private void OnAllBlueprintsFilled()
    {
        ExamManager.Instance?.EndExam();
    }

    // Метод для обновления UI при инициализации
    private void UpdateUI()
    {
        int completedDetails = GetCompletedDetailsInCurrentStage();
        int totalDetails = blueprintsByStage[currentStageIndex].Count;
        BlueprintUIManager.Instance.UpdateUI(totalStages, currentStageIndex + 1, completedDetails, totalDetails);
    }

    // Метод для получения количества заполненных деталей на текущем этапе
    private int GetCompletedDetailsInCurrentStage()
    {
        int count = 0;
        foreach (Blueprint bp in blueprintsByStage[currentStageIndex])
        {
            if (bp.IsFilled)
                count++;
        }

        return count;
    }
}using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

public class DraggableHandle : MonoBehaviour, IDragHandler, IBeginDragHandler, IEndDragHandler, IPointerEnterHandler, IPointerExitHandler
{
    public GameObject targetObject;
    private DraggableObject draggableObjectScript;
    public UIColorChanger colorChanger;
    private int ignoreLayer;
    public bool isDrag;
    private Camera camera;
    
    public TMP_Text detailNameText;
    public Image image;

    void Start()
    {
        camera = Camera.main;
        ignoreLayer = LayerMask.NameToLayer("Ignore Raycast");
        if (colorChanger == null)
        {
            colorChanger = GetComponent<UIColorChanger>();
        }
    }

    public void Init(DraggableObject draggableObject)
    {
        targetObject = draggableObject.gameObject;
        draggableObjectScript = draggableObject;
        GetComponent<ResizeBasedOnDistance>().Init(targetObject.transform);
        detailNameText.text = draggableObjectScript.dronePart.name;
        ShowUI(false);
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        if (eventData.button == PointerEventData.InputButton.Left)
        {
            draggableObjectScript.EnableRigidbody(false);
            targetObject.layer = ignoreLayer; // Устанавливаем слой для игнорирования
            colorChanger?.SetColor(colorChanger.pressedColor);
            isDrag = true;

            ShowUI(true);
        }
    }

    public void OnDrag(PointerEventData eventData)
    {
        if (eventData.button == PointerEventData.InputButton.Left)
        {
            Ray ray = camera.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;

            // Игнорируем слой Ignore Raycast
            int layerMask = ~LayerMask.GetMask("Ignore Raycast");

            if (Physics.Raycast(ray, out hit, Mathf.Infinity, layerMask))
            {
                // Проверяем, попал ли рейкаст в блюпринт
                Blueprint blueprint = hit.collider.GetComponent<Blueprint>();
                if (blueprint != null && blueprint.dronePart.name == draggableObjectScript.dronePart.name)
                {
                    // Заменяем блюпринт объектом
                    targetObject.transform.position = blueprint.transform.position;
                    targetObject.transform.rotation = blueprint.transform.rotation;
                    targetObject.transform.localScale = blueprint.transform.localScale;
                    Debug.Log("Объект заменил блюпринт.");
                }
                else
                {
                    // Перемещаем объект на позицию попадания рейкаста
                    Vector3 targetPosition = hit.point;

                    // Размеры коллайдера
                    Vector3 colliderExtents = targetObject.GetComponent<Collider>().bounds.extents;

                    // Смещение объекта назад по направлению луча
                    Vector3 offset = ray.direction * colliderExtents.z * 0.5f;
                    targetPosition -= offset;

                    // Поднимаем объект на высоту его половины
                    targetPosition.y += colliderExtents.y;

                    // Смещаем объект вбок на половину его ширины
                    targetPosition.x -= colliderExtents.x * 0.5f;

                    targetObject.transform.position = targetPosition;
                }
            }

            // Обновляем позицию UI элемента
            transform.position = Input.mousePosition;
        }
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        if (eventData.button == PointerEventData.InputButton.Left)
        {
            Ray ray = camera.ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;

            // Игнорируем слой Ignore Raycast
            int layerMask = ~LayerMask.GetMask("Ignore Raycast");

            if (Physics.Raycast(ray, out hit, Mathf.Infinity, layerMask))
            {
                Blueprint blueprint = hit.collider.GetComponent<Blueprint>();
                if (blueprint != null && blueprint.dronePart.name == draggableObjectScript.dronePart.name)
                {
                    // Оставляем объект на месте и удаляем ненужные компоненты
                    targetObject.transform.position = blueprint.transform.position;
                    targetObject.transform.rotation = blueprint.transform.rotation;
                    targetObject.transform.localScale = blueprint.transform.localScale;

                    // Destroy(targetObject.GetComponent<Collider>());
                    Destroy(targetObject.GetComponent<Rigidbody>());
                    Destroy(gameObject);
                    blueprint.Fill(); // Уведомляем о заполнении

                    Debug.Log("Объект закреплен на месте блюпринта.");
                    blueprint.gameObject.SetActive(false);
                    targetObject.layer = 0; // Возвращаем объект на стандартный слой
                    return;
                }
            }

            targetObject.layer = 0; // Возвращаем объект на стандартный слой
            draggableObjectScript.EnableRigidbody(true);
            colorChanger?.SetColor(colorChanger.normalColor);
            isDrag = false;

            ShowUI(false);
        }
    }

    public void OnPointerEnter(PointerEventData eventData)
    {
        if (!isDrag)
        {
            colorChanger?.SetColor(colorChanger.hoverColor);

            ShowUI(true);
        }
    }

    public void OnPointerExit(PointerEventData eventData)
    {
        if (!isDrag)
        {
            colorChanger?.SetColor(colorChanger.normalColor);
            ShowUI(false);
        }
    }

    public void ShowUI(bool value)
    {
        detailNameText.gameObject.SetActive(value);
    }
}