JumpPad.cs 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  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/Jump Pad Controller")]
  8. public class JumpPad : UdonSharpBehaviour
  9. {
  10. public bool debug;
  11. public Animator launchAnim;
  12. public string animName = "isLaunch";
  13. public Transform jumpTarget;
  14. public Transform self;
  15. public float arcTime = 1.2f;
  16. public float walkLimit = 0.2f;
  17. public float runLimit = 0.4f;
  18. public float strafeLimit = 0.2f;
  19. private Vector3 appliedVelocity;
  20. private float defaultWalk;
  21. private float defaultStrafe;
  22. private float defaultRun;
  23. private VRCPlayerApi player;
  24. private bool ready;
  25. private int localLaunches; // Launches of the local player still in the air
  26. private int animLaunches; // Launches of anyone still holding the launch animation on
  27. void Start()
  28. {
  29. // The inspector's Animator wins; only fall back to one on this object
  30. if (launchAnim == null) launchAnim = GetComponent<Animator>();
  31. if (self == null) self = transform;
  32. if (jumpTarget == null)
  33. {
  34. Debug.LogError("[AUMSS] Jump Pad Controller: Jump Target isn't assigned, so the pad won't launch anything.");
  35. return;
  36. }
  37. ready = true;
  38. if (debug) Debug.Log("Jump Pad Controller: Velocity Calculated to:" + CalculateInitialVelocity(self.position, jumpTarget.position, Physics.gravity.y, arcTime).ToString());
  39. }
  40. public static Vector3 CalculateInitialVelocity(Vector3 origin, Vector3 target, float gravity, float time)
  41. {
  42. // Compute the differences in position
  43. Vector3 displacement = target - origin;
  44. // Calculate the initial velocity components
  45. Vector3 initialVelocity = new Vector3(
  46. displacement.x / time, // Horizontal X velocity
  47. (displacement.y - 0.5f * gravity * time * time) / time, // Vertical Y velocity
  48. displacement.z / time // Horizontal Z velocity
  49. );
  50. return initialVelocity;
  51. }
  52. private float LaunchDuration()
  53. {
  54. return Mathf.Max(arcTime - 0.2f, 0f);
  55. }
  56. public override void OnPlayerTriggerEnter(VRCPlayerApi collidedPlayer)
  57. {
  58. if (!ready) return;
  59. StartLaunchAnim();
  60. SendCustomEventDelayedSeconds(nameof(EndLaunchAnim), LaunchDuration());
  61. // Remote players get launched by their own client, and speed/velocity calls on them throw and halt this script
  62. if (!collidedPlayer.isLocal) return;
  63. player = collidedPlayer;
  64. // Only save the speeds when not already mid-launch: mid-launch they're the limits, and would be kept forever
  65. if (localLaunches == 0)
  66. {
  67. defaultRun = player.GetRunSpeed();
  68. defaultStrafe = player.GetStrafeSpeed();
  69. defaultWalk = player.GetWalkSpeed();
  70. }
  71. localLaunches++;
  72. // Players fall with the world's gravity scaled by their own gravity strength
  73. appliedVelocity = CalculateInitialVelocity(self.position, jumpTarget.position, Physics.gravity.y * player.GetGravityStrength(), arcTime);
  74. LimitMobility();
  75. player.SetVelocity(appliedVelocity);
  76. if (debug) Debug.Log("Jump Pad Controller: Player Velocity Set to:" + appliedVelocity.ToString());
  77. SendCustomEventDelayedSeconds(nameof(Mobilize), LaunchDuration());
  78. }
  79. private void OnTriggerEnter(Collider other)
  80. {
  81. if (!ready || other == null) return;
  82. VRC_Pickup pickup = other.GetComponent<VRC_Pickup>();
  83. Rigidbody body = other.GetComponent<Rigidbody>();
  84. if (pickup == null || body == null) return;
  85. // A synced pickup is launched by its owner; anyone else setting its velocity just fights the sync
  86. if (other.GetComponent<VRCObjectSync>() != null && !Networking.IsOwner(other.gameObject)) return;
  87. appliedVelocity = CalculateInitialVelocity(self.position, jumpTarget.position, Physics.gravity.y, arcTime);
  88. pickup.Drop();
  89. body.velocity = appliedVelocity;
  90. }
  91. public void LimitMobility()
  92. {
  93. if (!Utilities.IsValid(player)) return;
  94. player.SetWalkSpeed(walkLimit);
  95. player.SetRunSpeed(runLimit);
  96. player.SetStrafeSpeed(strafeLimit);
  97. if (debug) Debug.Log("Jump Pad Controller: Limited Player Mobility for " + arcTime.ToString() + " seconds");
  98. }
  99. public void Mobilize()
  100. {
  101. if (localLaunches > 0) localLaunches--;
  102. if (localLaunches > 0 || !Utilities.IsValid(player)) return; // Still in the air from a later launch
  103. player.SetWalkSpeed(defaultWalk);
  104. player.SetRunSpeed(defaultRun);
  105. player.SetStrafeSpeed(defaultStrafe);
  106. if (debug) Debug.Log("Jump Pad Controller: De-Limited Player Mobility after" + arcTime.ToString() + " seconds");
  107. }
  108. private void StartLaunchAnim()
  109. {
  110. animLaunches++;
  111. if (launchAnim == null || string.IsNullOrEmpty(animName)) return;
  112. launchAnim.SetBool(animName, true);
  113. if (debug) Debug.Log("Jump Pad Controller: Animator State attempted to be set to True");
  114. }
  115. public void EndLaunchAnim()
  116. {
  117. if (animLaunches > 0) animLaunches--;
  118. if (animLaunches > 0) return; // Someone else launched since; their launch ends it
  119. if (launchAnim == null || string.IsNullOrEmpty(animName)) return;
  120. launchAnim.SetBool(animName, false);
  121. if (debug) Debug.Log("Jump Pad Controller: Animator State attempted to be set to False");
  122. }
  123. }