using MyCollections.Managers; using System; using System.Collections; using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.SceneManagement; using UnityEngine.Tilemaps; public class NPCManager : MonoBehaviour { [SerializeField] private List<NPCController> npcList = new List<NPCController>(); [SerializeField] private UIHandler uiHandler; [SerializeField] private DialogueManager dialogueManager; [SerializeField] private WorldUIObserver worldUIHandler; public Tilemap tilemap; public TilemapCollider2D tilemapCollider; // Attach this to the tilemap with collider private BoundsInt bounds; private List<Vector3Int> allTilePositions = new List<Vector3Int>(); [SerializeField] private List<Vector2> waypoints = new List<Vector2>(); [SerializeField] private uint waypointsNumber = 20; [SerializeField] private float warnRadius = 5f; [SerializeField] private LayerMask targetLayerMask; private CombatState combatstate; private GameStateManager gameStateManager; private Action<GameObject, NPCController> onTargetSpoted; public CombatState CombatState { get { return combatstate; } set { combatstate = value; } } //Properties public UIHandler UIhandler => uiHandler; public DialogueManager DialogueManager => dialogueManager; public WorldUIObserver WorldUIHandler => worldUIHandler; public Action<GameObject, NPCController> OnTargetSpoted => onTargetSpoted; private void Awake() { } // Start is called before the first frame update void Start() { gameStateManager = GameStateManager.Instance; foreach (NPCController npc in npcList) { npc.AddObserver(uiHandler); if (npc is InteractableNPC) { npc.AddObserver(dialogueManager); } npc.AddObserver(worldUIHandler); } onTargetSpoted += SetCombatState; GetAllTilePositions(); GenerateRandomPositions(waypointsNumber); } //When an enemy NPC detects the player it will create a combat state //If a state already exists the npc's notified by other npc's or spoted the target //Each group (NPC manager) has it's own Combat State public void SetCombatState(GameObject target, NPCController intervenient) { if (combatstate == null) { //Create a combat state if it doesn't exists one combatstate = new CombatState(target, intervenient); //Add to the manager gameStateManager.AddCombatState(combatstate); return; } //Adds the NPC to the current combat State combatstate.AddIntervenient(intervenient); } private void GetAllTilePositions() { // Get all tile positions bounds = tilemap.cellBounds; allTilePositions = new List<Vector3Int>(); for (int x = bounds.xMin; x < bounds.xMax; x++) { for (int y = bounds.yMin; y < bounds.yMax; y++) { Vector3Int tilePos = new Vector3Int(x, y, 0); if (tilemap.HasTile(tilePos)) { allTilePositions.Add(tilePos); // Add valid tile positions } } } } private void GenerateRandomPositions(uint amount) { // Get a random index from the tile positions if (allTilePositions.Count > 0) { for (int i = 0; i < amount; i++) { int randomIndex = UnityEngine.Random.Range(0, allTilePositions.Count); Vector3Int randomTilePos = allTilePositions[randomIndex]; //Debug.Log($"Random Tile Position: {randomTilePos}"); // Get the corresponding world position if needed Vector3 worldPos = tilemap.CellToWorld(randomTilePos); //Debug.Log($"World Position of Random Tile: {worldPos}"); waypoints.Add(worldPos); } } else { Debug.LogWarning("No tiles found in the tilemap!"); } } // Update is called once per frame void Update() { } public void RequestPosition(Agent agent) { int randomIndex = UnityEngine.Random.Range(0, waypoints.Count); Vector2 newPosition = waypoints[randomIndex]; agent.SetDestination(newPosition); } private void OnEnable() { foreach (NPCController npc in npcList) { npc.gameObject.SetActive(true); } } private IEnumerator ActivateNPCsAfterDelay() { // Wait until 1 second has passed since the level loaded while (Time.timeSinceLevelLoad < 5f) { yield return null; // Wait for the next frame } // Once 1 second has passed, activate the NPCs foreach (NPCController npc in npcList) { npc.gameObject.SetActive(true); } } void OnDisable() { foreach (NPCController npc in npcList) { npc.gameObject.SetActive(false); } } }