I am trying to achieve an helical movement with min/max limiation :
Both positive & negative rotation would be done with the MRTK hands interactions provided script, so this is not my problem. I (think) that I am struggling with the logic.
tl;dr : I want to screw something using Unity, MRTK and virtual hands.
I ended up solving my problem, after days of scratching my head really, really hard. To be honest, I probably wouldn't have succeeded on my own, because of a logic problem (this is very often the case, isn't it?).
In my case, the gameObject to interact with, is a screw. I wanted it to perform a positive translation when a positive rotation occurs, vice-versa. On this gameObject are attached some components :
The rigidbody, PointerHandler.cs, ObjectManipulator.cs and the TwistingRotation.cs configurations can be found here :
The magic appear with the PointerHandler.cs that allow us to detect when the near interaction happen with the screw, thx to the OnPointerDragged event.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// Translation of the object while rotating it when grabbed using the MRTK.ObjectManipulator
/// Boundaries and axis restrictions ongoing
/// </summary>
public class TwistingRotation : MonoBehaviour
{
/*******CACHE REFERENCE*******/
private Transform _myTransform;
[SerializeField] private float translationFactor = 90f;
private Vector3 _minPosition;
private Vector3 _maxPosition;
private Vector3 _previousVector;
private Rigidbody _rb;
private void Start()
{
// Cache reference
_myTransform = gameObject.transform;
_rb = gameObject.GetComponent<Rigidbody>();
// Reference for the previous rotation vector
_previousVector = _myTransform.up;
// Default position is the maximum transform.position (unscrewed)
_maxPosition = _myTransform.position;
// Minimum position is default transform.position + 1unit in local space direction
_minPosition = _maxPosition + Vector3.forward;
}
/// <summary>
/// Move the object according to the rotation angle value
/// A positive rotation leads to a positive translation, and vice-versa
/// </summary>
public void TranslateRotation()
{
// Retrieve the angle on a defined local axis when the rotation occur
var currentVector = _myTransform.up;
// Compute the angle between the previous and the current vector on a defined local axis
// Difference between the previous rotation vector, and the actual, on a global axis
var angle = Vector3.SignedAngle(_previousVector, currentVector, Vector3.forward);
// Move object proportional to its rotation
var translation = Vector3.forward * (angle / translationFactor);
_myTransform.Translate(translation, Space.Self);
// Get the GO current position
var currentPosition = _myTransform.position;
// Clamp for each axis between _minPosition and _maxPosition (the default spawn position)
// Doing a Mathf.Min/Max inside the Mathf.Clamp to insure that the min and max values are correct
var x = Mathf.Clamp(currentPosition.x, Mathf.Min(_minPosition.x, _maxPosition.x), Mathf.Max(_minPosition.x, _maxPosition.x));
var y = Mathf.Clamp(currentPosition.y, Mathf.Min(_minPosition.y, _maxPosition.y), Mathf.Max(_minPosition.y, _maxPosition.y));
var z = Mathf.Clamp(currentPosition.z, Mathf.Min(_minPosition.z, _maxPosition.z), Mathf.Max(_minPosition.z, _maxPosition.z));
// Compute the new position while taking the boundaries into consideration
var newPosition = new Vector3(x, y, z);
_myTransform.position = newPosition;
// Save position for the next frame
_previousVector = currentVector;
}
}
Quite simple : the screw is translating over 1 (unity) unit while rotating. The value of the rotation depend on the value of the translationFactor variable. In my case, the value is 360 so a complete rotation over a 1 (unity) unit translation.
It is far from being perfect, probably very much "meh" but hey, it is working (not as intended tho, but still) and it allowed me to move forward and I made my presentation.