Skip to content

Commit

Permalink
Add support for operating steering wheel behaviour with more than one…
Browse files Browse the repository at this point in the history
… hand (#142)
  • Loading branch information
FejZa committed Jul 17, 2024
1 parent cee98a5 commit 157bfcf
Showing 1 changed file with 36 additions and 29 deletions.
65 changes: 36 additions & 29 deletions Runtime/Input/InteractionBehaviours/SteeringWheelBehaviour.cs
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
// Copyright (c) Reality Collective. All rights reserved.
// Licensed under the MIT License. See LICENSE in the project root for license information.

using RealityCollective.Utilities.Extensions;
using RealityToolkit.Input.Events;
using RealityToolkit.Input.Interactors;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;

Expand All @@ -18,7 +20,7 @@ public class SteeringWheelBehaviour : BaseInteractionBehaviour
{
[SerializeField]
[Tooltip("Controls the threshold angle for steering when at maximum steering in either direction.")]
[Range(1f, 179f)]
[Range(1f, 45)]
private float steeringAngleLimit = 45f;

[SerializeField, Tooltip("If set, the steering resets to neutral on release.")]
Expand All @@ -39,7 +41,7 @@ public class SteeringWheelBehaviour : BaseInteractionBehaviour
private float elapsedResetTime;
private Quaternion resetStartRotation;
private Quaternion neutralSteeringRotation = Quaternion.Euler(0f, 0f, 0f);
private IControllerInteractor currentInteractor;
private readonly List<IControllerInteractor> interactors = new();
private float currentAngle;

/// <summary>
Expand Down Expand Up @@ -103,7 +105,7 @@ protected override void Awake()
/// <inheritdoc/>
protected override void Update()
{
if (currentInteractor == null && !resetting)
if (interactors.Count == 0 && !resetting)
{
return;
}
Expand All @@ -123,64 +125,69 @@ protected override void Update()
return;
}

var angle = FindSteeringWheelAngle();
var angle = FindWheelAngle();
var angleDifference = currentAngle - angle;
Rotate(-angleDifference);
currentAngle = angle;
}

/// <inheritdoc/>
protected override void OnFirstGrabEntered(InteractionEventArgs eventArgs)
protected override void OnGrabEntered(InteractionEventArgs eventArgs)
{
if (eventArgs.Interactor is not IControllerInteractor controllerInteractor)
{
return;
}

currentInteractor = controllerInteractor;
currentAngle = FindSteeringWheelAngle();
interactors.EnsureListItem(controllerInteractor);
currentAngle = FindWheelAngle();
}

/// <inheritdoc/>
protected override void OnLastGrabExited(InteractionExitEventArgs eventArgs)
protected override void OnGrabExited(InteractionExitEventArgs eventArgs)
{
currentAngle = FindSteeringWheelAngle();
currentInteractor = null;
if (eventArgs.Interactor is not IControllerInteractor controllerInteractor)
{
return;
}

interactors.SafeRemoveListItem(controllerInteractor);
currentAngle = FindWheelAngle();

if (resetsToNeutral)
{
ReturnToNeutral();
}
}

/// <summary>
/// Rotates the steering wheel by <paramref name="angle"/>.
/// </summary>
/// <param name="angle">The euler angle to rotate by.</param>
private void Rotate(float angle)
private float FindWheelAngle()
{
resetting = false;
var totalAngle = 0f;

var rotation = transform.localEulerAngles;
var updated = rotation.z + angle;
CurrentSteeringAngle = updated;
}
foreach (var interactor in interactors)
{
var direction = FindLocalPoint(interactor.GameObject.transform.position);
totalAngle += FindRotationSensitivity() * ConvertToAngle(direction);
}

private float FindSteeringWheelAngle()
{
var direction = FindLocalPoint(currentInteractor.GameObject.transform.position);
return ConvertToAngle(direction) * FindRotationSensitivity();
return totalAngle;
}

private Vector2 FindLocalPoint(Vector3 position) => upTransform.InverseTransformPoint(position);
private Vector2 FindLocalPoint(Vector3 position) => upTransform.InverseTransformPoint(position).normalized;

private float ConvertToAngle(Vector2 direction) => Vector2.SignedAngle(upTransform.up, direction);

private float FindRotationSensitivity() => 1f;
private float FindRotationSensitivity() => 1f / interactors.Count;

private void Rotate(float angle)
{
resetting = false;

var rotation = transform.localEulerAngles;
var updated = rotation.z + angle;
CurrentSteeringAngle = updated;
}

/// <summary>
/// Returns the steering wheel to neutral position.
/// </summary>
private void ReturnToNeutral()
{
if (resetting)
Expand Down

0 comments on commit 157bfcf

Please sign in to comment.