PlayerController.cs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. using UnityEngine;
  2. using TMPro;
  3. using System;
  4. public class PlayerController : MonoBehaviour
  5. {
  6. [Header("References")]
  7. public PlayerStats stats;
  8. public PlayerMentality mentality;
  9. public AIStrategy currentStrategy;
  10. [Header("UI")]
  11. public TextMeshPro positionLabel;
  12. public GameObject circleMesh;
  13. [Header("Puck Possession")]
  14. [SerializeField] private GameObject possessionIndicator; // Visual indicator when player has puck
  15. [SerializeField] private float pickupCooldown = 0.5f;
  16. private bool hasPuck = false;
  17. private PuckController controlledPuck;
  18. private float lastPickupTime = 0f;
  19. private bool isFrozen = false;
  20. void Start()
  21. {
  22. SetupVisuals();
  23. }
  24. void Update()
  25. {
  26. UpdatePossessionIndicator();
  27. }
  28. void SetupVisuals()
  29. {
  30. // Create circle (use a cylinder with flat height)
  31. if (circleMesh == null)
  32. {
  33. circleMesh = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
  34. circleMesh.transform.SetParent(transform);
  35. circleMesh.transform.localPosition = Vector3.zero;
  36. circleMesh.transform.localScale = new Vector3(1f, 0.1f, 1f);
  37. }
  38. // Create position label
  39. if (positionLabel == null)
  40. {
  41. GameObject labelObj = new GameObject("PositionLabel");
  42. labelObj.transform.SetParent(transform);
  43. labelObj.transform.localPosition = new Vector3(0, 0.5f, 0);
  44. positionLabel = labelObj.AddComponent<TextMeshPro>();
  45. positionLabel.alignment = TextAlignmentOptions.Center;
  46. positionLabel.fontSize = 4;
  47. }
  48. positionLabel.text = stats.position.ToString();
  49. // Create possession indicator (ring around player)
  50. if (possessionIndicator == null)
  51. {
  52. possessionIndicator = GameObject.CreatePrimitive(PrimitiveType.Sphere);
  53. if (possessionIndicator.GetComponent<MeshFilter>() == null)
  54. {
  55. // Fallback: create a thin cylinder ring
  56. possessionIndicator = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
  57. }
  58. possessionIndicator.transform.SetParent(transform);
  59. possessionIndicator.transform.localPosition = new Vector3(0, 0.2f, 0);
  60. possessionIndicator.transform.localScale = new Vector3(1.5f, 0.05f, 1.5f);
  61. // Make it bright and visible
  62. Renderer renderer = possessionIndicator.GetComponent<Renderer>();
  63. if (renderer != null)
  64. {
  65. renderer.material.color = Color.yellow;
  66. renderer.material.EnableKeyword("_EMISSION");
  67. renderer.material.SetColor("_EmissionColor", Color.yellow);
  68. }
  69. // Remove collider from indicator
  70. Collider indicatorCollider = possessionIndicator.GetComponent<Collider>();
  71. if (indicatorCollider != null)
  72. {
  73. Destroy(indicatorCollider);
  74. }
  75. possessionIndicator.SetActive(false);
  76. }
  77. }
  78. void UpdatePossessionIndicator()
  79. {
  80. if (possessionIndicator != null)
  81. {
  82. possessionIndicator.SetActive(hasPuck);
  83. // Rotate for visual effect
  84. if (hasPuck)
  85. {
  86. possessionIndicator.transform.Rotate(Vector3.up, 180f * Time.deltaTime);
  87. }
  88. }
  89. }
  90. public void SetFrozen(bool frozen)
  91. {
  92. isFrozen = frozen;
  93. // You can add visual feedback here (e.g., change color, show "frozen" indicator)
  94. }
  95. public void GainPuck(PuckController newPuck)
  96. {
  97. controlledPuck = newPuck;
  98. hasPuck = true;
  99. lastPickupTime = Time.time;
  100. Debug.Log($"{stats.playerName} gained control of the puck!");
  101. }
  102. public void ReleasePuck()
  103. {
  104. if (controlledPuck != null)
  105. {
  106. controlledPuck = null;
  107. hasPuck = false;
  108. }
  109. }
  110. public bool CanPickupPuck()
  111. {
  112. // Can only pick up if not recently picked up and not frozen
  113. return !hasPuck && !isFrozen && (Time.time - lastPickupTime) > pickupCooldown;
  114. }
  115. public bool HasPuck()
  116. {
  117. return hasPuck;
  118. }
  119. public void Shoot(Vector3 targetDirection, float powerMultiplier = 1.0f)
  120. {
  121. if (!hasPuck || controlledPuck == null) return;
  122. // Calculate shot accuracy based on stats
  123. float accuracy = stats.shotAccuracy / 100f;
  124. float power = stats.shotPower / 100f;
  125. // Add some inaccuracy based on stats
  126. Vector3 direction = targetDirection;
  127. float inaccuracy = (1f - accuracy) * 15f; // Up to 15 degrees off
  128. direction = Quaternion.Euler(0, UnityEngine.Random.Range(-inaccuracy, inaccuracy), 0) * direction;
  129. // Apply force to puck
  130. float shotForce = power * 30f * powerMultiplier; // Base force multiplied by power stat
  131. controlledPuck.ApplyForce(direction.normalized * shotForce, ForceMode.Impulse);
  132. Debug.Log($"{stats.playerName} shoots! Accuracy: {accuracy}, Power: {power}");
  133. }
  134. public void Pass(PlayerController target)
  135. {
  136. if (!hasPuck || controlledPuck == null || target == null) return;
  137. float accuracy = stats.passAccuracy / 100f;
  138. // Calculate pass direction and force based on distance
  139. Vector3 direction = (target.transform.position - transform.position).normalized;
  140. float distance = Vector3.Distance(transform.position, target.transform.position);
  141. // Add inaccuracy
  142. float inaccuracy = (1f - accuracy) * 10f;
  143. direction = Quaternion.Euler(0, UnityEngine.Random.Range(-inaccuracy, inaccuracy), 0) * direction;
  144. // Force scales with distance
  145. float passForce = Mathf.Lerp(10f, 25f, distance / 30f);
  146. controlledPuck.ApplyForce(direction * passForce, ForceMode.Impulse);
  147. Debug.Log($"{stats.playerName} passes to {target.stats.playerName}! Accuracy: {accuracy}");
  148. }
  149. public void Check(PlayerController target)
  150. {
  151. if (target == null) return;
  152. float checkPower = stats.checking / 100f;
  153. bool checkSuccess = UnityEngine.Random.value < checkPower;
  154. if (checkSuccess && target.HasPuck())
  155. {
  156. // Successful check - target loses puck
  157. Debug.Log($"{stats.playerName} checks {target.stats.playerName} successfully!");
  158. if (target.controlledPuck != null)
  159. {
  160. // Knock puck loose
  161. Vector3 knockDirection = (target.transform.position - transform.position).normalized;
  162. target.controlledPuck.ApplyForce(knockDirection * 8f, ForceMode.Impulse);
  163. }
  164. }
  165. else
  166. {
  167. Debug.Log($"{stats.playerName} checks {target.stats.playerName} but fails to dislodge puck");
  168. }
  169. }
  170. }