Example #1
0
        private bool IsValidContact(InteractableTool collidingTool, Vector3 buttonDirection)
        {
            if (_contactTests == null || collidingTool.IsFarFieldTool)
            {
                return(true);
            }

            foreach (var contactTest in _contactTests)
            {
                switch (contactTest)
                {
                case ContactTest.BackwardsPress:
                    if (!PassEntryTest(collidingTool, buttonDirection))
                    {
                        return(false);
                    }

                    break;

                default:
                    if (!PassPerpTest(collidingTool, buttonDirection))
                    {
                        return(false);
                    }

                    break;
                }
            }

            return(true);
        }
 public InteractableCollisionInfo(ColliderZone collider, InteractableCollisionDepth collisionDepth,
                                  InteractableTool collidingTool)
 {
     InteractableCollider = collider;
     CollisionDepth       = collisionDepth;
     CollidingTool        = collidingTool;
 }
Example #3
0
        private bool IsValidContact(InteractableTool collidingTool, Vector3 buttonDirection)
        {
            if (_contactTests == null || collidingTool.IsFarFieldTool)
            {
                return(true);
            }

            //foreach (var contactTest in _contactTests)
            //{
            //	switch (contactTest)
            //	{
            //		case ContactTest.BackwardsPress:
            //			if (!PassEntryTest(collidingTool, buttonDirection))
            //			{
            //				return false;
            //			}

            //			break;
            //		default:
            //			if (!PassPerpTest(collidingTool, buttonDirection))
            //			{
            //				return false;
            //			}

            //			break;
            //	}
            //}

            return(true);
        }
		public void UnregisterInteractableTool(InteractableTool interactableTool)
		{
			if (interactableTool.IsRightHandedTool)
			{
				if (interactableTool.IsFarFieldTool)
				{
					_rightHandFarTools.Remove(interactableTool);
				}
				else
				{
					_rightHandNearTools.Remove(interactableTool);
				}
			}
			else
			{
				if (interactableTool.IsFarFieldTool)
				{
					_leftHandFarTools.Remove(interactableTool);
				}
				else
				{
					_leftHandNearTools.Remove(interactableTool);
				}
			}
		}
 public ColliderZoneArgs(ColliderZone collider, float frameTime,
                         InteractableTool collidingTool, InteractionType interactionType)
 {
     Collider      = collider;
     FrameTime     = frameTime;
     CollidingTool = collidingTool;
     InteractionT  = interactionType;
 }
Example #6
0
 public InteractableStateArgs(Interactable interactable, InteractableTool tool,
                              InteractableState newInteractableState, InteractableState oldState,
                              ColliderZoneArgs colliderArgs)
 {
     Interactable         = interactable;
     Tool                 = tool;
     NewInteractableState = newInteractableState;
     OldInteractableState = oldState;
     ColliderArgs         = colliderArgs;
 }
		/// <summary>
		/// If our collision information changed per frame, make note of it. Removed, added and remaining
		/// objects must get their proper events.
		/// </summary>
		/// <param name="oldCollisionMap">Previous collision information.</param>
		/// <param name="newCollisionMap">Current collision information.</param>
		private void UpdateUsingOldNewCollisionData(InteractableTool interactableTool,
		  Dictionary<Interactable, InteractableCollisionInfo> oldCollisionMap,
		  Dictionary<Interactable, InteractableCollisionInfo> newCollisionMap)
		{
			_addedInteractables.Clear();
			_removedInteractables.Clear();
			_remainingInteractables.Clear();

			foreach (Interactable key in newCollisionMap.Keys)
			{
				if (!oldCollisionMap.ContainsKey(key))
				{
					_addedInteractables.Add(key);
				}
				else
				{
					_remainingInteractables.Add(key);
				}
			}

			foreach (Interactable key in oldCollisionMap.Keys)
			{
				if (!newCollisionMap.ContainsKey(key))
				{
					_removedInteractables.Add(key);
				}
			}

			// tell removed interactables that we are gone
			foreach (Interactable removedInteractable in _removedInteractables)
			{
				removedInteractable.UpdateCollisionDepth(interactableTool, oldCollisionMap[removedInteractable].CollisionDepth,
				  InteractableCollisionDepth.None, oldCollisionMap[removedInteractable].CollidingTool);
			}

			// tell added interactable what state we are now in
			foreach (Interactable addedInteractableKey in _addedInteractables)
			{
				var addedInteractable = newCollisionMap[addedInteractableKey];
				var collisionDepth = addedInteractable.CollisionDepth;
				addedInteractableKey.UpdateCollisionDepth(interactableTool, InteractableCollisionDepth.None,
				  collisionDepth, newCollisionMap[addedInteractableKey].CollidingTool);
			}

			// remaining interactables must be updated
			foreach (Interactable remainingInteractableKey in _remainingInteractables)
			{
				var newDepth = newCollisionMap[remainingInteractableKey].CollisionDepth;
				var oldDepth = oldCollisionMap[remainingInteractableKey].CollisionDepth;
				remainingInteractableKey.UpdateCollisionDepth(interactableTool, oldDepth, newDepth,
				  newCollisionMap[remainingInteractableKey].CollidingTool);
			}
		}
