Skip to content

AngularTransformDrive gets stuck when its current rotation is outside DriveLimit range #267

@Scraphead

Description

@Scraphead

Environment

Unity 2021.3
"io.extendreality.tilia.interactions.controllables.unity": "2.10.21",
"io.extendreality.tilia.interactions.interactables.unity": "2.16.6",

Steps to reproduce

1: Create standard VRTK environment with interactor
2: Create an AngularTransformDrive and set its DriveLimit max to 800 (Above 720)
3: Create script that will set AngularDriveFacade SetDriveLimitMaximum to 300 (Below 360)

4: Play Game
5: Grab and rotate cube so it reaches maximum 800.
6: Invoke script so DriveLimit max is set to 300.
7: Try to grab and rotate cube again.

Expected behavior

Cube should still be able to be rotated within min/max DriveLimit range.

Current behavior

Cube is stuck, unable to be rotated,

Other:

My crude workaround to set DriveLimit without it getting stuck.
  // Workaround for Controllables that can be stuck when rotationMultiplier is not within current DriveLimit restrictions
  public void SetMinMaxLimitWithCrudeFix(Vector2 minMax)
  {
      var angularFacade = GetComponent<AngularDriveFacade>();
      angularFacade.DriveLimit = new FloatRange(minMax);
      
      MethodInfo _mGetSimpleEulerAngels = typeof(AngularDrive).GetMethod("GetSimpleEulerAngles",
      BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

      FieldInfo _fRotationMultiplier = typeof(AngularDrive).GetField("rotationMultiplier",
      BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.FlattenHierarchy);

      var simpleEulerAngels = (Vector3) _mGetSimpleEulerAngels.Invoke(angularFacade.Drive, null);
      var rotationMultiplier = (float) _fRotationMultiplier.GetValue(angularFacade.Drive);
      var currentPseudoRotation = simpleEulerAngels[(int) angularFacade.DriveAxis] + (rotationMultiplier * 360f);
      var currentLimit = angularFacade.DriveLimit;

      if (currentLimit.Contains(currentPseudoRotation))
          return; // All good, within limits.

      var limitExceeded = currentLimit.maximum;
      if (currentPseudoRotation < currentLimit.minimum)
          limitExceeded = currentLimit.minimum;

      // Set rotationMultiplier to be closest step within range of DriveLimit
      var diff = currentPseudoRotation - limitExceeded;
      var subtractMultiplier = (int) (diff / 360f);
      rotationMultiplier = rotationMultiplier - subtractMultiplier;

      // Very bad additional workaround:
      // Need to overshoot RotationMultiplier by one since I have to fight 
      // AngularDrive.CalculateRotationMultiplier() that re-applies a rotation step next Process()
      rotationMultiplier += subtractMultiplier < 0 ? 1 : -1;
      
      // This workaround does not update current angle to be at the new limit, only that the rotationMultipiler is in valid range.
      _fRotationMultiplier.SetValue(angularFacade.Drive, rotationMultiplier);
  }

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions