| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461 |
- using UnityEngine;
- using System.Collections;
- using System.Collections.Generic;
- using System.Linq;
- using UnityEngine.InputSystem;
- public class FaceoffManager : MonoBehaviour
- {
- [Header("References")]
- [SerializeField] private PuckController puck;
- [Header("Faceoff Spots")]
- [SerializeField] private Transform centerIceFaceoffSpot;
- [SerializeField] private Transform homeZoneLeftFaceoffSpot;
- [SerializeField] private Transform homeZoneRightFaceoffSpot;
- [SerializeField] private Transform awayZoneLeftFaceoffSpot;
- [SerializeField] private Transform awayZoneRightFaceoffSpot;
- [SerializeField] private Transform homeZoneBlueLineLeftFaceoffSpot;
- [SerializeField] private Transform homeZoneBlueLineRightFaceoffSpot;
- [SerializeField] private Transform awayZoneBlueLineLeftFaceoffSpot;
- [SerializeField] private Transform awayZoneBlueLineRightFaceoffSpot;
- private Transform currentFaceoffSpot;
- [Header("Faceoff Settings")]
- [SerializeField] private float faceoffDuration = 2.0f;
- [SerializeField] private float struggleDuration = 3.0f;
- [SerializeField] private float struggleChance = 0.3f;
- [SerializeField] private float winThreshold = 0.7f;
- [Header("Puck Launch Settings")]
- [SerializeField] private float passForce = 8f; // Force to send puck to teammate
- [SerializeField] private float struggleLaunchForce = 5f; // Force when puck is loose
- private PlayerController homeCenterPlayer;
- private PlayerController awayCenterPlayer;
- private List<PlayerController> homeTeam = new List<PlayerController>();
- private List<PlayerController> awayTeam = new List<PlayerController>();
- private bool faceoffInProgress = false;
- private FaceoffOutcome currentOutcome;
- // Public property to check if faceoff is in progress
- public bool IsFaceoffInProgress => faceoffInProgress;
- public enum FaceoffOutcome
- {
- None,
- HomeWin,
- AwayWin,
- Struggle
- }
- void Start()
- {
- FindPlayers();
- }
- void FindPlayers()
- {
- PlayerController[] allPlayers = FindObjectsByType<PlayerController>(FindObjectsSortMode.None);
- homeTeam.Clear();
- awayTeam.Clear();
- foreach (var player in allPlayers)
- {
- if (player.CompareTag("HomeTeam"))
- {
- homeTeam.Add(player);
- if (player.stats.position == PlayerPosition.C)
- {
- homeCenterPlayer = player;
- }
- }
- else if (player.CompareTag("AwayTeam"))
- {
- awayTeam.Add(player);
- if (player.stats.position == PlayerPosition.C)
- {
- awayCenterPlayer = player;
- }
- }
- }
- Debug.Log($"Found {homeTeam.Count} home players and {awayTeam.Count} away players");
- }
- public void StartFaceoffAt(Transform faceoffSpot)
- {
- if (faceoffSpot == null)
- {
- Debug.LogWarning("Faceoff spot is not assigned!");
- return;
- }
- currentFaceoffSpot = faceoffSpot;
- StartFaceoff();
- }
- public void StartFaceoff()
- {
- if (faceoffInProgress)
- {
- Debug.LogWarning("Faceoff already in progress!");
- return;
- }
- if (currentFaceoffSpot == null)
- {
- currentFaceoffSpot = centerIceFaceoffSpot;
- }
- if (homeCenterPlayer == null || awayCenterPlayer == null)
- {
- Debug.LogError("Missing center players for faceoff!");
- return;
- }
- StartCoroutine(FaceoffSequence());
- }
- private IEnumerator FaceoffSequence()
- {
- faceoffInProgress = true;
- Debug.Log("Faceoff starting...");
- // Stop timer and freeze players during faceoff
- if (GameManager.Instance != null)
- {
- GameManager.Instance.SetPuckInPlay(false);
- }
- // Position puck at faceoff spot
- if (puck != null && currentFaceoffSpot != null)
- {
- puck.transform.position = currentFaceoffSpot.position + Vector3.up * 0.025f; // Slight lift
- puck.Release(); // Make sure puck is free
- }
- FreezeAllPlayers(true);
- yield return new WaitForSeconds(1.0f);
- currentOutcome = DetermineFaceoffOutcome();
- Debug.Log($"Faceoff outcome: {currentOutcome}");
- yield return new WaitForSeconds(faceoffDuration);
- switch (currentOutcome)
- {
- case FaceoffOutcome.HomeWin:
- ExecuteCleanWin(homeCenterPlayer, homeTeam, awayTeam);
- break;
- case FaceoffOutcome.AwayWin:
- ExecuteCleanWin(awayCenterPlayer, awayTeam, homeTeam);
- break;
- case FaceoffOutcome.Struggle:
- ExecuteStruggle();
- yield return new WaitForSeconds(struggleDuration);
- break;
- }
- FreezeAllPlayers(false);
- faceoffInProgress = false;
- // Start timer and allow movement after faceoff completes
- if (GameManager.Instance != null)
- {
- GameManager.Instance.SetPuckInPlay(true);
- }
- Debug.Log("Faceoff complete!");
- }
- private FaceoffOutcome DetermineFaceoffOutcome()
- {
- if (homeCenterPlayer == null || awayCenterPlayer == null)
- return FaceoffOutcome.Struggle;
- float homeStrength = CalculateFaceoffStrength(homeCenterPlayer);
- float awayStrength = CalculateFaceoffStrength(awayCenterPlayer);
- float totalStrength = homeStrength + awayStrength;
- float homeWinChance = homeStrength / totalStrength;
- if (Mathf.Abs(homeWinChance - 0.5f) < (0.5f - winThreshold))
- {
- return FaceoffOutcome.Struggle;
- }
- float roll = Random.value;
- if (roll < struggleChance)
- {
- return FaceoffOutcome.Struggle;
- }
- return Random.value < homeWinChance ? FaceoffOutcome.HomeWin : FaceoffOutcome.AwayWin;
- }
- private float CalculateFaceoffStrength(PlayerController player)
- {
- return (player.stats.strength * 0.3f) +
- (player.stats.stickHandling * 0.3f) +
- (player.stats.awareness * 0.2f) +
- (player.stats.agility * 0.2f);
- }
- private void ExecuteCleanWin(PlayerController winner, List<PlayerController> winningTeam, List<PlayerController> losingTeam)
- {
- Debug.Log($"{winner.stats.playerName} wins the faceoff cleanly!");
- // Find best pass target FIRST (before assigning puck)
- PlayerController target = ChoosePassTarget(winner, winningTeam);
- if (target != null && target != winner)
- {
- Debug.Log($"Puck sent to {target.stats.playerName} at position {target.transform.position}");
- // Calculate direction from FACEOFF SPOT (not puck position, since puck might be carried)
- Vector3 startPosition = currentFaceoffSpot.position;
- Vector3 targetPosition = target.transform.position;
- // Keep pass flat on the ice (ignore Y difference)
- startPosition.y = 0.025f;
- targetPosition.y = 0.025f;
- Vector3 passDirection = (targetPosition - startPosition).normalized;
- float distance = Vector3.Distance(startPosition, targetPosition);
- float adjustedForce = passForce * Mathf.Clamp(distance / 5f, 0.8f, 2f);
- Debug.Log($"Pass direction: {passDirection}, Distance: {distance:F2}m, Force: {adjustedForce:F2}");
- // Make sure puck is free and at faceoff spot
- if (puck != null)
- {
- puck.Release();
- // Wait one frame to ensure Release() completes
- StartCoroutine(ExecutePassAfterFrame(startPosition, passDirection, adjustedForce, target));
- }
- }
- else
- {
- Debug.Log($"{winner.stats.playerName} keeps the puck!");
- if (puck != null)
- {
- puck.AssignToPlayer(winner);
- }
- }
- }
- private IEnumerator ExecutePassAfterFrame(Vector3 startPosition, Vector3 direction, float force, PlayerController target)
- {
- yield return new WaitForFixedUpdate(); // Wait for physics to settle
- if (puck != null)
- {
- // Position puck at faceoff spot
- puck.transform.position = startPosition;
- // Get rigidbody and zero everything
- Rigidbody puckRb = puck.GetComponent<Rigidbody>();
- if (puckRb != null)
- {
- puckRb.linearVelocity = Vector3.zero;
- puckRb.angularVelocity = Vector3.zero;
- // Apply force in next physics frame
- yield return new WaitForFixedUpdate();
- puckRb.AddForce(direction * force, ForceMode.VelocityChange);
- Debug.Log($"Applied force: {direction * force}");
- }
- }
- // Delay assignment to let puck travel
- StartCoroutine(AssignPuckAfterDelay(target, 0.5f));
- }
- private IEnumerator AssignPuckAfterDelay(PlayerController target, float delay)
- {
- yield return new WaitForSeconds(delay);
- // Check if puck is close enough to target
- if (puck != null && target != null && puck.IsLoose)
- {
- float distance = Vector3.Distance(puck.transform.position, target.transform.position);
- if (distance < 4f) // Increased pickup range further
- {
- // Stop the puck's movement before assigning
- Rigidbody puckRb = puck.GetComponent<Rigidbody>();
- if (puckRb != null)
- {
- puckRb.linearVelocity = Vector3.zero;
- puckRb.angularVelocity = Vector3.zero;
- }
- puck.AssignToPlayer(target);
- Debug.Log($"{target.stats.playerName} received the puck!");
- }
- else
- {
- Debug.Log($"Puck too far from {target.stats.playerName} ({distance:F1}m) - Puck at {puck.transform.position}, Target at {target.transform.position}");
- }
- }
- }
- private void ExecuteStruggle()
- {
- Debug.Log("Faceoff is a struggle! Puck is loose!");
- if (puck != null)
- {
- puck.Release();
- // Launch puck in random direction
- Vector3 randomDirection = new Vector3(
- Random.Range(-1f, 1f),
- 0.1f, // Slight upward component
- Random.Range(-1f, 1f)
- ).normalized;
- puck.ApplyForce(randomDirection * struggleLaunchForce, ForceMode.Impulse);
- }
- StartCoroutine(ResolveStruggle());
- }
- private IEnumerator ResolveStruggle()
- {
- yield return new WaitForSeconds(struggleDuration * 0.5f);
- // Find closest player to puck
- PlayerController closestPlayer = null;
- float closestDistance = float.MaxValue;
- List<PlayerController> allPlayers = new List<PlayerController>();
- allPlayers.AddRange(homeTeam);
- allPlayers.AddRange(awayTeam);
- foreach (var player in allPlayers)
- {
- float distance = Vector3.Distance(player.transform.position, puck.transform.position);
- if (distance < closestDistance)
- {
- closestDistance = distance;
- closestPlayer = player;
- }
- }
- if (closestPlayer != null && closestDistance < 3f)
- {
- puck.AssignToPlayer(closestPlayer);
- Debug.Log($"{closestPlayer.stats.playerName} gains control after struggle!");
- }
- }
- private PlayerController ChoosePassTarget(PlayerController winner, List<PlayerController> team)
- {
- // Prefer defenders for breakout
- List<PlayerController> defenders = team.Where(p =>
- p != winner && (p.stats.position == PlayerPosition.LD || p.stats.position == PlayerPosition.RD)
- ).ToList();
- if (defenders.Count > 0)
- {
- // Choose closest defender
- return defenders.OrderBy(d =>
- Vector3.Distance(d.transform.position, winner.transform.position)
- ).First();
- }
- // If no defenders, choose any teammate
- List<PlayerController> availableTeammates = team.Where(p => p != winner).ToList();
- if (availableTeammates.Count > 0)
- {
- return availableTeammates[Random.Range(0, availableTeammates.Count)];
- }
- return winner;
- }
- private void FreezeAllPlayers(bool freeze)
- {
- foreach (var player in homeTeam)
- {
- if (player != null)
- {
- player.SetFrozen(freeze);
- }
- }
- foreach (var player in awayTeam)
- {
- if (player != null)
- {
- player.SetFrozen(freeze);
- }
- }
- }
- public void InitiateFaceoff(Vector3 faceoffPosition)
- {
- if (currentFaceoffSpot == null)
- {
- GameObject spot = new GameObject("FaceoffSpot");
- currentFaceoffSpot = spot.transform;
- }
- currentFaceoffSpot.position = faceoffPosition;
- StartFaceoff();
- }
- void Update()
- {
- if (Keyboard.current != null && !faceoffInProgress)
- {
- if (Keyboard.current.fKey.wasPressedThisFrame)
- {
- StartFaceoffAt(centerIceFaceoffSpot);
- }
- else if (Keyboard.current.digit1Key.wasPressedThisFrame)
- {
- StartFaceoffAt(homeZoneLeftFaceoffSpot);
- }
- else if (Keyboard.current.digit2Key.wasPressedThisFrame)
- {
- StartFaceoffAt(homeZoneRightFaceoffSpot);
- }
- else if (Keyboard.current.digit3Key.wasPressedThisFrame)
- {
- StartFaceoffAt(awayZoneLeftFaceoffSpot);
- }
- else if (Keyboard.current.digit4Key.wasPressedThisFrame)
- {
- StartFaceoffAt(awayZoneRightFaceoffSpot);
- }
- else if (Keyboard.current.digit5Key.wasPressedThisFrame)
- {
- StartFaceoffAt(homeZoneBlueLineLeftFaceoffSpot);
- }
- else if (Keyboard.current.digit6Key.wasPressedThisFrame)
- {
- StartFaceoffAt(homeZoneBlueLineRightFaceoffSpot);
- }
- else if (Keyboard.current.digit7Key.wasPressedThisFrame)
- {
- StartFaceoffAt(awayZoneBlueLineLeftFaceoffSpot);
- }
- else if (Keyboard.current.digit8Key.wasPressedThisFrame)
- {
- StartFaceoffAt(awayZoneBlueLineRightFaceoffSpot);
- }
- }
- }
- }
|