Я работаю над приложением 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.Пожалуйста, простите меня за неточность, я начинающий программист, а английский не мой родной язык!