/* * Copyright (c) Meta Platforms, Inc. and affiliates. * All rights reserved. * * Licensed under the Oculus SDK License Agreement (the "License"); * you may not use the Oculus SDK except in compliance with the License, * which is provided at the time of installation or download, or which * otherwise accompanies this software in either electronic or hard copy form. * * You may obtain a copy of the License at * * https://developer.oculus.com/licenses/oculussdk/ * * Unless required by applicable law or agreed to in writing, the Oculus SDK * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using UnityEngine; namespace Oculus.Interaction { /// /// Gradually pulls the selected interactable towards your interactor. /// public class AutoMoveTowardsTargetProvider : MonoBehaviour, IMovementProvider { [SerializeField] private PoseTravelData _travellingData = PoseTravelData.DEFAULT; public PoseTravelData TravellingData { get { return _travellingData; } set { _travellingData = value; } } [SerializeField, Interface(typeof(IPointableElement))] private UnityEngine.Object _pointableElement; public IPointableElement PointableElement { get; private set; } private bool _started; public List _movers = new List(); protected virtual void Awake() { PointableElement = _pointableElement as IPointableElement; } protected virtual void Start() { this.BeginStart(ref _started); this.AssertField(_pointableElement, nameof(_pointableElement)); this.EndStart(ref _started); } private void LateUpdate() { for (int i = _movers.Count - 1; i >= 0; i--) { AutoMoveTowardsTarget mover = _movers[i]; if (mover.Aborting) { mover.Tick(); if (mover.Stopped) { _movers.Remove(mover); } } } } public IMovement CreateMovement() { AutoMoveTowardsTarget mover = new AutoMoveTowardsTarget(_travellingData, PointableElement); mover.WhenAborted += HandleAborted; return mover; } private void HandleAborted(AutoMoveTowardsTarget mover) { mover.WhenAborted -= HandleAborted; _movers.Add(mover); } #region Inject public void InjectAllAutoMoveTowardsTargetProvider(IPointableElement pointableElement) { InjectPointableElement(pointableElement); } public void InjectPointableElement(IPointableElement pointableElement) { PointableElement = pointableElement; _pointableElement = pointableElement as UnityEngine.Object; } #endregion } /// /// This IMovement stores the initial Pose, and in case /// of an aborted movement it will finish it itself. /// public class AutoMoveTowardsTarget : IMovement { private PoseTravelData _travellingData; private IPointableElement _pointableElement; public Pose Pose => _tween.Pose; public bool Stopped => _tween == null || _tween.Stopped; public bool Aborting { get; private set; } public Action WhenAborted = delegate { }; private UniqueIdentifier _identifier; public int Identifier => _identifier.ID; private Tween _tween; private Pose _target; private Pose _source; private bool _eventRegistered; public AutoMoveTowardsTarget(PoseTravelData travellingData, IPointableElement pointableElement) { _identifier = UniqueIdentifier.Generate(Context.Global.GetInstance(), this); _travellingData = travellingData; _pointableElement = pointableElement; } public void MoveTo(Pose target) { AbortSelfAligment(); _target = target; _tween = _travellingData.CreateTween(_source, target); if (!_eventRegistered) { _pointableElement.WhenPointerEventRaised += HandlePointerEventRaised; _eventRegistered = true; } } public void UpdateTarget(Pose target) { _target = target; _tween.UpdateTarget(_target); } public void StopAndSetPose(Pose pose) { if (_eventRegistered) { _pointableElement.WhenPointerEventRaised -= HandlePointerEventRaised; _eventRegistered = false; } _source = pose; if (_tween != null && !_tween.Stopped) { GeneratePointerEvent(PointerEventType.Hover); GeneratePointerEvent(PointerEventType.Select); Aborting = true; WhenAborted.Invoke(this); } } public void Tick() { _tween.Tick(); if (Aborting) { GeneratePointerEvent(PointerEventType.Move); if (_tween.Stopped) { AbortSelfAligment(); } } } private void HandlePointerEventRaised(PointerEvent evt) { if (evt.Type == PointerEventType.Select || evt.Type == PointerEventType.Unselect) { AbortSelfAligment(); } } private void AbortSelfAligment() { if (Aborting) { Aborting = false; GeneratePointerEvent(PointerEventType.Unselect); GeneratePointerEvent(PointerEventType.Unhover); } } private void GeneratePointerEvent(PointerEventType pointerEventType) { PointerEvent evt = new PointerEvent(Identifier, pointerEventType, Pose); _pointableElement.ProcessPointerEvent(evt); } } }