using TMPro; using UdonSharp; using UnityEngine; using VRC.SDKBase; using VRC.Udon; [UdonBehaviourSyncMode(BehaviourSyncMode.Continuous)] public class PlayerHorseshoe : UdonSharpBehaviour { [SerializeField] private Canvas _ScoreDisplayCanvas; [SerializeField] private TextMeshProUGUI _ScoreDisplayText; [Space] [SerializeField] private HorseshoesGameManager _GameManager; [SerializeField] private Transform[] _ValidStakes; [SerializeField] private ParticleSystem _SandBurst; [Space] [SerializeField] private Rigidbody _HorseshoeRigidBody; [SerializeField] private PlayerHorseshoeStakeDetection _RingerDetector; [SerializeField] private PlayerHorseshoeStakeDetection _LeanDetector; [SerializeField] private Transform[] _DistanceDetectors; [UdonSynced, FieldChangeCallback(nameof(ScoreText))] private string _ScoreText = ""; private bool _CheckMotion = false; private float _CheckMotionTimer = 0.0f; void FixedUpdate() { if (_CheckMotion) { if (_HorseshoeRigidBody.velocity.magnitude < 0.0000000000001f && _HorseshoeRigidBody.angularVelocity.sqrMagnitude < 0.0000000000001f) { _CheckMotionTimer += Time.fixedDeltaTime; if (_CheckMotionTimer >= 0.5f) { DetermineDistance(); } } else { _CheckMotionTimer = 0.0f; } } } private void DetermineDistance() { if (_RingerDetector.StakeCollision) { _GameManager.CalculateRinger(this); } //else if (_LeanDetector.StakeCollision) //{ // Debug.LogError("[PlayerHorseshoe] Leaning on stake."); //} else { // First, figure out which stake we're closest to Vector3 ClosestStakePosition = Vector3.zero; float ClosestStakeDistance = float.MaxValue; foreach (Transform StakeTransform in _ValidStakes) { float DistanceToStake = Vector3.Distance(transform.position, StakeTransform.position); if (DistanceToStake < ClosestStakeDistance) { ClosestStakeDistance = DistanceToStake; ClosestStakePosition = StakeTransform.position; } } // Then determine which distance detector is closest to this stake float ClosestShoeDistance = float.MaxValue; foreach (Transform DistanceDetector in _DistanceDetectors) { // Change Y value to 0 for all positions, so we only measure lateral position. Vector3 DistanceDetectorPositionLateral = DistanceDetector.position; DistanceDetectorPositionLateral.y = 0.0f; Vector3 ClosestStakePositionLateral = ClosestStakePosition; ClosestStakePositionLateral.y = 0.0f; float DistanceToStake = Vector3.Distance(DistanceDetectorPositionLateral, ClosestStakePositionLateral); if (DistanceToStake < ClosestShoeDistance) { ClosestShoeDistance = DistanceToStake; } } // Subtract half an inch from the measurement, since we measure from the // centre of the 1" diameter stake ClosestShoeDistance -= (0.0254f / 2.0f); _GameManager.CalculatePoints(this, ClosestShoeDistance); //Debug.Log("[PlayerHorseshoe] Detected distance: " + ClosestShoeDistance); } StopCheckingMotion(); } void OnCollisionEnter(Collision Other) { if (_HorseshoeRigidBody.velocity.sqrMagnitude > 1.0f && Other.gameObject.name.StartsWith("Sand")) { _SandBurst.Play(); } } void LateUpdate() { _ScoreDisplayCanvas.transform.LookAt(Networking.LocalPlayer.GetBonePosition(HumanBodyBones.Head), Vector3.up); } public override void OnPickup() { ScoreText = ""; base.OnPickup(); } public override void OnDrop() { SendCustomEventDelayedSeconds(nameof(StartCheckingMotion), 0.05f); base.OnDrop(); } public void StartCheckingMotion() { _CheckMotion = true; _CheckMotionTimer = 0.0f; } public void StopCheckingMotion() { _CheckMotion = false; _CheckMotionTimer = 0.0f; } public void SetScoreText(string Text) { ScoreText = Text; RequestSerialization(); } private string ScoreText { set { _ScoreText = value; _ScoreDisplayText.text = _ScoreText; _ScoreDisplayCanvas.gameObject.SetActive(!(value == null || value == "")); } get => _ScoreText; } }