public void ForceResetButton()
        {
            var oldState = CurrentButtonState;

            CurrentButtonState = InteractableState.Default;
            InteractableStateChanged?.Invoke(new InteractableStateArgs(this, null,
                                                                       CurrentButtonState, oldState, new ColliderZoneArgs(ContactCollider, Time.frameCount,
                                                                                                                          null, InteractionType.Exit)));
        }
Beispiel #2
0
        public override void UpdateCollisionDepth(InteractableTool interactableTool,
                                                  InteractableCollisionDepth oldCollisionDepth,
                                                  InteractableCollisionDepth newCollisionDepth)
        {
            bool isFarFieldTool = interactableTool.IsFarFieldTool;

            // if this is a near field tool and another tool already controls it, bail.
            if (!isFarFieldTool && _toolToState.Keys.Count > 0 && !_toolToState.ContainsKey(interactableTool))
            {
                return;
            }

            var oldState = _currentButtonState;

            // ignore contact test if you are using the far field tool
            var  currButtonDirection = transform.TransformDirection(_localButtonDirection);
            bool validContact        = IsValidContact(interactableTool, currButtonDirection) ||
                                       interactableTool.IsFarFieldTool;
            // in case tool enters contact zone first, we are in proximity as well
            bool toolIsInProximity = newCollisionDepth >= InteractableCollisionDepth.Proximity;
            bool toolInContactZone = newCollisionDepth == InteractableCollisionDepth.Contact;
            bool toolInActionZone  = newCollisionDepth == InteractableCollisionDepth.Action;

            bool switchingStates = oldCollisionDepth != newCollisionDepth;

            if (switchingStates)
            {
                FireInteractionEventsOnDepth(oldCollisionDepth, interactableTool,
                                             InteractionType.Exit);
                FireInteractionEventsOnDepth(newCollisionDepth, interactableTool,
                                             InteractionType.Enter);
            }
            else
            {
                FireInteractionEventsOnDepth(newCollisionDepth, interactableTool,
                                             InteractionType.Stay);
            }

            var upcomingState = oldState;

            if (interactableTool.IsFarFieldTool)
            {
                upcomingState = toolInContactZone ? InteractableState.ContactState :
                                toolInActionZone ? InteractableState.ActionState : InteractableState.Default;
            }
            else
            {
                // plane describing positive side of button
                var buttonZonePlane = new Plane(-currButtonDirection, _buttonPlaneCenter.position);
                // skip plane test if the boolean flag tells us not to test it
                bool onPositiveSideOfButton = !_makeSureToolIsOnPositiveSide ||
                                              buttonZonePlane.GetSide(interactableTool.InteractionPosition);
                upcomingState = GetUpcomingStateNearField(oldState, newCollisionDepth,
                                                          toolInActionZone, toolInContactZone, toolIsInProximity,
                                                          validContact, onPositiveSideOfButton);
            }

            if (upcomingState != InteractableState.Default)
            {
                _toolToState[interactableTool] = upcomingState;
            }
            else
            {
                _toolToState.Remove(interactableTool);
            }

            // if using far field tool, the upcoming state is based
            // on the far field tool that has the greatest max state so far
            // (since there can be multiple far field tools interacting
            // with button)
            if (isFarFieldTool)
            {
                foreach (var toolState in _toolToState.Values)
                {
                    if (upcomingState < toolState)
                    {
                        upcomingState = toolState;
                    }
                }
            }

            if (oldState != upcomingState)
            {
                _currentButtonState = upcomingState;

                var interactionType = !switchingStates ? InteractionType.Stay :
                                      newCollisionDepth == InteractableCollisionDepth.None ? InteractionType.Exit :
                                      InteractionType.Enter;
                var CurrentCollider =
                    _currentButtonState == InteractableState.ProximityState ? ProximityCollider :
                    _currentButtonState == InteractableState.ContactState ? ContactCollider :
                    _currentButtonState == InteractableState.ActionState ? ActionCollider : null;
                if (InteractableStateChanged != null)
                {
                    InteractableStateChanged.Invoke(new InteractableStateArgs(this, interactableTool,
                                                                              _currentButtonState, oldState, new ColliderZoneArgs(CurrentCollider, Time.frameCount,
                                                                                                                                  interactableTool, interactionType)));
                }
            }
        }
      public override void UpdateCollisionDepth(InteractableTool interactableTool,
                                                InteractableCollisionDepth oldCollisionDepth,
                                                InteractableCollisionDepth collisionDepth, InteractableTool collidingTool)
      {
          bool isFarFieldTool = interactableTool.IsFarFieldTool;

          // if this is a near field tool and another tool already controls it, bail.
          if (!isFarFieldTool && _toolToState.Keys.Count > 0 && !_toolToState.ContainsKey(interactableTool))
          {
              return;
          }

          var oldState = _currentButtonState;

          // ignore contact test if you are using the far field tool
          var  currButtonDirection = transform.TransformDirection(_localButtonDirection);
          bool validContact        = IsValidContact(collidingTool, currButtonDirection) || collidingTool.IsFarFieldTool;
          // in case finger enters contact zone first, we are in proximity as well
          bool toolInActionZone = collisionDepth == InteractableCollisionDepth.Action;

          // plane describing positive side of button
          var buttonZonePlane = new Plane(-currButtonDirection, _buttonPlaneCenter.position);
          // skip plane test if the boolean flag tells us not to test it
          bool onPositiveSideOfButton = !_makeSureToolIsOnPositiveSide ||
                                        buttonZonePlane.GetSide(collidingTool.InteractionPosition);

          bool switchingStates = oldCollisionDepth != collisionDepth;

          if (!switchingStates)
          {
              if (collisionDepth == InteractableCollisionDepth.Action)
              {
                  if (OnStayInActionZone != null)
                  {
                      OnStayInActionZone.Invoke();
                  }
              }
          }

          var newState = oldState;

          if (collidingTool.IsFarFieldTool)
          {
              newState = toolInActionZone ? InteractableState.ActionState : InteractableState.Default;
          }
          else
          {
              switch (oldState)
              {
              case InteractableState.ActionState:
                  if (!toolInActionZone)
                  {
                      newState = InteractableState.Default;
                      if (OnExitActionZone != null)
                      {
                          OnExitActionZone.Invoke();
                      }
                  }

                  break;

              case InteractableState.Default:
                  // test contact, action first then proximity (more important states
                  // take precedence)
                  if (validContact &&
                      collisionDepth == InteractableCollisionDepth.Action)
                  {
                      newState = InteractableState.ActionState;
                      if (OnEnterActionZone != null)
                      {
                          OnEnterActionZone.Invoke();
                      }
                  }

                  break;
              }
          }

          if (newState != InteractableState.Default)
          {
              _toolToState[interactableTool] = newState;
          }
          else
          {
              _toolToState.Remove(interactableTool);
          }

          // far field tools depend on max state set
          if (isFarFieldTool)
          {
              foreach (var toolState in _toolToState.Values)
              {
                  if (newState < toolState)
                  {
                      newState = toolState;
                  }
              }
          }

          if (oldState != newState)
          {
              _currentButtonState = newState;
              var interactionType = !switchingStates ? InteractionType.Stay :
                                    collisionDepth == InteractableCollisionDepth.None ? InteractionType.Exit :
                                    InteractionType.Enter;
              if (InteractableStateChanged != null)
              {
                  InteractableStateChanged.Invoke(new InteractableStateArgs(this, interactableTool,
                                                                            _currentButtonState, oldState, new ColliderZoneArgs(ContactCollider, Time.frameCount,
                                                                                                                                collidingTool, interactionType)));
              }
          }
      }
        public override void UpdateCollisionDepth(InteractableTool interactableTool,
                                                  InteractableCollisionDepth oldCollisionDepth,
                                                  InteractableCollisionDepth newCollisionDepth)
        {
            bool isFarFieldTool = interactableTool.IsFarFieldTool;

            // if this is a near field tool and another tool already controls it, bail.
            // (assuming we are not allowing multiple near field tools)
            bool testForSingleToolInteraction = !isFarFieldTool &&
                                                !_allowMultipleNearFieldInteraction;

            if (testForSingleToolInteraction && _toolToState.Keys.Count > 0 &&
                !_toolToState.ContainsKey(interactableTool))
            {
                return;
            }

            var oldState = CurrentButtonState;

            // ignore contact test if you are using the far field tool
            var  currButtonDirection = transform.TransformDirection(_localButtonDirection);
            bool validContact        = IsValidContact(interactableTool, currButtonDirection) ||
                                       interactableTool.IsFarFieldTool;
            // in case tool enters contact zone first, we are in proximity as well
            bool toolIsInProximity = newCollisionDepth >= InteractableCollisionDepth.Proximity;
            bool toolInContactZone = newCollisionDepth == InteractableCollisionDepth.Contact;
            bool toolInActionZone  = newCollisionDepth == InteractableCollisionDepth.Action;

            bool switchingStates = oldCollisionDepth != newCollisionDepth;

            if (switchingStates)
            {
                FireInteractionEventsOnDepth(oldCollisionDepth, interactableTool,
                                             InteractionType.Exit);
                FireInteractionEventsOnDepth(newCollisionDepth, interactableTool,
                                             InteractionType.Enter);
            }
            else
            {
                FireInteractionEventsOnDepth(newCollisionDepth, interactableTool,
                                             InteractionType.Stay);
            }

            var upcomingState = oldState;

            if (interactableTool.IsFarFieldTool)
            {
                upcomingState = toolInContactZone ? InteractableState.ContactState :
                                toolInActionZone ? InteractableState.ActionState : InteractableState.Default;
            }
            else
            {
                // plane describing positive side of button
                var buttonZonePlane = new Plane(-currButtonDirection, _buttonPlaneCenter.position);
                // skip plane test if the boolean flag tells us not to test it
                bool onPositiveSideOfButton = !_makeSureToolIsOnPositiveSide ||
                                              buttonZonePlane.GetSide(interactableTool.InteractionPosition);
                upcomingState = GetUpcomingStateNearField(oldState, newCollisionDepth,
                                                          toolInActionZone, toolInContactZone, toolIsInProximity,
                                                          validContact, onPositiveSideOfButton);
            }

            if (upcomingState != InteractableState.Default)
            {
                _toolToState[interactableTool] = upcomingState;
            }
            else
            {
                _toolToState.Remove(interactableTool);
            }

            // far field tools depend on max state set
            // (or if proper flag is set for near field tools)
            bool setMaxStateForAllTools = isFarFieldTool ||
                                          _allowMultipleNearFieldInteraction;

            if (setMaxStateForAllTools)
            {
                foreach (var toolState in _toolToState.Values)
                {
                    if (upcomingState < toolState)
                    {
                        upcomingState = toolState;
                    }
                }
            }

            if (oldState != upcomingState)
            {
                CurrentButtonState = upcomingState;

                var interactionType = !switchingStates ? InteractionType.Stay :
                                      newCollisionDepth == InteractableCollisionDepth.None ? InteractionType.Exit :
                                      InteractionType.Enter;
                ColliderZone currentCollider = null;
                switch (CurrentButtonState)
                {
                case InteractableState.ProximityState:
                    currentCollider = ProximityCollider;
                    break;

                case InteractableState.ContactState:
                    currentCollider = ContactCollider;
                    break;

                case InteractableState.ActionState:
                    currentCollider = ActionCollider;
                    break;

                default:
                    currentCollider = null;
                    break;
                }
                InteractableStateChanged?.Invoke(new InteractableStateArgs(this, interactableTool,
                                                                           CurrentButtonState, oldState, new ColliderZoneArgs(currentCollider, Time.frameCount,
                                                                                                                              interactableTool, interactionType)));
            }
        }
        public override void UpdateCollisionDepth(InteractableTool interactableTool,
                                                  InteractableCollisionDepth oldCollisionDepth,
                                                  InteractableCollisionDepth collisionDepth, InteractableTool collidingTool)
        {
            bool isFarFieldTool = interactableTool.IsFarFieldTool;

            // if this is a near field tool and another tool already controls it, bail.
            if (!isFarFieldTool && _toolToState.Keys.Count > 0 && !_toolToState.ContainsKey(interactableTool))
            {
                return;
            }

            var oldState = _currentButtonState;

            // ignore contact test if you are using the far field tool
            var  currButtonDirection = transform.TransformDirection(_localButtonDirection);
            bool validContact        = IsValidContact(collidingTool, currButtonDirection) || collidingTool.IsFarFieldTool;
            // in case finger enters contact zone first, we are in proximity as well
            bool toolIsInProximity = collisionDepth >= InteractableCollisionDepth.Proximity;
            bool toolInContactZone = collisionDepth == InteractableCollisionDepth.Contact;
            bool toolInActionZone  = collisionDepth == InteractableCollisionDepth.Action;

            // plane describing positive side of button
            var buttonZonePlane = new Plane(-currButtonDirection, _buttonPlaneCenter.position);
            // skip plane test if the boolean flag tells us not to test it
            bool onPositiveSideOfButton = !_makeSureToolIsOnPositiveSide ||
                                          buttonZonePlane.GetSide(collidingTool.InteractionPosition);

            bool switchingStates = oldCollisionDepth != collisionDepth;

            if (switchingStates)
            {
                CallEventsOnOldDepth(oldCollisionDepth, collidingTool);
                CallEventsOnNewDepth(collisionDepth, collidingTool);
            }
            else
            {
                SustainEventsOnDepth(collisionDepth, collidingTool);
            }

            var newState = oldState;

            if (collidingTool.IsFarFieldTool)
            {
                newState = toolInContactZone ? InteractableState.ContactState :
                           toolInActionZone ? InteractableState.ActionState : InteractableState.Default;
            }
            else
            {
                switch (oldState)
                {
                case InteractableState.ActionState:
                    if (!toolInActionZone)
                    {
                        // if retreating from action, can go back into action state even if contact
                        // is not legal (i.e. tool/finger retracts)
                        if (toolInContactZone)
                        {
                            newState = InteractableState.ContactState;
                        }
                        else if (toolIsInProximity)
                        {
                            newState = InteractableState.ProximityState;
                        }
                        else
                        {
                            newState = InteractableState.Default;
                        }
                    }

                    break;

                case InteractableState.ContactState:
                    if (collisionDepth < InteractableCollisionDepth.Contact)
                    {
                        newState = toolIsInProximity ? InteractableState.ProximityState : InteractableState.Default;
                    }
                    // can only go to action state if contact is legal
                    // if tool goes into contact state due to proper movement, but does not maintain
                    // that movement throughout (i.e. a tool/finger presses downwards initially but
                    // moves in random directions afterwards), then don't go into action
                    else if (toolInActionZone)
                    {
                        newState = InteractableState.ActionState;
                    }

                    break;

                case InteractableState.ProximityState:
                    if (collisionDepth < InteractableCollisionDepth.Proximity)
                    {
                        newState = InteractableState.Default;
                    }
                    else if (collisionDepth > InteractableCollisionDepth.Proximity)
                    {
                        newState = collisionDepth == InteractableCollisionDepth.Action
                                                          ? InteractableState.ActionState
                                                          : InteractableState.ContactState;
                    }

                    break;

                case InteractableState.Default:
                    // test contact, action first then proximity (more important states
                    // take precedence)
                    if (validContact && onPositiveSideOfButton &&
                        collisionDepth > InteractableCollisionDepth.Proximity)
                    {
                        newState = collisionDepth == InteractableCollisionDepth.Action
                                                          ? InteractableState.ActionState
                                                          : InteractableState.ContactState;
                    }
                    else if (toolIsInProximity)
                    {
                        newState = InteractableState.ProximityState;
                    }

                    break;
                }
            }

            if (newState != InteractableState.Default)
            {
                _toolToState[interactableTool] = newState;
            }
            else
            {
                _toolToState.Remove(interactableTool);
            }

            // far field tools depend on max state set
            if (isFarFieldTool)
            {
                foreach (var toolState in _toolToState.Values)
                {
                    if (newState < toolState)
                    {
                        newState = toolState;
                    }
                }
            }

            if (oldState != newState)
            {
                _currentButtonState = newState;
                var interactionType = !switchingStates ? InteractionType.Stay :
                                      collisionDepth == InteractableCollisionDepth.None ? InteractionType.Exit :
                                      InteractionType.Enter;
                if (InteractableStateChanged != null)
                {
                    InteractableStateChanged.Invoke(new InteractableStateArgs(this, interactableTool,
                                                                              _currentButtonState, oldState, new ColliderZoneArgs(ContactCollider, Time.frameCount,
                                                                                                                                  collidingTool, interactionType)));
                }
            }
        }