UI элементы. OnDrag и OnPointerDown при переключении скрипта

Программирование на Юнити.

UI элементы. OnDrag и OnPointerDown при переключении скрипта

Сообщение Roman777 12 май 2019, 21:36

Добрый день!
Есть ScrollRect, элементами которого являются кнопки.
Хотел, чтобы при разворачивания скролла можно было бы перемещать эти кнопки. Если на кнопку нажать и подержать, должен появиться спрайт, который бы уже следовал за пальцем (указателем мышкой) по событию OnDrag(). Дело в том, что когда переопределяется функция OnDrag(), то сам скролл пререстаёт работать. Поэтому я решил немного исхитриться и создал 2 скрипта.
Один наследует все 3 функции события Drag() и называется "ButtnDragMe", а второй наследует функции событий нажатия и называется "ButtnScrollMe". В изначальном состоянии компонента скрипта "ButtnDragMe" выключена и работает "ButtnScrollMe" (который не использует событийные ф-ии Drag(). Получается, я могу скроллить. А при удержании 0.5 секунд иконки (кнопки), скрипт "ButtnDragMe" включается и выключается "ButtnScrollMe".
Проблема в том, что при включении "ButtnDragMe" события Drag сразу не работают. Требуется отпустить левую клавишу мыши и снова нажав только уже с активным "ButtnDragMe", у меня получается перемещать курсором появившийся спрайт.

Не получается избавиться от этого лишнего снятия нажатия и продолжить сразу перемещать, вызывая события Drag() (хотя бы OnDrag) по новому, активировавшемуся компоненту скрипта "ButtnDragMe". Как ещё сделать такое переключение на перемещение Drag-ом при удержании скроллируемой кнопки, пока не могу представить.
Подскажите, пожалуйста, варианты решения.


Код "ButtnScrollMe"
Синтаксис:
Используется csharp
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;


[RequireComponent(typeof(Image))]
public class ButtnScrollMe : MonoBehaviour, IPointerDownHandler, IPointerUpHandler{
        public bool dragOnSurfaces = true;

//      private int Mode = 2;

        private bool bStrtTime = false;
        private float startTime = 0f;
        private float waitTime = 0.5f;
        private bool onbegin = false;
        private bool ongoing = false;
        private bool onend = false;

        public PointerEventData eData;

        public void OnPointerDown(PointerEventData eventData){
                if (!bStrtTime) {
                        startTime = Time.time;
                        bStrtTime = true;
                        eData = eventData;
//                      this.gameObject.GetComponent<ButtnDragMe> ().eData = eventData;
                }
        }
        public void Update(){
                //If starts counting time
                if (bStrtTime) {
                        if (!onbegin && !ongoing) {
                                if (Time.time > startTime + waitTime) {
                                        //onBegin
                                        onbegin = true;
                                }
                        }
                        if (onbegin) {
                                ongoing = true;
                                onbegin = false;
                                bStrtTime = false;
                                SetChangeEvent ();
                        }
                }
                if (onend) {
                        onend = false;
                }
        }

        public void OnPointerUp(PointerEventData eventData){
                bStrtTime = false;
                ongoing = false;
                onbegin = false;
                onend = true;
        }

        private void SetChangeEvent(){
                this.gameObject.GetComponent<ButtnDragMe>().enabled = true;
                this.enabled = false;
        }
}
Roman777
UNIт
 
Сообщения: 95
Зарегистрирован: 06 мар 2016, 12:09

Re: UI элементы. OnDrag и OnPointerDown при переключении скрипта

Сообщение Roman777 19 май 2019, 18:52

Если кому будет интересно, то задачу скроллируемых кнопок с драгом получилось решить следующим образом:
Создал класс, наследуемый от ScrollRect, где добавил булевое поле (public bool ScrollDisabled), которое определяет, что класс должен делать: скроллировать иди драггать картинку от кнопки:
Синтаксис:
Используется csharp
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

[RequireComponent(typeof(Image))]
public class DraggingScroll : ScrollRect, IBeginDragHandler , IDragHandler, IEndDragHandler {
        public bool dragOnSurfaces = true;

        private GameObject m_DraggingIcon;
        private RawImage image;
        private RectTransform rt;

        private Image MainIMG; //Ссылка на Image кнопки
        private Color nullColor; //начальный цвет кнопки
        private RectTransform m_DraggingPlane;
        private static bool flgCrossed = false;

        private static GameObject curCrGO; //Ссылка на пересекаемый объект
        private static MainLine curML;//Ссылка на MainLine этого (Пересекаемого) объекта
        private static GameObject Locker=null;//Объект с коллайдером для отслеживания пересечений

        private static float W_Weight, W_Height, W_Length;

        public PointerEventData eData;
        public  Texture2D TextureOfSprite;

        private bool bStrtTime = false;
        private float startTime = 0f;
        private float waitTime = 0.5f;
        private bool onbegin = false;
        private bool ongoing = false;
        private bool onend = false;
        public bool ScrollDisabled = false;


        public void OnBeginDrag(PointerEventData eventData){
                if (!ScrollDisabled) {
                        base.OnBeginDrag (eventData);
                }else{
                        var canvas = FindInParents<Canvas> (gameObject);//canvas = GameObject.Find ("Canvas");
                        if (canvas == null)
                                return;
                        MainIMG = this.GetComponent<Image> ();
                        nullColor = MainIMG.color;
                        // We have clicked something that can be dragged.
                        // What we want to do is create an icon for this.

                        m_DraggingIcon = GameObject.Find ("DraggingIcon");//На случай нажатия двух кнопок
                        if (m_DraggingIcon == null) {
                                m_DraggingIcon = new GameObject ("DraggingIcon");
                        }

                        m_DraggingIcon.transform.SetParent (canvas.transform, false);
                        m_DraggingIcon.transform.SetAsLastSibling ();

                        image = m_DraggingIcon.GetComponent<RawImage> ();
                        if (image == null) {
                                image = m_DraggingIcon.AddComponent<RawImage> ();
                        }

                        image.texture = TextureOfSprite;

                        rt = m_DraggingIcon.GetComponent<RectTransform> ();
                        rt.localRotation = new Quaternion (0, 0, 0, 1);
                        rt.pivot = new Vector2 (0.5f, 0.5f);
                        rt.anchorMax = new Vector2 (1, 0);
                        rt.anchorMin = rt.anchorMax;

                        rt.anchoredPosition = new Vector2 (1, 0);
                        rt.sizeDelta = new Vector2 (1, 1); // размеры проёма

                        image.SetNativeSize ();
                        if (dragOnSurfaces)
                                m_DraggingPlane = transform as RectTransform;
                        else
                                m_DraggingPlane = canvas.transform as RectTransform;

                        SetDraggedPosition (eventData);

                        NewScene.Mode = NewScene.Modes.CreatingWalls;
                        Locker = new GameObject ("Locker");
                        MeshCollider MCldr = Locker.AddComponent<MeshCollider> ();
                        Mesh template = null;
                        float ScaleK = 1.1f; //Увеличивающий меш таргета коэффициент. чтобы точно не резать там, где могут быть ошибки
                        if (All.CurTypeWindow == 0) {
                                W_Weight = 0.2f * 1.2f;//!!!!!!!!!!!!!! пока не правильно ! У каждой стены своя толщина
                                W_Height = 2f;//All.WallCurHeight/2; //!!!!!!!!!!!!!пока не верно
                                W_Length = All.DefaultWindowLength;//1метр по умолчанию
                                template = PolCreate.ParallelepipedMesh (W_Weight * ScaleK, W_Length * ScaleK, W_Height);
                                Vector3 pntWorld = Camera.main.ScreenToWorldPoint (new Vector3 (0, 0, Camera.main.transform.position.y));

                                Locker.transform.position = pntWorld;
                                Locker.transform.position = pntWorld + new Vector3 (0f, W_Height, 0f);
                        } else if (All.CurTypeWindow == 1) {
                                W_Weight = All.WallCurWeight * 1.2f;
                                W_Height = 2f;//3*All.WallCurHeight/4+0.1f; //3/4
                                W_Length = All.DefaultWindowLength;//1метр по умолчанию
                                template = PolCreate.ParallelepipedMesh (W_Weight * ScaleK, W_Length * ScaleK, W_Height);
                                Vector3 pntWorld = Camera.main.ScreenToWorldPoint (new Vector3 (0, 0, Camera.main.transform.position.y));

                                Locker.transform.position = pntWorld;
                                Locker.transform.position = pntWorld + new Vector3 (0f, W_Height / 2 - 0.05f, 0f);
                        }
                        Locker.AddComponent<CrossHandler> ();

                        Locker.layer = All.ApertureLayer;
                        Rigidbody RB = Locker.AddComponent<Rigidbody> ();
                        RB.isKinematic = true;

                        MCldr.sharedMesh = template;
                        MCldr.convex = true; //for moving
                        MCldr.isTrigger = true;
                }
        }

        public void OnDrag(PointerEventData data){
                if (!ScrollDisabled) {
                        base.OnDrag (data);
                } else {
                        RaycastHit _hit;
                        Ray _ray = Camera.main.ScreenPointToRay (new Vector3 (Input.mousePosition.x, Input.mousePosition.y, 0));
                        if (Physics.Raycast (_ray, out _hit, NewScene.distanceToCam, NewScene.bitMaskMeshColl)) {
                                MeshCollider MeshCol = (MeshCollider)_hit.collider; //Объект, по которому пульнули (нажали)
                                curCrGO = MeshCol.gameObject;
                                curML = PoligActions.dGoToMainLine [MeshCol.gameObject];

                                MainLine goML = curML;
                                Vector2 v0 = Camera.main.WorldToScreenPoint (goML.line.v [0]);
                                Vector2 v1 = Camera.main.WorldToScreenPoint (goML.line.v [1]);
                                Vector2 MLV = v1 - v0;
                                Vector2 Vpointer = data.position - v0;

                                Vector2 tmpV = (Vector2)Vector3.Project (Vpointer, MLV) + v0;
                                rt.position = tmpV;
                                //Ниже векторное произведение позволяет нам узнать знак угла
                                Vector3 AnglV3 = new Vector3 (0, 0, Vector2.Angle (MLV, Vector2.right)) * -1 * Mathf.Sign (Vector3.Cross (MLV, Vector2.right).z);
                                Quaternion AnglQ = Quaternion.Euler (AnglV3);
                                rt.rotation = AnglQ;

                                Vector3 tmpPos = Camera.main.ScreenToWorldPoint (new Vector3 (rt.position.x, rt.position.y, Camera.main.transform.position.y));
                                tmpPos = tmpPos + new Vector3 (0f, W_Height / 2 - 0.05f, 0f);
                                Locker.transform.position = tmpPos;
                                Locker.transform.rotation = Quaternion.Euler (new Vector3 (0f, curML.angleRad * 180 / All.Pi, 0f));
                                if (!CrossHandler.flg) {
                                        flgCrossed = true;
                                        image.color = Color.green;
                                        MainIMG.color = Color.green;
                                } else {
                                        flgCrossed = false;
                                        image.color = Color.red;
                                        MainIMG.color = Color.red;
                                }
                        } else {
                                if (m_DraggingIcon != null) {
                                        SetDraggedPosition (data);
                                }
                                flgCrossed = false;
                                image.color = Color.white;
                                MainIMG.color = nullColor;
                        }
                        NewScene.Mode = NewScene.Modes.CreatingWindow;
                }
        }

        private void SetDraggedPosition(PointerEventData data){
                if (dragOnSurfaces && data.pointerEnter != null && data.pointerEnter.transform as RectTransform != null)
                        m_DraggingPlane = data.pointerEnter.transform as RectTransform;

                Vector3 globalMousePos;

                if (RectTransformUtility.ScreenPointToWorldPointInRectangle (m_DraggingPlane, data.position, data.pressEventCamera, out globalMousePos)) {
                        if (globalMousePos.x > 4 * Screen.width / 5) {
                                globalMousePos.x = 4 * Screen.width / 5;
                        }

                        rt.position = globalMousePos;
                        rt.rotation = Quaternion.Euler (Vector2.right);//m_DraggingPlane.rotation;
                }
        }

        public void OnEndDrag(PointerEventData eventData)
        {
               
                Debug.Log("OnEndDragInButtnDragMe");
                if (!ScrollDisabled) {
                        base.OnEndDrag (eventData);
                } else {
                        Destroy (Locker.GetComponent<MeshCollider> ().sharedMesh);
                        Destroy (Locker);
                        CrossHandler.flg = false;

                        NewScene.Mode = NewScene.Modes.CreatingWalls;
                        if (flgCrossed) {
                                Vector2 rotEl = rt.rotation.eulerAngles;
                                DVmanager.СutWindow (curCrGO, rt.position, new Vector3 (0f, curML.angleRad * 180 / All.Pi, 0f), All.CurTypeWindow);
                        }
                        if (m_DraggingIcon != null) {
                                Destroy (m_DraggingIcon);
                        }
                        MainIMG.color = nullColor;
                        ScrollDisabled = false;
                }
        }

        static public T FindInParents<T>(GameObject go) where T : Component{
                if (go == null) return null;
                var comp = go.GetComponent<T>();

                if (comp != null)
                        return comp;

                Transform t = go.transform.parent;
                while (t != null && comp == null)
                {
                        comp = t.gameObject.GetComponent<T>();
                        t = t.parent;
                }
                return comp;
        }


}

а управляется функция скролла по нажатию (удержанию кнопки), на которой будет скрипт:
Синтаксис:
Используется csharp
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;


public class ButtnScrollMe : MonoBehaviour, IPointerDownHandler, IPointerUpHandler{
        private bool bStrtTime = false;
        private float startTime = 0f;
        private float waitTime = 0.5f;
        private bool onbegin = false;
        private bool ongoing = false;
        private bool onend = false;

        public PointerEventData eData;
        public DraggingScroll ScrllRctLink = null;


        public void OnPointerDown(PointerEventData eventData){
                if (!bStrtTime) {
                        startTime = Time.time;
                        bStrtTime = true;
                        eData = eventData;
                }
        }
        public void Update(){
                //If starts counting time
                if (bStrtTime) {
                        if (!onbegin && !ongoing) {
                                if (Time.time > startTime + waitTime) {
                                        //onBegin
                                        onbegin = true;
                                }
                        }
                        if (onbegin) {
//                              ongoing = true;
                                onbegin = false;
                                bStrtTime = false;
                                SetChangeEvent ();
                        }
                }
                if (onend) {
                        onend = false;
                }
        }

        public void OnPointerUp(PointerEventData eventData){
                bStrtTime = false;
                ongoing = false;
                onbegin = false;
                onend = true;
        }
        private void SetChangeEvent(){
                ScrllRctLink.ScrollDisabled = true;
                ScrllRctLink.TextureOfSprite = this.GetComponent<Image> ().sprite.texture;
        }
}

Скролл создаю в коде динамически и вместо ScrollRect использую именно DraggingScroll;
При создании кнопок внутри объекта DraggingScroll, я записывал ссылку в public ScrllRctLink на используемый объект DraggingScroll и уже по нему в SetChangeEvent изменяю тип реакции на эвенты.
Roman777
UNIт
 
Сообщения: 95
Зарегистрирован: 06 мар 2016, 12:09


Вернуться в Скрипты

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 15