namespace Marro.PacManUdon { using System; using UnityEngine; using VRC.SDKBase; using VRC.Udon.Common; enum InputMethod { KeyboardMouse, Other, } public class PlayerInput : SyncedObject { public bool active; private GameManager gameManager; private VRCPlayerApi player; private InputMethod inputMethod; private Direction resultInput; private Vector2 analogInput; private bool dirty; private HandType lastUsedHand; private bool horizontalPriority; public void Initialize(GameManager gameManager) { this.gameManager = gameManager; player = Networking.LocalPlayer; inputMethod = InputMethod.KeyboardMouse; resultInput = Direction.Zero; analogInput = Vector2.zero; dirty = false; horizontalPriority = false; SubscribeToEvent(NetworkEventType.InputChange); } void Update() { if (active) { if (Input.GetKeyDown(KeyCode.R)) { gameManager.ResetButtonPressed(); } if (Input.GetKeyDown(KeyCode.G)) { gameManager.networkManager.DoFullSync(); } if (Input.GetKeyDown(KeyCode.C)) { gameManager.JumpToTimeSequenceBoardClear(); } } else { if (Input.GetKeyDown(KeyCode.T)) { gameManager.ResetButtonPressed(); } } } public override void SyncedUpdate() { if (dirty) // Update now to ensure input feedback is performed timely { UpdateResultInput(); } } public void Activate() { Debug.Log($"{gameObject} got activated, {player} was immobilized"); active = true; player.SetWalkSpeed(0); player.SetRunSpeed(0); player.SetStrafeSpeed(0); gameManager.JoystickGrabbed(); } public void Deactivate() { Debug.Log($"{gameObject} got deactivated, {player} was released"); player.SetWalkSpeed(2); player.SetRunSpeed(4); player.SetStrafeSpeed(2); active = false; gameManager.JoystickReleased(); } public override void InputJump(bool pressed, UdonInputEventArgs args) { if (!active) { return; } if (pressed) { Deactivate(); } } public override void InputMoveHorizontal(float value, UdonInputEventArgs args) { if (!active) { return; } analogInput.x = value; lastUsedHand = args.handType; dirty = true; } public override void InputMoveVertical(float value, UdonInputEventArgs args) { if (!active) { return; } analogInput.y = value; lastUsedHand = args.handType; dirty = true; } public override void OnInputMethodChanged(VRCInputMethod inputMethod) { switch (inputMethod) { case VRCInputMethod.Keyboard: case VRCInputMethod.Mouse: this.inputMethod = InputMethod.KeyboardMouse; return; default: this.inputMethod = InputMethod.Other; return; } } private void UpdateResultInput() { dirty = false; var newResult = GetResultInput(analogInput); if (newResult == resultInput) { return; } //Debug.Log($"Switched to input direction {newResult} from analogInput {analogInput} with HorizontalPriority {horizontalPriority}"); resultInput = newResult; networkManager.SendEventSoon(NetworkEventType.InputChange, true); PlayHaptics(); } private void PlayHaptics() { if (inputMethod == InputMethod.KeyboardMouse) { return; } VRC_Pickup.PickupHand hand; switch (lastUsedHand) { case HandType.LEFT: hand = VRC_Pickup.PickupHand.Left; break; case HandType.RIGHT: hand = VRC_Pickup.PickupHand.Right; break; default: return; } player.PlayHapticEventInHand(hand, 0.1f, 0.15f, 75); } private Direction GetResultInput(Vector2 analogInput) { if (analogInput.magnitude < 0.8) { return Direction.Zero; } var normalized = analogInput.normalized; //Debug.Log($"Checking analogInput {analogInput} with HorizontalPriority {horizontalPriority}, normalized {normalized}"); const float directionDivider = 0.72f; if (normalized.x > directionDivider) { horizontalPriority = false; return Direction.Right; } else if (normalized.x < -directionDivider) { horizontalPriority = false; return Direction.Left; } else if (normalized.y > directionDivider) { horizontalPriority = true; return Direction.Up; } else if (normalized.y < -directionDivider) { horizontalPriority = true; return Direction.Down; } if (horizontalPriority) { if (normalized.x > 0) { return Direction.Right; } return Direction.Left; } if (normalized.y > 0) { return Direction.Up; } return Direction.Down; } public Direction GetDirection() { if (dirty) // Update now to reduce input delay { UpdateResultInput(); } return resultInput; } public override void CollectSyncedData(byte[] data, ref int index, NetworkEventType eventType) { if (eventType != NetworkEventType.InputChange) { return; } ByteUtils.AppendAsByte(data, (int)resultInput, ref index); } public override bool WriteSyncedData(byte[] data, ref int index, NetworkEventType eventType) { if (eventType != NetworkEventType.InputChange) { return true; } resultInput = (Direction)ByteUtils.ReadByte(data, ref index); return true; } } }