Как обработать сенсорный выбор на Unity3D, используя бесплатный актив LeanTouch? - PullRequest
0 голосов
/ 13 ноября 2018

Я работаю над приложением AR, которое отслеживает самолеты с помощью ARCore и заставляет меня выбирать из серии различных моделей, которые я затем могу создать на самолете.После того, как модель была установлена ​​на сцене, я использовал бесплатный актив Lean Touch от Carlos Wilkes, чтобы взаимодействовать с ней с помощью жестов.Используя сценарии из этого ресурса, я также пытаюсь сделать так, чтобы круг появлялся под моделью, когда она выбрана, но, хотя она отлично работает, применяя компоненты на кубе непосредственно в сцене, я не могу заставить его работать, когда применяюкомпоненты через скрипт.

Это моя сцена .Он показывает, как я настраивал компоненты на своем кубе.

LeanSelectable - это скрипт из ресурса, который используется для определения, какие объекты могут быть выбраны.LeanSelectableCircle - мой сценарий, он расширяет LeanSelectableBehavior, абстрагирующий класс от ресурса, специально созданного для облегчения обработки выбираемых действий.Мой скрипт находит круг, дочерний элемент куба и переопределяет функции OnSelect и OnDeselect абстрактного класса.В методе OnSelect он активирует круг, делая его видимым при выделении объекта.В методе OnDeselect он деактивирует окружность, скрывая ее, когда объект не выделен.Как я уже сказал, эта комбинация компонентов отлично работает на кубе в сцене: если я выбираю куб, появляется круг, если я отменяю выбор куба, круг исчезает.

Это абстрактный класс:

public abstract class LeanSelectableBehaviour : MonoBehaviour
    {
        [System.NonSerialized]
        private LeanSelectable selectable;

        public LeanSelectable Selectable
        {
            get
            {
                if (selectable == null)
                {
                    UpdateSelectable();
                }

                return selectable;
            }
        }

        protected virtual void OnEnable()
        {
            UpdateSelectable();

            // Hook LeanSelectable events
            selectable.OnSelect.AddListener(OnSelect);
            selectable.OnSelectUp.AddListener(OnSelectUp);
            selectable.OnDeselect.AddListener(OnDeselect);
        }

        protected virtual void OnDisable()
        {
            UpdateSelectable();

            // Unhook LeanSelectable events
            selectable.OnSelect.RemoveListener(OnSelect);
            selectable.OnSelectUp.RemoveListener(OnSelectUp);
            selectable.OnDeselect.RemoveListener(OnDeselect);
        }

        // Called when selection begins (finger = the finger that selected this)
        protected virtual void OnSelect(LeanFinger finger)
        {
        }

        // Called when the selecting finger goes up (finger = the finger that selected this)
        protected virtual void OnSelectUp(LeanFinger finger)
        {
        }

        // Called when this is deselected, if OnSelectUp hasn't been called yet, it will get called first
        protected virtual void OnDeselect()
        {
        }

        private void UpdateSelectable()
        {
            if (selectable == null)
            {
                selectable = GetComponentInParent<LeanSelectable>();

                if (selectable == null)
                {
                    Debug.LogError("This GameObject or one of its parents must have the LeanSelectable component.", this);
                }
            }
        }
    }

Это мой класс:

public class LeanSelectableCircle : LeanSelectableBehaviour
    {
        GameObject circle;

        protected virtual void Awake()
        {
            circle = this.gameObject.transform.GetChild(1).gameObject;
            Debug.Log(circle.ToString());
        }

        protected override void OnSelect(LeanFinger finger)
        {
            circle.SetActive(true);
            Debug.Log("Oggetto selezionato");
        }

        protected override void OnDeselect()
        {
            circle.SetActive(false);
            Debug.Log("Oggetto deselezionato");
        }
    }

Наконец, у меня есть класс ARController, который обрабатывает все связанные с AR вещи, включаяразмещение модели на плоскости (модель создается в другом классе, но здесь это не актуально).После того как модель масштабируется, помещается в положение и становится дочерним элементом якоря, она создает экземпляр круга и устанавливает его в значение false, чтобы скрыть его.Затем я добавляю все необходимые компоненты, чтобы сенсорные жесты работали с активом LeanTouch.И затем я устанавливаю модель активной.

