Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Bug Locomotion Provider events not firing when expected.

Discussion in 'XR Interaction Toolkit and Input' started by Bwavo, Jun 22, 2021.

  1. Bwavo

    Bwavo

    Joined:
    Feb 22, 2017
    Posts:
    7
    The use case for the locomotion provider's beginLocomotion and endLocomotion actions as detailed in this video no longer work as expected. For some reason, when using the continuous turn provider and continuous move providers, the end locomotion event is invoked seemingly every frame rather than when the locomotion is actually finished. According to the documentation, "The endLocomotion action will be called when a LocomotionProvider successfully ends a locomotion event." According to this, then, wouldn't it make the most sense for endLocomotion to fire once I'm done turning or moving? Just wondering if this is an unintended bug or if I'm misunderstanding how to utilize these events.
    Thanks,
    Bwavo.
     
  2. TreyK-47

    TreyK-47

    Unity Technologies

    Joined:
    Oct 22, 2019
    Posts:
    1,795
  3. War_Tourist

    War_Tourist

    Joined:
    Dec 3, 2014
    Posts:
    8
    Getting the same issue.
     
  4. sebesdm

    sebesdm

    Joined:
    Jun 29, 2019
    Posts:
    2
    Seeing this here as well
     
  5. sebesdm

    sebesdm

    Joined:
    Jun 29, 2019
    Posts:
    2
    Ok, there are two things to note that are happening here. When your ContinuousMoveProvider has GravityApplicationMode set to "Immediate", beginLocomotion will fire on every frame it is active in the scene. If GravityApplicationMode is set to "Attempting Move", beginLocomotion will fire on every frame that input is active. Additionally, endLocomotion seems to be called on the same frame as beginLocomotion for any configuration.

    I am probably misunderstanding how to properly use these events. However, I created a simple component that gets me the correct behavior for what I need. Add the following component to a game object that has the ContinuousMoveProvider and hook up to the events on this one instead. This should get it at least within one frame of starting and stopping (I think). I just needed it for a vignette, so it is good enough.

    Code (CSharp):
    1. using System;
    2. using UnityEngine;
    3. using UnityEngine.XR.Interaction.Toolkit;
    4.  
    5. [RequireComponent(typeof(ActionBasedContinuousMoveProvider))]
    6. [AddComponentMenu("XR/Locomotion/Continuous Move Provider Event Fixer (Action-based)", 11)]
    7. public class ActionBasedContinuousMoveProviderLocomotionEventFixer : MonoBehaviour
    8. {
    9.     public ActionBasedContinuousMoveProvider continuousMoveProvider;
    10.     public Action OnBeginLocomotion;
    11.     public Action OnEndLocomotionLikeSuperSeriousThisTime;
    12.  
    13.     private void Awake()
    14.     {
    15.         continuousMoveProvider.beginLocomotion += _ =>
    16.         {
    17.             beginLocomotionThisFrame = true;
    18.             if (!locomotionStarted)
    19.             {
    20.                 locomotionStarted = true;
    21.                 OnBeginLocomotion?.Invoke();
    22.             }
    23.         };
    24.     }
    25.  
    26.     private void Update()
    27.     {
    28.         if (locomotionStarted && !beginLocomotionThisFrame)
    29.         {
    30.             locomotionStarted = false;
    31.             OnEndLocomotionLikeSuperSeriousThisTime?.Invoke();
    32.         }
    33.  
    34.         beginLocomotionThisFrame = false;
    35.     }
    36.  
    37.     private bool locomotionStarted = false;
    38.     private bool beginLocomotionThisFrame = false;
    39. }
    40.  
     
  6. VRDave_Unity

    VRDave_Unity

    Unity Technologies

    Joined:
    Nov 19, 2021
    Posts:
    254
    Hey all,
    I would like to also point you at the Tunneling Vignette Controller, which we have a sample for in XRI. This is designed to work with a set of Locomotion providers to hook into the correct spots when locomotion is occurring. It also allows for multiple providers so that you can change the size/color/etc of the effect depending on the type of locomotion. For example, you may want to use a full fade-out for teleport vs a narrowing of vision for continuous movement.

    If the Vignette Controller and sample does not work for your project, please let us know. We would love to improve the implementation to meet more of everyone's needs if there is an opportunity to do so.
     
  7. nalex66

    nalex66

    Joined:
    Aug 26, 2022
    Posts:
    41
    I'm using the Vignette Controller in my project, and I've found that it doesn't work with Immediate Gravity; due to the problem described in this thread of Continuous Locomotion begin/end events firing every frame, the vignette was always showing. My solution was to not use Immediate Gravity, but instead I wrote a custom extension to the Continuous Move Provider that pulls the XR Rig along if the head moves too far (I use the custom version in addition to a Continuous Move Provider). This allows me to support room-scale play in the way that Immediate Gravity does, while still being able to rely on Begin/End Locomotion to trigger stuff like footstep sounds.

    Here's my code for this:

    Code (CSharp):
    1. namespace UnityEngine.XR.Interaction.Toolkit
    2. {
    3.     public class PlayerPullRig : ContinuousMoveProvider
    4.     {
    5.         CharacterController charController;
    6.         Transform head;
    7.         Vector3 charPos;
    8.      
    9.         void Start()
    10.         {
    11.             charController = GetComponent<CharacterController>();
    12.             head = Camera.main.transform;        
    13.         }
    14.  
    15.  
    16.         public void PullPlayerRig(float maxOffset)
    17.         {
    18.             // If head distance from charController > maxOffset, pull the charController position
    19.             // relative to the head, and apply collisions and gravity.
    20.             // This keeps position updated for roomscale movement and prevents physically
    21.             // walking through walls or floating over open space.
    22.  
    23.             // The advantage of this over using Immediate Gravity in the Continuous Move Provider
    24.             // is that this works even in Teleport-Only mode (when the Continuous Move Provider is disabled),
    25.             // and this works with the tunnelling vignette (Immediate Gravity is incompatible, makes the vignette always on).
    26.  
    27.             charPos = transform.TransformPoint(charController.center);      // charController position (converted to worldspace)
    28.             Vector3 horOffset = Vector3.Scale((head.position - charPos), new Vector3(1, 0, 1));   // horizontal offset between head and charController
    29.  
    30.             if (horOffset.magnitude <= maxOffset) return;
    31.  
    32.             // move charController towards headPos, by amount over maxOffset (no physics)
    33.             charController.center += transform.InverseTransformDirection((horOffset.magnitude - maxOffset) * horOffset.normalized);
    34.              
    35.             // invoke MoveRig to update locomotion system, collision, and gravity
    36.             //MoveRig(Vector3.zero);
    37.             MoveRig(horOffset*0.0001f); // try a tiny move instead of zero?
    38.             // Triggering a zero move updates position based on camera(headset) and invokes physics.
    39.             // For some reason, collision does not update with a zero move if ground is clear but top of capsule collides with wall
    40.             // (overhang obstacle). !? Using a tiny movement amount solved collision with upper part of capsule.        
    41.         }
    42. }