using System; using System.Collections.Generic; using UnityEngine; namespace DoomBreakers { public class BattleColliderManager : MonoBehaviour { // //The battle collider manager' purpose is too communicate collisions between enemy AI & player, vice versa. //We will need to communicate some details about each object involved with the collision. // // private Dictionary _battleEventDictionary; private static BattleColliderManager _battleEventManager; private static int _mostRecentCollidedPlayerId; private static Dictionary _playerFaceDir; private static Dictionary _playerState; private static Dictionary _playerWeapon; private static Dictionary _playerStats; private static float _playerAttackButtonHeldTime; private static int _mostRecentCollidedBasicEnemyId; //Needed for Enemy Hit By Power Attack behaviour state. private static Dictionary _enemyFaceDir; private static Dictionary _basicEnemyState; private static Dictionary _basicBanditStats; private static Dictionary _basicSkellyStats; private static Dictionary _basicGoblinStats; private static Dictionary _basicTrollStats; public static BattleColliderManager _instance { get //When we access our instance from another place, we'll setup as appropriate if required. { if (!_battleEventManager) { //FindObjectOfType isn't a cheap call but we only do this once, if not at all. _battleEventManager = FindObjectOfType(typeof(BattleColliderManager)) as BattleColliderManager; if (!_battleEventManager) print("\nBattleColliderManager= You need an active BattleColliderManager script attached to a GameObject within the scene!"); else _battleEventManager.Setup(); } return _battleEventManager; } } private void Setup() { if (_battleEventDictionary == null) _battleEventDictionary = new Dictionary(); if (_playerFaceDir == null) _playerFaceDir = new Dictionary(); if (_playerState == null) _playerState = new Dictionary(); if (_playerWeapon == null) _playerWeapon = new Dictionary(); if (_playerStats == null) _playerStats = new Dictionary(); if (_enemyFaceDir == null) _enemyFaceDir = new Dictionary(); if (_basicEnemyState == null) _basicEnemyState = new Dictionary(); if (_basicBanditStats == null) _basicBanditStats = new Dictionary(); if (_basicSkellyStats == null) _basicSkellyStats = new Dictionary(); if (_basicGoblinStats == null) _basicGoblinStats = new Dictionary(); if (_basicTrollStats == null) _basicTrollStats = new Dictionary(); _mostRecentCollidedPlayerId = 0; _playerAttackButtonHeldTime = 0f; //_enemyType = EnemyAI.None; } private void OnDisable() => FreeMemory(); public void FreeMemory() { //Alerts GC to collect and free up memory. _battleEventDictionary.Clear(); _playerFaceDir.Clear(); _playerState.Clear(); _playerWeapon.Clear(); _playerStats.Clear(); _enemyFaceDir.Clear(); _basicEnemyState.Clear(); _basicBanditStats.Clear(); _basicSkellyStats.Clear(); _basicGoblinStats.Clear(); _basicTrollStats.Clear(); _battleEventManager = null; } // //Bundle all appropriate collision assignment calls into one method call. //This is so far, AssignPlayerState(), AssignPlayerFaceDir() and TriggerEvent("ReportCollisionWithSomething"). // // public static void AssignCollisionDetails(string eventName, ref BaseState playerState, int forPlayerId, IPlayerSprite playerSprite, ItemBase weapon, ref PlayerStats characterStat) { AssignPlayerFaceDir(forPlayerId, playerSprite); AssignPlayerState(ref playerState, forPlayerId); AssignPlayerWeapon(forPlayerId, weapon); AssignPlayerStats(forPlayerId, ref characterStat); BaseTriggerEvent(eventName); } // //AssignPlayerState() is used to communicate player state during an attack. //We will need this for enemy AI regarding the Bandit.cs->AttackedByPlayer() so //we can determine the enemy' next state, as appropriate. // // public static void AssignPlayerState(ref BaseState playerState, int playerId) { if (!_playerState.ContainsKey(playerId)) _playerState.Add(playerId, playerState); else { if(playerState.GetType() != _playerState[playerId].GetType()) { _playerState.Remove(playerId); _playerState.Add(playerId, playerState); } } } public static BaseState GetAssignedPlayerState(int playerId) //=> _playerState[playerId]; { if (!_playerState.ContainsKey(playerId)) return null; return _playerState[playerId]; } // //AssignPlayerFaceDir() is used to communicate player face direction during an attack. //We will need this for enemy AI regarding the HitByPowerAttack obj state. // // public static void AssignPlayerFaceDir(int forPlayerId, IPlayerSprite playerSprite) { //PlayerCollision.cs->UpdateDetectEnemyTargets() _mostRecentCollidedPlayerId = forPlayerId; if (!_playerFaceDir.ContainsKey(forPlayerId)) _playerFaceDir.Add(forPlayerId, playerSprite.GetSpriteDirection()); else { if (_playerFaceDir[forPlayerId] != playerSprite.GetSpriteDirection()) { _playerFaceDir.Remove(forPlayerId); _playerFaceDir.Add(forPlayerId, playerSprite.GetSpriteDirection());//There we go dumbass. } } } public static int GetAssignedPlayerFaceDir(int forPlayerId) { if (_playerFaceDir.ContainsKey(forPlayerId)) return _playerFaceDir[forPlayerId]; else return 1; } // //AssignPlayerWeapon() is used to communicate player damage output during an attack. //We will need this for enemy AI regarding the Bandit.cs->AttackedByPlayer() Method. //But will use this Method at PlayerCollision.cs->UpdateDetectEnemyTargets() // public static void AssignPlayerWeapon(int forPlayerId, ItemBase weapon) { if (weapon == null) return; if(!_playerWeapon.ContainsKey(forPlayerId)) _playerWeapon.Add(forPlayerId, weapon); else { if (_playerWeapon[forPlayerId] != weapon) { _playerWeapon.Remove(forPlayerId); _playerWeapon.Add(forPlayerId, weapon); } } } public static ItemBase GetAssignedPlayerWeapon(int forPlayerId) { if (_playerWeapon == null) return null; if (_playerWeapon.ContainsKey(forPlayerId)) return _playerWeapon[forPlayerId]; else return null; } public static void AssignPlayerStats(int forPlayerId, ref PlayerStats characterStat) { _mostRecentCollidedBasicEnemyId = forPlayerId; if (!_playerStats.ContainsKey(forPlayerId)) _playerStats.Add(forPlayerId, characterStat); else { if (_playerStats[forPlayerId] != characterStat) { _playerStats.Remove(forPlayerId); _playerStats.Add(forPlayerId, characterStat); } } } public static int GetRecentCollidedPlayerId() => _mostRecentCollidedPlayerId; public static PlayerStats GetAssignedPlayerStatus(int forPlayerId)// => _playerStats[forPlayerId]; { if (!_playerStats.ContainsKey(forPlayerId)) return null; return _playerStats[forPlayerId]; } public static void SetPlayerHeldAttackButtonTime(float time) => _playerAttackButtonHeldTime = time; public static float GetPlayerHeldAttackButtonTime() => _playerAttackButtonHeldTime; // //Bundle all appropriate collision assignment calls into one method call. //This is so far, AssignBanditState(), AssignBanditFaceDir() and TriggerEvent("ReportCollisionWithSomething"). //We'll overload this from Player use for Bandit use. // public static void AssignCollisionDetails(string eventName, ref BasicEnemyBaseState banditState, int forBanditId, int faceDir, ref BanditStats characterStat) { AssignBasicEnemyFaceDir(forBanditId, faceDir); AssignBasicEnemyState(ref banditState, forBanditId); AssignBasicEnemyStats(forBanditId, ref characterStat); BaseTriggerEvent(eventName); } public static void AssignCollisionDetails(string eventName, ref BasicEnemyBaseState skellyState, int forSkellyId, int faceDir, ref SkeletonStats characterStat) { AssignBasicEnemyFaceDir(forSkellyId, faceDir); AssignBasicEnemyState(ref skellyState, forSkellyId); AssignBasicEnemyStats(forSkellyId, ref characterStat); BaseTriggerEvent(eventName); } public static void AssignCollisionDetails(string eventName, ref BasicEnemyBaseState goblinState, int forGoblinId, int faceDir, ref GoblinStats characterStat) { AssignBasicEnemyFaceDir(forGoblinId, faceDir); AssignBasicEnemyState(ref goblinState, forGoblinId); AssignBasicEnemyStats(forGoblinId, ref characterStat); BaseTriggerEvent(eventName); } public static void AssignCollisionDetails(string eventName, ref BasicEnemyBaseState trollState, int forTrollId, int faceDir, ref TrollStats characterStat) { AssignBasicEnemyFaceDir(forTrollId, faceDir); AssignBasicEnemyState(ref trollState, forTrollId); AssignBasicEnemyStats(forTrollId, ref characterStat); BaseTriggerEvent(eventName); } public static void AssignBasicEnemyState(ref BasicEnemyBaseState banditState, int enemyId) { if (!_basicEnemyState.ContainsKey(enemyId)) _basicEnemyState.Add(enemyId, banditState); else { if (banditState.GetType() != _basicEnemyState[enemyId].GetType()) { _basicEnemyState.Remove(enemyId); _basicEnemyState.Add(enemyId, banditState); } } } public static BasicEnemyBaseState GetAssignedBasicEnemyState(int enemyId) //=> _basicEnemyState[enemyId]; { if (!_basicEnemyState.ContainsKey(enemyId)) return null; return _basicEnemyState[enemyId]; } public static void AssignBasicEnemyFaceDir(int forEnemyId, int faceDir) { //BanditCollision.cs->UpdateDetectEnemyTargets() _mostRecentCollidedBasicEnemyId = forEnemyId; if (!_enemyFaceDir.ContainsKey(forEnemyId)) _enemyFaceDir.Add(forEnemyId, faceDir); else { if (_enemyFaceDir[forEnemyId] != faceDir) { _enemyFaceDir.Remove(forEnemyId); _enemyFaceDir.Add(forEnemyId, faceDir); } } } public static void AssignBasicEnemyStats(int forBanditId, ref BanditStats characterStat) { _mostRecentCollidedBasicEnemyId = forBanditId; if (!_basicBanditStats.ContainsKey(forBanditId)) _basicBanditStats.Add(forBanditId, characterStat); else { if (_basicBanditStats[forBanditId] != characterStat) { _basicBanditStats.Remove(forBanditId); _basicBanditStats.Add(forBanditId, characterStat); } } } public static void AssignBasicEnemyStats(int forSkellyId, ref SkeletonStats characterStat) { _mostRecentCollidedBasicEnemyId = forSkellyId; if (!_basicSkellyStats.ContainsKey(forSkellyId)) _basicSkellyStats.Add(forSkellyId, characterStat); else { if (_basicSkellyStats[forSkellyId] != characterStat) { _basicSkellyStats.Remove(forSkellyId); _basicSkellyStats.Add(forSkellyId, characterStat); } } } public static void AssignBasicEnemyStats(int forGoblinId, ref GoblinStats characterStat) { _mostRecentCollidedBasicEnemyId = forGoblinId; if (!_basicGoblinStats.ContainsKey(forGoblinId)) _basicGoblinStats.Add(forGoblinId, characterStat); else { if (_basicGoblinStats[forGoblinId] != characterStat) { _basicGoblinStats.Remove(forGoblinId); _basicGoblinStats.Add(forGoblinId, characterStat); } } } public static void AssignBasicEnemyStats(int forTrollId, ref TrollStats characterStat) { _mostRecentCollidedBasicEnemyId = forTrollId; if (!_basicTrollStats.ContainsKey(forTrollId)) _basicTrollStats.Add(forTrollId, characterStat); else { if (_basicTrollStats[forTrollId] != characterStat) { _basicTrollStats.Remove(forTrollId); _basicTrollStats.Add(forTrollId, characterStat); } } } public static int GetAssigneBasicEnemyFaceDir(int forEnemyId) => _enemyFaceDir[forEnemyId]; public static BanditStats GetAssignedBanditStatus(int forBanditId) //=> _basicBanditStats[forBanditId]; { if (!_basicBanditStats.ContainsKey(forBanditId)) return null; return _basicBanditStats[forBanditId]; } public static int GetRecentCollidedBasicEnemyId() => _mostRecentCollidedBasicEnemyId; public static SkeletonStats GetAssignedSkeletonStatus(int forSkellyId) //=> _basicBanditStats[forBanditId]; { if (!_basicSkellyStats.ContainsKey(forSkellyId)) return null; return _basicSkellyStats[forSkellyId]; } public static GoblinStats GetAssignedGoblinStatus(int forGoblinId) //=> _basicBanditStats[forBanditId]; { if (!_basicGoblinStats.ContainsKey(forGoblinId)) return null; return _basicGoblinStats[forGoblinId]; } public static TrollStats GetAssignedTrollStatus(int forTrollId) //=> _basicBanditStats[forBanditId]; { if (!_basicTrollStats.ContainsKey(forTrollId)) return null; return _basicTrollStats[forTrollId]; } public static void Subscribe(string eventName, Action listener) { Action thisEvent; //out: differs from the ref keyword in that it does not require parameter variables to be //initialized before they are passed to a method. Must be explicitly declared in the method //definition​ as well as in the calling method. if (_instance._battleEventDictionary.TryGetValue(eventName, out thisEvent)) { //Add another event to the existing ones. thisEvent += listener; //Update the dictionary. _instance._battleEventDictionary[eventName] = thisEvent; } else { //Add the event to the dictionary for the first time. thisEvent += listener; _instance._battleEventDictionary.Add(eventName, thisEvent); } } public static void Unsubscribe(string eventName, Action listener) { if (_battleEventManager == null) //Guard Clause. return; Action thisEvent; if (_instance._battleEventDictionary.TryGetValue(eventName, out thisEvent)) { //Remove the event from the existing ones. thisEvent -= listener; //Now update the dictionary. _instance._battleEventDictionary[eventName] = thisEvent; } } private static void BaseTriggerEvent(string eventName) { Action thisEvent = null; if (_instance._battleEventDictionary.TryGetValue(eventName, out thisEvent)) { _instance._battleEventDictionary[eventName](); //thisEvent.Invoke(); } } public static void TriggerEvent(string eventName) { BaseTriggerEvent(eventName); } } }