Это метод, который обрабатывает эту часть и вызывается во время функции Update () в ARController.

public void _InteractWithARScene()
    {
        Touch touch;
        if (Input.touchCount < 1 || (touch = Input.GetTouch(0)).phase != TouchPhase.Began) // If the player has not touched the screen, we are done with this update.
        {
            return;
        }
        _SpawnARObject();
    }

    public void _SpawnARObject()
    {
        Touch touch;
        touch = Input.GetTouch(0);

        TrackableHit hit;
        TrackableHitFlags raycastFilter = TrackableHitFlags.PlaneWithinPolygon | TrackableHitFlags.FeaturePointWithSurfaceNormal; // Raycast against the location the player touched to search for planes.

        if (!EventSystem.current.IsPointerOverGameObject(touch.fingerId)) //Evita di istanziare oggetti se il touch non è sopra un elemento dell'UI
        {
            if (Frame.Raycast(touch.position.x, touch.position.y, raycastFilter, out hit))
            {
                // Use hit pose and camera pose to check if hittest is from the back of the plane, if it is, no need to create the anchor.
                if ((hit.Trackable is DetectedPlane) && Vector3.Dot(FirstPersonCamera.transform.position - hit.Pose.position, hit.Pose.rotation * Vector3.up) < 0)
                {
                    Debug.Log("Hit at back of the current DetectedPlane");
                }
                else
                {
                    //Choose the Andy model for the Trackable that got hit.
                    GameObject modelObject = assetBundleSytem.transform.GetChild(0).gameObject;
                    //GameObject modelObject = GameObject.FindWithTag("NEW");
                    if (modelObject != null) Debug.Log("Model foud");


                    //Scale model
                    GameObject scaledObject = scalingCube.Scale(modelObject);
                    scaledObject.transform.SetPositionAndRotation(hit.Pose.position, hit.Pose.rotation);
                    scaledObject.tag = "AR";

                    // Compensate for the hitPose rotation facing away from the raycast (i.e. camera).
                    scaledObject.transform.Rotate(0, k_ModelRotation, 0, Space.Self);

                    // Create an anchor to allow ARCore to track the hitpoint as understanding of the physical world evolves.
                    var anchor = hit.Trackable.CreateAnchor(hit.Pose);

                    // Make Andy model a child of the anchor.
                    scaledObject.transform.parent = anchor.transform;

                    //Instantiate the circle that tells when the object is selected
                    GameObject circle = Instantiate(selectionCircle, scaledObject.transform, true) as GameObject;
                    circle.transform.SetPositionAndRotation(scaledObject.transform.position, circle.transform.rotation);
                    circle.SetActive(false);

                    //Add a MeshCollider Componet to the object mesh
                    GameObject modelObjectMesh = scaledObject.transform.GetChild(0).gameObject;
                    modelObjectMesh.AddComponent<MeshCollider>();

                    //Implement LeanTouch
                    scaledObject.AddComponent<LeanSelectable>();
                    scaledObject.AddComponent<LeanSelectableCircle>();

                    //Set the object to active
                    scaledObject.SetActive(true);
                }
            }
        }
    }

Когда он пытаетсяПри добавлении компонента LeanSelectableCircle к меделью вызывается функция OnEnable () LeanSelectableBehaviour, и она возвращает эту ошибку:

NullReferenceException: ссылка на объект не установлена ​​на экземпляр объекта Lean.Touch.LeanSelectableBehaviour.OnEnable () (в

Активы / LeanTouch / Примеры / Сценарии / LeanSelectableBehaviour.cs: 29) UnityEngine.GameObject: AddComponent () ARController: _SpawnARObject () (в Активы / Скрипты / ARCont:117) ARController: _InteractWithARScene () (в ресурсах / сценариях / ARController.cs: 64) ARController: обновление () (в ресурсах / сценариях / ARController.cs: 38)

Это моя сцена после того, как я поместил модель на плоскость. Он показывает все компоненты модели.Странно то, что если я деактивирую модель, а затем снова активирую ее в инспекторе во время воспроизведения сцены, то она работает нормально!

Я не могу по жизни понять, что я делаю неправильно, поэтому любая помощь будет оценена, спасибо!

Ps.Пожалуйста, простите меня за неточность, я начинающий программист, а английский не мой родной язык!

...