using ProceduralEditor; using Rive; using Rive.Components; using System.Reflection.Metadata; using UnityEngine; using UnityEngine.InputSystem; /// Sends keyboard and gamepad navigation commands to the Rive menu and /// activates the Play option when Enter/gamepad confirm is pressed public class RiveNavigationController : MonoBehaviour { [Header("Rive")] [Tooltip("RiveWidget that hosts the menu artboard.")] [SerializeField] private RiveWidget riveWidget; [Header("Scene Transition")] [Tooltip("Object containing the SceneTransitionController component.")] [SerializeField] private SceneTransitionController sceneTransitionController; [Header("Menu Selection")] [Tooltip("Total number of selectable Rive menu buttons.")] [Min(1)] [SerializeField] private int menuItemCount = 1; private const string NextTriggerName = "nextButtonClicked"; private const string PreviousTriggerName = "previousButtonClicked"; private const int PlayIndex = 0; private ViewModelInstanceTriggerProperty nextTrigger; private ViewModelInstanceTriggerProperty previousTrigger; private int selectedIndex; private void OnEnable() { if (riveWidget == null) { Debug.LogError($"{nameof(RiveNavigationController)}: riveWidget is not assigned."); return; } if (sceneTransitionController == null) { Debug.LogError($"{nameof(RiveNavigationController)}: SceneTransitionController is not assigned."); } riveWidget.OnWidgetStatusChanged += HandleWidgetStatusChanged; // In case the widget already finished loading before we subscribed. HandleWidgetStatusChanged(); } private void OnDisable() { if (riveWidget != null) riveWidget.OnWidgetStatusChanged -= HandleWidgetStatusChanged; } private void HandleWidgetStatusChanged() { if (riveWidget.Status != WidgetStatus.Loaded) return; ViewModelInstance viewModelInstance = riveWidget.StateMachine?.ViewModelInstance; if (viewModelInstance == null) { Debug.LogError($"{nameof(RiveNavigationController)}: ViewModelInstance is null. " + "Set Data Binding Mode to Auto Bind Default on the Rive Widget."); return; } // Cache both triggers once the artboard is ready so Update() doesn't do // string lookups every frame. nextTrigger = viewModelInstance.GetTriggerProperty(NextTriggerName); previousTrigger = viewModelInstance.GetTriggerProperty(PreviousTriggerName); if (nextTrigger == null) Debug.LogError($"{nameof(RiveNavigationController)}: Trigger '{NextTriggerName}' not found on view model."); if (previousTrigger == null) Debug.LogError($"{nameof(RiveNavigationController)}: Trigger '{PreviousTriggerName}' not found on view model."); } private void Update() { Keyboard keyboard = Keyboard.current; Gamepad gamepad = Gamepad.current; bool movedRight = false; bool movedLeft = false; bool confirmPressed = false; if (keyboard != null) { movedRight |= keyboard.rightArrowKey.wasPressedThisFrame; movedLeft |= keyboard.leftArrowKey.wasPressedThisFrame; confirmPressed |= keyboard.enterKey.wasPressedThisFrame || keyboard.numpadEnterKey.wasPressedThisFrame; } if (gamepad != null) { // D-pad and left stick both move the selection — leftStick.left/right are the // Input System's built-in synthetic buttons derived from the stick's deflection, // so this fires once per push just like a button, not continuously while held. movedRight |= gamepad.dpad.right.wasPressedThisFrame || gamepad.leftStick.right.wasPressedThisFrame; movedLeft |= gamepad.dpad.left.wasPressedThisFrame || gamepad.leftStick.left.wasPressedThisFrame; confirmPressed |= gamepad.buttonSouth.wasPressedThisFrame; } if (movedRight) { MoveSelection(+1); nextTrigger?.Trigger(); } if (movedLeft) { MoveSelection(-1); previousTrigger?.Trigger(); } if (confirmPressed && selectedIndex == PlayIndex) { if (sceneTransitionController == null) { Debug.LogError($"{nameof(RiveNavigationController)}: SceneTransitionController is not assigned."); return; } sceneTransitionController.LoadGameplayScene(); } } private void MoveSelection(int direction) { if (menuItemCount <= 0) return; selectedIndex += direction; if (selectedIndex >= menuItemCount) selectedIndex = 0; if (selectedIndex < 0) selectedIndex = menuItemCount - 1; Debug.Log($"Rive menu selection index: {selectedIndex}"); } }