using UnityEngine; using TMPro; using System; public class PlayerController : MonoBehaviour { [Header("References")] public PlayerStats stats; public PlayerMentality mentality; public AIStrategy currentStrategy; [Header("UI")] public TextMeshPro positionLabel; public GameObject circleMesh; [Header("Puck Possession")] [SerializeField] private GameObject possessionIndicator; // Visual indicator when player has puck [SerializeField] private float pickupCooldown = 0.5f; private bool hasPuck = false; private PuckController controlledPuck; private float lastPickupTime = 0f; private bool isFrozen = false; void Start() { SetupVisuals(); } void Update() { UpdatePossessionIndicator(); } void SetupVisuals() { // Create circle (use a cylinder with flat height) if (circleMesh == null) { circleMesh = GameObject.CreatePrimitive(PrimitiveType.Cylinder); circleMesh.transform.SetParent(transform); circleMesh.transform.localPosition = Vector3.zero; circleMesh.transform.localScale = new Vector3(1f, 0.1f, 1f); } // Create position label if (positionLabel == null) { GameObject labelObj = new GameObject("PositionLabel"); labelObj.transform.SetParent(transform); labelObj.transform.localPosition = new Vector3(0, 0.5f, 0); positionLabel = labelObj.AddComponent(); positionLabel.alignment = TextAlignmentOptions.Center; positionLabel.fontSize = 4; } positionLabel.text = stats.position.ToString(); // Create possession indicator (ring around player) if (possessionIndicator == null) { possessionIndicator = GameObject.CreatePrimitive(PrimitiveType.Sphere); if (possessionIndicator.GetComponent() == null) { // Fallback: create a thin cylinder ring possessionIndicator = GameObject.CreatePrimitive(PrimitiveType.Cylinder); } possessionIndicator.transform.SetParent(transform); possessionIndicator.transform.localPosition = new Vector3(0, 0.2f, 0); possessionIndicator.transform.localScale = new Vector3(1.5f, 0.05f, 1.5f); // Make it bright and visible Renderer renderer = possessionIndicator.GetComponent(); if (renderer != null) { renderer.material.color = Color.yellow; renderer.material.EnableKeyword("_EMISSION"); renderer.material.SetColor("_EmissionColor", Color.yellow); } // Remove collider from indicator Collider indicatorCollider = possessionIndicator.GetComponent(); if (indicatorCollider != null) { Destroy(indicatorCollider); } possessionIndicator.SetActive(false); } } void UpdatePossessionIndicator() { if (possessionIndicator != null) { possessionIndicator.SetActive(hasPuck); // Rotate for visual effect if (hasPuck) { possessionIndicator.transform.Rotate(Vector3.up, 180f * Time.deltaTime); } } } public void SetFrozen(bool frozen) { isFrozen = frozen; // You can add visual feedback here (e.g., change color, show "frozen" indicator) } public void GainPuck(PuckController newPuck) { controlledPuck = newPuck; hasPuck = true; lastPickupTime = Time.time; Debug.Log($"{stats.playerName} gained control of the puck!"); } public void ReleasePuck() { if (controlledPuck != null) { controlledPuck = null; hasPuck = false; } } public bool CanPickupPuck() { // Can only pick up if not recently picked up and not frozen return !hasPuck && !isFrozen && (Time.time - lastPickupTime) > pickupCooldown; } public bool HasPuck() { return hasPuck; } public void Shoot(Vector3 targetDirection, float powerMultiplier = 1.0f) { if (!hasPuck || controlledPuck == null) return; // Calculate shot accuracy based on stats float accuracy = stats.shotAccuracy / 100f; float power = stats.shotPower / 100f; // Add some inaccuracy based on stats Vector3 direction = targetDirection; float inaccuracy = (1f - accuracy) * 15f; // Up to 15 degrees off direction = Quaternion.Euler(0, UnityEngine.Random.Range(-inaccuracy, inaccuracy), 0) * direction; // Apply force to puck float shotForce = power * 30f * powerMultiplier; // Base force multiplied by power stat controlledPuck.ApplyForce(direction.normalized * shotForce, ForceMode.Impulse); Debug.Log($"{stats.playerName} shoots! Accuracy: {accuracy}, Power: {power}"); } public void Pass(PlayerController target) { if (!hasPuck || controlledPuck == null || target == null) return; float accuracy = stats.passAccuracy / 100f; // Calculate pass direction and force based on distance Vector3 direction = (target.transform.position - transform.position).normalized; float distance = Vector3.Distance(transform.position, target.transform.position); // Add inaccuracy float inaccuracy = (1f - accuracy) * 10f; direction = Quaternion.Euler(0, UnityEngine.Random.Range(-inaccuracy, inaccuracy), 0) * direction; // Force scales with distance float passForce = Mathf.Lerp(10f, 25f, distance / 30f); controlledPuck.ApplyForce(direction * passForce, ForceMode.Impulse); Debug.Log($"{stats.playerName} passes to {target.stats.playerName}! Accuracy: {accuracy}"); } public void Check(PlayerController target) { if (target == null) return; float checkPower = stats.checking / 100f; bool checkSuccess = UnityEngine.Random.value < checkPower; if (checkSuccess && target.HasPuck()) { // Successful check - target loses puck Debug.Log($"{stats.playerName} checks {target.stats.playerName} successfully!"); if (target.controlledPuck != null) { // Knock puck loose Vector3 knockDirection = (target.transform.position - transform.position).normalized; target.controlledPuck.ApplyForce(knockDirection * 8f, ForceMode.Impulse); } } else { Debug.Log($"{stats.playerName} checks {target.stats.playerName} but fails to dislodge puck"); } } }