From 157bfcfe246244576dee803327baf1dc3af87985 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dino=20Fejzagi=C4=87?= Date: Wed, 17 Jul 2024 20:15:45 +0200 Subject: [PATCH] Add support for operating steering wheel behaviour with more than one hand (#142) --- .../SteeringWheelBehaviour.cs | 65 ++++++++++--------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/Runtime/Input/InteractionBehaviours/SteeringWheelBehaviour.cs b/Runtime/Input/InteractionBehaviours/SteeringWheelBehaviour.cs index f13f0461..494c2ffb 100644 --- a/Runtime/Input/InteractionBehaviours/SteeringWheelBehaviour.cs +++ b/Runtime/Input/InteractionBehaviours/SteeringWheelBehaviour.cs @@ -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; @@ -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.")] @@ -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 interactors = new(); private float currentAngle; /// @@ -103,7 +105,7 @@ protected override void Awake() /// protected override void Update() { - if (currentInteractor == null && !resetting) + if (interactors.Count == 0 && !resetting) { return; } @@ -123,29 +125,34 @@ protected override void Update() return; } - var angle = FindSteeringWheelAngle(); + var angle = FindWheelAngle(); var angleDifference = currentAngle - angle; Rotate(-angleDifference); currentAngle = angle; } /// - 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(); } /// - 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) { @@ -153,34 +160,34 @@ protected override void OnLastGrabExited(InteractionExitEventArgs eventArgs) } } - /// - /// Rotates the steering wheel by . - /// - /// The euler angle to rotate by. - 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; + } - /// - /// Returns the steering wheel to neutral position. - /// private void ReturnToNeutral() { if (resetting)