FaceoffPositioning.cs 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. using UnityEngine;
  2. /// <summary>
  3. /// Positions players correctly for faceoff based on their positions
  4. /// Handles both center ice and zone faceoffs
  5. /// </summary>
  6. public class FaceoffPositioning : MonoBehaviour
  7. {
  8. [Header("Faceoff Locations")]
  9. [SerializeField] private Transform centerIceFaceoff;
  10. [SerializeField] private Transform homeZoneFaceoff;
  11. [SerializeField] private Transform awayZoneFaceoff;
  12. [Header("Position Offsets")]
  13. [SerializeField] private float centerDistance = 0.5f; // Centers from faceoff dot
  14. [SerializeField] private float wingDistance = 3.0f; // Wings from center
  15. [SerializeField] private float defenseDistance = 5.0f; // Defenders behind
  16. [SerializeField] private float wingBackDistance = 1.5f; // Wings back from faceoff
  17. public enum FaceoffLocation
  18. {
  19. CenterIce,
  20. HomeZone,
  21. AwayZone
  22. }
  23. /// <summary>
  24. /// Position all players for a faceoff
  25. /// </summary>
  26. public void PositionPlayersForFaceoff(FaceoffLocation location)
  27. {
  28. Transform faceoffSpot = GetFaceoffSpot(location);
  29. if (faceoffSpot == null)
  30. {
  31. Debug.LogError("Faceoff spot not set!");
  32. return;
  33. }
  34. // Find all players
  35. PlayerController[] allPlayers = FindObjectsOfType<PlayerController>();
  36. foreach (PlayerController player in allPlayers)
  37. {
  38. bool isHomeTeam = player.CompareTag("HomeTeam");
  39. Vector3 position = CalculateFaceoffPosition(
  40. player.stats.position,
  41. isHomeTeam,
  42. faceoffSpot.position,
  43. location
  44. );
  45. player.transform.position = position;
  46. // Face the faceoff spot
  47. Vector3 lookDirection = faceoffSpot.position - position;
  48. if (lookDirection.magnitude > 0.1f)
  49. {
  50. player.transform.rotation = Quaternion.LookRotation(lookDirection);
  51. }
  52. }
  53. Debug.Log($"Players positioned for {location} faceoff");
  54. }
  55. private Transform GetFaceoffSpot(FaceoffLocation location)
  56. {
  57. switch (location)
  58. {
  59. case FaceoffLocation.CenterIce:
  60. return centerIceFaceoff;
  61. case FaceoffLocation.HomeZone:
  62. return homeZoneFaceoff;
  63. case FaceoffLocation.AwayZone:
  64. return awayZoneFaceoff;
  65. default:
  66. return centerIceFaceoff;
  67. }
  68. }
  69. private Vector3 CalculateFaceoffPosition(PlayerPosition position, bool isHomeTeam, Vector3 faceoffSpot, FaceoffLocation location)
  70. {
  71. // Multiplier for team side (home = -1, away = +1 typically)
  72. float teamSide = isHomeTeam ? -1f : 1f;
  73. // Defensive zone faceoffs might require different positioning
  74. bool isDefensiveFaceoff = (isHomeTeam && location == FaceoffLocation.HomeZone) ||
  75. (!isHomeTeam && location == FaceoffLocation.AwayZone);
  76. Vector3 offset = Vector3.zero;
  77. switch (position)
  78. {
  79. case PlayerPosition.C: // Center
  80. // Centers face each other at faceoff
  81. offset = new Vector3(0, 0, centerDistance * teamSide);
  82. break;
  83. case PlayerPosition.LW: // Left Wing
  84. // Wing to the left, slightly back
  85. offset = new Vector3(-wingDistance, 0, wingBackDistance * teamSide);
  86. break;
  87. case PlayerPosition.RW: // Right Wing
  88. // Wing to the right, slightly back
  89. offset = new Vector3(wingDistance, 0, wingBackDistance * teamSide);
  90. break;
  91. case PlayerPosition.LD: // Left Defense
  92. // Defender back and to the left
  93. if (isDefensiveFaceoff)
  94. {
  95. offset = new Vector3(-defenseDistance * 0.7f, 0, -defenseDistance * teamSide);
  96. }
  97. else
  98. {
  99. offset = new Vector3(-defenseDistance * 0.7f, 0, -defenseDistance * 0.5f * teamSide);
  100. }
  101. break;
  102. case PlayerPosition.RD: // Right Defense
  103. // Defender back and to the right
  104. if (isDefensiveFaceoff)
  105. {
  106. offset = new Vector3(defenseDistance * 0.7f, 0, -defenseDistance * teamSide);
  107. }
  108. else
  109. {
  110. offset = new Vector3(defenseDistance * 0.7f, 0, -defenseDistance * 0.5f * teamSide);
  111. }
  112. break;
  113. }
  114. return faceoffSpot + offset;
  115. }
  116. /// <summary>
  117. /// Setup faceoff spots automatically based on rink dimensions
  118. /// Call this if you don't have faceoff spots set up manually
  119. /// </summary>
  120. [ContextMenu("Auto-Create Faceoff Spots")]
  121. public void AutoCreateFaceoffSpots()
  122. {
  123. // Typical NHL rink: 200ft x 85ft = ~61m x 26m
  124. // Faceoff circles are 15ft from blue lines, center ice
  125. if (centerIceFaceoff == null)
  126. {
  127. GameObject centerSpot = new GameObject("CenterIceFaceoff");
  128. centerSpot.transform.position = new Vector3(0, 0, 0);
  129. centerIceFaceoff = centerSpot.transform;
  130. Debug.Log("Created center ice faceoff spot");
  131. }
  132. if (homeZoneFaceoff == null)
  133. {
  134. GameObject homeSpot = new GameObject("HomeZoneFaceoff");
  135. homeSpot.transform.position = new Vector3(0, 0, -20f); // Adjust based on your rink
  136. homeZoneFaceoff = homeSpot.transform;
  137. Debug.Log("Created home zone faceoff spot");
  138. }
  139. if (awayZoneFaceoff == null)
  140. {
  141. GameObject awaySpot = new GameObject("AwayZoneFaceoff");
  142. awaySpot.transform.position = new Vector3(0, 0, 20f); // Adjust based on your rink
  143. awayZoneFaceoff = awaySpot.transform;
  144. Debug.Log("Created away zone faceoff spot");
  145. }
  146. Debug.Log("Faceoff spots created! Adjust positions in inspector to match your rink");
  147. }
  148. // Testing in editor
  149. void Update()
  150. {
  151. if (!Application.isPlaying) return;
  152. // Test keys
  153. if (Input.GetKeyDown(KeyCode.Alpha1))
  154. {
  155. PositionPlayersForFaceoff(FaceoffLocation.CenterIce);
  156. }
  157. if (Input.GetKeyDown(KeyCode.Alpha2))
  158. {
  159. PositionPlayersForFaceoff(FaceoffLocation.HomeZone);
  160. }
  161. if (Input.GetKeyDown(KeyCode.Alpha3))
  162. {
  163. PositionPlayersForFaceoff(FaceoffLocation.AwayZone);
  164. }
  165. }
  166. // Draw faceoff spots in editor
  167. void OnDrawGizmos()
  168. {
  169. if (centerIceFaceoff != null)
  170. {
  171. Gizmos.color = Color.blue;
  172. Gizmos.DrawWireSphere(centerIceFaceoff.position, 0.3f);
  173. Gizmos.DrawLine(centerIceFaceoff.position + Vector3.left * 0.5f, centerIceFaceoff.position + Vector3.right * 0.5f);
  174. Gizmos.DrawLine(centerIceFaceoff.position + Vector3.forward * 0.5f, centerIceFaceoff.position + Vector3.back * 0.5f);
  175. #if UNITY_EDITOR
  176. UnityEditor.Handles.Label(centerIceFaceoff.position + Vector3.up, "Center Ice");
  177. #endif
  178. }
  179. if (homeZoneFaceoff != null)
  180. {
  181. Gizmos.color = Color.red;
  182. Gizmos.DrawWireSphere(homeZoneFaceoff.position, 0.3f);
  183. #if UNITY_EDITOR
  184. UnityEditor.Handles.Label(homeZoneFaceoff.position + Vector3.up, "Home Zone");
  185. #endif
  186. }
  187. if (awayZoneFaceoff != null)
  188. {
  189. Gizmos.color = Color.green;
  190. Gizmos.DrawWireSphere(awayZoneFaceoff.position, 0.3f);
  191. #if UNITY_EDITOR
  192. UnityEditor.Handles.Label(awayZoneFaceoff.position + Vector3.up, "Away Zone");
  193. #endif
  194. }
  195. }
  196. }