BoneLookAtPlayer.cs 2.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. using UdonSharp;
  2. using UnityEngine;
  3. using VRC.SDKBase;
  4. [UdonBehaviourSyncMode(BehaviourSyncMode.NoVariableSync)]
  5. [DisallowMultipleComponent]
  6. [AddComponentMenu("Artyom Scripting System/Bone Look At Player")]
  7. public class BoneLookAtPlayer : UdonSharpBehaviour
  8. {
  9. public GameObject objectToRotate; // The object to rotate
  10. public float rotationSpeed = 90.0f; // Maximum rotation speed in degrees per second
  11. public Vector3 rotationOffset; // Rotation offset for each axis
  12. private Transform objectTransform;
  13. private VRCPlayerApi[] players = new VRCPlayerApi[0]; // Reused every frame, grown when more players join
  14. void Start()
  15. {
  16. if (objectToRotate == null)
  17. {
  18. Debug.LogError("[AUMSS] Bone Look At Player: Object To Rotate isn't assigned, so nothing will turn.");
  19. enabled = false; // Stops Update, which would otherwise throw and halt the script
  20. return;
  21. }
  22. objectTransform = objectToRotate.transform;
  23. }
  24. void Update()
  25. {
  26. if (objectTransform == null) return; // Not set up (enabled = false only takes effect next frame)
  27. VRCPlayerApi nearestPlayer = GetNearestPlayer();
  28. if (nearestPlayer == null) return;
  29. Vector3 playerHeadPosition = nearestPlayer.GetTrackingData(VRCPlayerApi.TrackingDataType.Head).position;
  30. // Calculate the direction to look
  31. Vector3 directionToLook = playerHeadPosition - objectTransform.position;
  32. if (directionToLook != Vector3.zero)
  33. {
  34. Quaternion targetRotation = Quaternion.LookRotation(directionToLook);
  35. // Apply the rotation offset
  36. targetRotation *= Quaternion.Euler(rotationOffset);
  37. objectTransform.rotation = Quaternion.RotateTowards(objectTransform.rotation, targetRotation, rotationSpeed * Time.deltaTime);
  38. }
  39. }
  40. VRCPlayerApi GetNearestPlayer()
  41. {
  42. int count = VRCPlayerApi.GetPlayerCount();
  43. if (players.Length < count) players = new VRCPlayerApi[count];
  44. VRCPlayerApi.GetPlayers(players);
  45. VRCPlayerApi nearestPlayer = null;
  46. float closestDistance = float.MaxValue;
  47. Vector3 currentPosition = transform.position;
  48. for (int i = 0; i < count; i++)
  49. {
  50. VRCPlayerApi player = players[i];
  51. if (!Utilities.IsValid(player)) continue; // The local player counts too
  52. float distance = Vector3.Distance(currentPosition, player.GetPosition());
  53. if (distance < closestDistance)
  54. {
  55. closestDistance = distance;
  56. nearestPlayer = player;
  57. }
  58. }
  59. return nearestPlayer;
  60. }
  61. }