PickupMovementFixer.cs 2.9 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677
  1. using UdonSharp;
  2. using UnityEngine;
  3. using VRC.SDK3.Components;
  4. using VRC.SDKBase;
  5. [UdonBehaviourSyncMode(BehaviourSyncMode.NoVariableSync)]
  6. [DisallowMultipleComponent]
  7. [AddComponentMenu("Artyom Scripting System/Pickup Following Mover Fix")]
  8. public class PickupMovementFixer : UdonSharpBehaviour
  9. {
  10. public GameObject targetObject; // The object to follow
  11. private int pickupLayer = 13; // The layer assigned to pickup objects
  12. private Collider triggerCollider;
  13. private Vector3 previousTargetPosition;
  14. private Vector3 targetVelocity;
  15. private bool carrying; // While the target moves, and for one frame after it stops
  16. private bool ready;
  17. private void Start()
  18. {
  19. triggerCollider = GetComponent<Collider>();
  20. if (triggerCollider == null || !triggerCollider.isTrigger)
  21. {
  22. Debug.LogError("[AUMSS] Pickup Following Mover Fix: Collider must be set as a trigger.");
  23. }
  24. if (targetObject == null)
  25. {
  26. Debug.LogError("[AUMSS] Pickup Following Mover Fix: Target Object isn't assigned.");
  27. enabled = false;
  28. return;
  29. }
  30. previousTargetPosition = targetObject.transform.position;
  31. ready = true;
  32. }
  33. // LateUpdate runs after Update scripts and Animators have moved the target this frame,
  34. // so the movement measured here matches this frame's deltaTime
  35. private void LateUpdate()
  36. {
  37. if (!ready) return; // Not set up (enabled = false only takes effect next frame)
  38. Vector3 currentTargetPosition = targetObject.transform.position;
  39. Vector3 newVelocity = (currentTargetPosition - previousTargetPosition) / Time.deltaTime;
  40. previousTargetPosition = currentTargetPosition;
  41. // A still target leaves the pickups to their own physics, so they can fall and slide.
  42. // The frame it stops still applies (zero), so the pickups stop with it instead of sliding off.
  43. bool moving = newVelocity.sqrMagnitude > 0.0001f;
  44. carrying = moving || targetVelocity.sqrMagnitude > 0.0001f;
  45. targetVelocity = newVelocity;
  46. }
  47. private void OnTriggerEnter(Collider other)
  48. {
  49. Carry(other);
  50. }
  51. private void OnTriggerStay(Collider other)
  52. {
  53. Carry(other);
  54. }
  55. private void Carry(Collider other)
  56. {
  57. if (!ready || !carrying || other == null || other.gameObject.layer != pickupLayer) return;
  58. VRC_Pickup pickup = other.GetComponent<VRC_Pickup>();
  59. if (pickup == null || pickup.IsHeld) return;
  60. // A synced pickup is moved by its owner; anyone else setting its velocity just fights the sync
  61. if (other.GetComponent<VRCObjectSync>() != null && !Networking.IsOwner(other.gameObject)) return;
  62. Rigidbody pickupRigidbody = other.GetComponent<Rigidbody>();
  63. if (pickupRigidbody != null)
  64. {
  65. pickupRigidbody.velocity = targetVelocity;
  66. }
  67. }
  68. }