Using Touch to Manipulate the Object | AR Unity Developer

Derek Anderson
4 min readMay 8, 2024

--

The AR app now has an examine and an unexamine feature when it comes to selecting and looking at the placement prefabs. The next step is to work with touch input with the examinable objects, such as rotating the object up close.

There are a number of different options for detecting touch under the Input class. To detect taps on the screen, Input.touchCount will count the number of touches occurring throughout the frame. If one finger is touching the screen, then the touch count would be one.

void Update()
{
if (Input.touchCount > 0)
{
print("Touch");
}
}

Next is GetTouch, which determines which finger is touching the screen. For example, the first touch would be an index of 0, while the second touch would be an index of 1. This returns a data type Touch, which contains information about a particular touch such as position, rotation, phase, and more.

void Update()
{
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
print(touch.position);
}
}

Right now, this is occurring on every frame on the ExaminableManager script, even if an object isn’t being examined. This should be limited to only detecting or printing out the touch information if an object is being examined. A Boolean will solve this issue, and it will be placed in the perform methods of ExaminableManager.

    public void PerformExamine(Examinable examinable)
{
_currentExaminedObject = examinable;

_cachedPosition = examinable.transform.position;
_cachedRotation = examinable.transform.rotation;

_currentExaminedObject.transform.position = _examineTarget.position;
_currentExaminedObject.transform.parent = _examineTarget;

_isExamining = true;
}

public void PerformUnexamine()
{
_currentExaminedObject.transform.position = _cachedPosition;
_currentExaminedObject.transform.rotation= _cachedRotation;
_currentExaminedObject.transform.parent = null;
_currentExaminedObject = null;

_isExamining = false;
}

The touch information will now print out so long as an object is being examined.

    void Update()
{
if (_isExamining == true)
{
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
print(touch.position);
}
}
}

In order to rotate the examined object, the movement of the finger needs to be detected. Digging into the documentation of touch, we can read the phase, or the part of the lifecycle, that the touch is on.

With this in mind, we can use Touch.phase to detect the phase of the touch movement. For rotating or moving an object, the finger won’t be stationary in the frame, so TouchPhase.Moved will be used.

    void Update()
{
if (_isExamining == true)
{
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Moved)
{
print(touch.position);
}
}
}
}

While this is useful for printing the actual position of the object, it doesn’t tell the change in position of the object. deltaPosition can be used to print the difference between the new position and the old position from the previous frame.

void Update()
{
if (_isExamining == true)
{
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Moved)
{
print(touch.deltaPosition);
_currentExaminedObject.transform.Rotate(touch.deltaPosition.x, touch.deltaPosition.y, 0);
}
}
}
}

This can be taken a step further in rotating the object being examined by accessing the transform of the object. As the app is working on a phone screen, there isn’t any depth to the Z-axis, so there isn’t any Z-axis information that’s needed.

The object can now be rotated while it is being examined, but it moves a bit too fast. The rotation speed can be reduced using a speed variable. SerializeField will allow any speed changes needed within the Unity editor.

[SerializeField] private float _rotationSpeed = 1.0;
.
.
.
void Update()
{
if (_isExamining == true)
{
if (Input.touchCount > 0)
{
Touch touch = Input.GetTouch(0);
if (touch.phase == TouchPhase.Moved)
{
_currentExaminedObject.transform.Rotate(touch.deltaPosition.x * _rotateSpeed, touch.deltaPosition.y * _rotateSpeed, 0);
}
}
}
}

Another thing that can be cached with our examinable objects is the scale. Some objects, like a cube, are just the right size when being examined, but this won’t always be the case with different objects. Caching the scale is similar to caching the position and rotation of the examinable objects in the ExaminableManager script. However, modifying the scale should be set in the Examinable script to account for the different objects.

    public void PerformExamine(Examinable examinable)
{
_currentExaminedObject = examinable;

_cachedPosition = _currentExaminedObject.transform.position;
_cachedRotation = _currentExaminedObject.transform.rotation;
_cachedScale = _currentExaminedObject.transform.localScale;

_currentExaminedObject.transform.position = _examineTarget.position;
_currentExaminedObject.transform.parent = _examineTarget;

_isExamining = true;
}

public void PerformUnexamine()
{
_currentExaminedObject.transform.position = _cachedPosition;
_currentExaminedObject.transform.rotation= _cachedRotation;
_currentExaminedObject.transform.localScale = _cachedScale;

_currentExaminedObject.transform.parent = null;
_currentExaminedObject = null;

_isExamining = false;
}

Create a public float variable in the Examinable script for the scale modifier. However, we can’t use this in the ExaminableManager script because it’s a float. A new local Vector3 variable is needed for this scale modifier.

    public void PerformExamine(Examinable examinable)
{
_currentExaminedObject = examinable;

//Cached examinable transform data so it can be reset
_cachedPosition = _currentExaminedObject.transform.position;
_cachedRotation = _currentExaminedObject.transform.rotation;
_cachedScale = _currentExaminedObject.transform.localScale;

//Move examinable to target position
_currentExaminedObject.transform.position = _examineTarget.position;
_currentExaminedObject.transform.parent = _examineTarget;

//Offset scale to fit examinable in view
Vector3 offsetScale = _cachedScale * examinable._examineScaleOffset;
_currentExaminedObject.transform.localScale = offsetScale;

_isExamining = true;
}

With that set, we can now examine an object up close with a modified scale and rotate it.

This not only showcases scale, it’s also an excuse to have a better featured image

--

--