Example #8
0
        public void CrossingButtonStateChanged(InteractableStateArgs obj)
        {
            bool inActionState = obj.NewInteractableState == InteractableState.ActionState;

            if (inActionState)
            {
                ActivateTrainCrossing();
            }

            _toolInteractingWithMe = obj.NewInteractableState > InteractableState.Default ?
                                     obj.Tool : null;
        }
Example #9
0
        /// <summary>
        /// Is tool entering button correctly? Check velocity and make sure that
        /// tool is not below action zone.
        /// </summary>
        private bool PassEntryTest(InteractableTool collidingTool, Vector3 buttonDirection)
        {
            var jointVelocityVector = collidingTool.Velocity.normalized;
            var dotProduct          = Vector3.Dot(jointVelocityVector, buttonDirection);

            if (dotProduct < ENTRY_DOT_THRESHOLD)
            {
                return(false);
            }

            return(true);
        }
Example #10
0
        private void StartStopStateChanged(InteractableStateArgs obj)
        {
            bool inActionState = obj.NewInteractableState == InteractableState.ActionState;

            if (inActionState)
            {
                if (_bladesRotation.IsMoving)
                {
                    _bladesRotation.SetMoveState(false, 0.0f);
                }
                else
                {
                    _bladesRotation.SetMoveState(true, _maxSpeed);
                }
            }

            _toolInteractingWithMe = obj.NewInteractableState > InteractableState.Default ?
                                     obj.Tool : null;
        }
Example #11
0
        /// <summary>
        /// Is our tool pointing in opposite direction compared to button?
        /// </summary>
        private bool PassPerpTest(InteractableTool collidingTool, Vector3 buttonDirection)
        {
            // the "right" vector points along tool by default
            // if it's right hand, then flip that direction
            var toolDirection = collidingTool.ToolTransform.right;

            if (collidingTool.IsRightHandedTool)
            {
                toolDirection = -toolDirection;
            }

            var dotProduct = Vector3.Dot(toolDirection, buttonDirection);

            if (dotProduct < PERP_DOT_THRESHOLD)
            {
                return(false);
            }

            return(true);
        }
        private void CallEventsOnOldDepth(InteractableCollisionDepth oldDepth, InteractableTool collidingTool)
        {
            switch (oldDepth)
            {
            case InteractableCollisionDepth.Action:
                OnActionZoneEvent(new ColliderZoneArgs(ActionCollider, Time.frameCount,
                                                       collidingTool, InteractionType.Exit));
                break;

            case InteractableCollisionDepth.Contact:
                OnContactZoneEvent(new ColliderZoneArgs(ContactCollider, Time.frameCount,
                                                        collidingTool, InteractionType.Exit));
                break;

            case InteractableCollisionDepth.Proximity:
                OnProximityZoneEvent(new ColliderZoneArgs(ProximityCollider, Time.frameCount,
                                                          collidingTool, InteractionType.Exit));
                break;
            }
        }
 private void OnButtonStateChanged(InteractableStateArgs obj)
 {
     toolInteractingWithMe = obj.NewInteractableState > InteractableState.Default ?
                             obj.Tool : null;
 }
Example #14
0
 public abstract void UpdateCollisionDepth(InteractableTool interactableTool,
                                           InteractableCollisionDepth oldCollisionDepth, InteractableCollisionDepth newCollisionDepth);
Example #15
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 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)));
            }
        }
Example #17
0
 public abstract void UpdateCollisionDepth(InteractableTool interactableTool,
                                           InteractableCollisionDepth oldCollisionDepth, InteractableCollisionDepth collisionDepth,
                                           InteractableTool collidingTool);
        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)));
                }
            }
        }