using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Threading.Tasks; using UnityEngine; public class PositionHandler : MonoBehaviour { public static PositionHandler Instance { get; private set; } [Header("Positions")] [SerializeField] private List<Transform> player_Loc; // Reference to the transforms that the players can be located at [SerializeField] private List<Transform> enemy_Locs; // Reference to the transforms that the enemies can be located at [SerializeField] private List<Transform> member_Locs; // Reference to the transforms that the members can be located at [SerializeField] private Transform leftAllLocation; [SerializeField] private Transform rightAllLocation; [SerializeField] private Transform topOfScreenPosition; [SerializeField] private Transform bottomOfScreenPosition; [SerializeField] private Transform centerOfScreenPosition; [Header("Spawning Materials")] [SerializeField] private Material bossSpawnMaterial; [SerializeField] private AudioClip bossSpawnSFX; private void Awake() { Instance = this; } /// <summary> /// Spawns the player game object within the player position from the handler /// </summary> /// <param name="player">Player game object</param> /// <returns>The spawned game object reference</returns> public GameObject PositionPlayer(GameObject player) { GameObject playerInstance = Instantiate(player, player_Loc.First(), false); playerInstance.GetComponent<Player>().DeactivateVisually(); return playerInstance; } public GameObject[] PositionAlly(GameObject[] allies) { if (allies is null) return null; int counter = 0; foreach (GameObject ally in allies) { if (ally == null) continue; else ++counter; } GameObject[] spawnedAllies = new GameObject[counter]; for (int i = 0; i < counter; i++) { spawnedAllies[i] = Instantiate(allies[i], member_Locs[i], false); spawnedAllies[i].GetComponentInChildren<SpriteRenderer>().sortingOrder = i + 1; spawnedAllies[i].GetComponent<Ally>().DeactivateVisually(); } List<GameObject> allyGUIs = GeneralUI.Instance.GetAllyIconGUIs(); for (int i = 0; i < allyGUIs.Count; i++) { string allyGuiName = allyGUIs[i].GetComponent<PartyMemberGUI>().GetAllyInfo().GetName(); foreach (GameObject spawnedAlly in spawnedAllies) { if (allyGuiName.Equals(spawnedAlly.GetComponent<Ally>().GetName())) { spawnedAlly.GetComponent<Ally>().InjectGUI(allyGUIs[i].GetComponent<PartyMemberGUI>()); break; } } } return spawnedAllies; } public void ShowAndRaisePlayerObject(GameObject playerObject) { if (playerObject.transform.parent != player_Loc[0]) { playerObject.transform.SetParent(player_Loc[0]); playerObject.transform.localPosition = Vector3.zero; } // Re-enable sprite functionality playerObject.GetComponent<Player>().ReactivateVisually(); // Raise to 1 and drop playerObject.transform.position = new Vector3(playerObject.transform.position.x, playerObject.transform.position.y + 1f, playerObject.transform.position.z); playerObject.GetComponent<Target>().ReactivateDrop(); } public void ShowAndRaiseAllyObjects(GameObject[] allyObjects) { int posCounter = 0; foreach (GameObject allyObject in allyObjects) { if (allyObject.transform.parent != member_Locs[posCounter]) { allyObject.transform.SetParent(member_Locs[posCounter]); allyObject.transform.localPosition = Vector3.zero; } // Re-enable sprite functionality allyObject.GetComponent<Ally>().ReactivateVisually(); // Raise to 1 and drop allyObject.transform.position = new Vector3(allyObject.transform.position.x, allyObject.transform.position.y + 1f, allyObject.transform.position.z); allyObject.GetComponent<Target>().ReactivateDrop(); posCounter++; } } /// <summary> /// Positions the enemy sprites into the locations set within the field /// </summary> /// <param name="enemies">The enemy game objects to set within the field</param> /// <returns>The enemy components from the game objects</returns> public (GameObject[], Enemy[]) PositionEnemies(GameObject[] enemies, BattleHandler bh, bool isBoss) { GameObject[] enemyObjects = new GameObject[enemies.Length]; int positionCounter = 0; for (int i = 0; i < enemies.Length; i++) { if (isBoss) { enemyObjects[0] = SpawnBoss(enemies[0]).GetAwaiter().GetResult(); break; } // Put space between legendary enemies if available if (enemies[i].GetComponent<Enemy>().GetEnemyDifficulty() is Enemy.DifficultyRating.Legendary && positionCounter < 4) { positionCounter++; enemyObjects[i] = Instantiate(enemies[i], enemy_Locs[positionCounter++], false); } else enemyObjects[i] = Instantiate(enemies[i], enemy_Locs[positionCounter++], false); } Enemy[] compColl = new Enemy[enemyObjects.Length]; for (int i = 0; i < compColl.Length; i++) { compColl[i] = enemyObjects[i].GetComponent<Enemy>(); compColl[i].InjectHandler(bh); } return (enemyObjects, compColl); } public async Task<GameObject> SpawnBoss(GameObject boss) { GameObject bossObject = Instantiate(boss, enemy_Locs[1], false); bossObject.GetComponentInChildren<SpriteRenderer>().material = bossSpawnMaterial; Color bossColor = bossObject.GetComponentInChildren<SpriteRenderer>().color; // Spawn higher with 4 extra units up in the Y Vector3 bossPosition = bossObject.transform.position; bossObject.transform.position = new Vector3(bossPosition.x, bossPosition.y + 4f, bossPosition.z); // Transparent color and a material that shows energy forming around the entity StartCoroutine(WhitenBoss(bossColor)); bossObject.transform.GetChild(bossObject.transform.childCount - 1).GetChild(0).gameObject.SetActive(true); Transform subParticleObject = bossObject.transform.GetChild(bossObject.transform.childCount - 1).GetChild(0); // Wait for the energy to coalesce around the boss before triggering a large shockwave and coloring the boss await Task.Delay(3000); subParticleObject.GetComponent<ParticleSystem>().TriggerSubEmitter(0); SoundManager.Instance.PlaySoundFX(bossSpawnSFX); bossObject.GetComponent<Rigidbody2D>().bodyType = RigidbodyType2D.Dynamic; await bossObject.GetComponent<Boss>().PlayEncounterEffect(); return bossObject; } private IEnumerator WhitenBoss(Color bossColor) { while (bossColor.a < 1f) { bossColor = new Color(bossColor.r, bossColor.g, bossColor.b, bossColor.a + (.1f * Time.deltaTime)); yield return null; } yield return null; } /// <summary> /// Creates a temporary minion for either the left or right side /// </summary> /// <param name="minion">The object to instantiate</param> /// <param name="isLeft">If true then it will be added to allies, otherwise add to enemies</param> public GameObject InjectMinion(GameObject minion, bool isLeft) { GameObject createdMinion = null; if (isLeft) { for (int i = 0; i < member_Locs.Count; i++) { if (member_Locs[i].childCount is 0) { createdMinion = Instantiate(minion, member_Locs[i]); break; } } } else { for (int i = 0; i < enemy_Locs.Count; i++) { if (enemy_Locs[i].childCount is 0) { createdMinion = Instantiate(minion, enemy_Locs[i]); break; } else if (!enemy_Locs[i].GetChild(0).TryGetComponent(out Enemy _)) { // If false, means an effect object is present so just put the enemy here createdMinion = Instantiate(minion, enemy_Locs[i]); break; } } } return createdMinion; } public int GatherLocationCount(int transformCountIndicator, bool wasEnemyCast) { return transformCountIndicator switch { 5 => wasEnemyCast ? GatherLocationCount(6, wasEnemyCast) : GatherLocationCount(8, wasEnemyCast), 6 => enemy_Locs.Where(enemy => enemy.childCount is not 0 && enemy.GetComponent<Enemy>().HasDied is false).Count(), 8 => (player_Loc[0].childCount is not 0 && player_Loc[0].GetComponent<Player>().HasDied is false ? 1 : 0) + member_Locs.Where(companion => companion.childCount is not 0 && companion.GetComponent<Ally>().HasDied is false).Count(), _ => 1, }; } public Transform[] GatherLocation(SpellVisualEffects.EffectLocation effectLocation, int castingLocation, int targetLocation, bool wasEnemyCast, bool isTargettingSameSide) { switch (effectLocation) { case SpellVisualEffects.EffectLocation.SelfLocation: Transform[] selfLocation = new Transform[1]; selfLocation[0] = wasEnemyCast ? enemy_Locs[castingLocation] : (castingLocation is 0 ? player_Loc[castingLocation] : member_Locs[castingLocation - 1]); return selfLocation; case SpellVisualEffects.EffectLocation.TargettedLocation: Transform[] targettedLocation = new Transform[1]; if (!isTargettingSameSide) targettedLocation[0] = wasEnemyCast ? (targetLocation is 0 ? player_Loc[targetLocation] : member_Locs[targetLocation - 1]) : enemy_Locs[targetLocation]; else targettedLocation[0] = wasEnemyCast ? enemy_Locs[targetLocation] : (targetLocation is 0 ? player_Loc[targetLocation] : member_Locs[targetLocation - 1]); return targettedLocation; case SpellVisualEffects.EffectLocation.TravelSelfToTarget: Transform[] selfToTarget = new Transform[1]; selfToTarget[0] = wasEnemyCast ? enemy_Locs[castingLocation] : (castingLocation is 0 ? player_Loc[castingLocation] : member_Locs[castingLocation - 1]); return selfToTarget; case SpellVisualEffects.EffectLocation.TravelTargetToSelf: Transform[] targetToSelf = new Transform[1]; targetToSelf[0] = wasEnemyCast ? (targetLocation is 0 ? player_Loc[targetLocation] : member_Locs[targetLocation - 1]) : enemy_Locs[targetLocation]; return targetToSelf; case SpellVisualEffects.EffectLocation.AllSide: Transform[] allSideTransform = new Transform[1]; allSideTransform[0] = wasEnemyCast ? leftAllLocation : rightAllLocation; return allSideTransform; case SpellVisualEffects.EffectLocation.AllSideEachLocation: if (wasEnemyCast) return GatherLocation(SpellVisualEffects.EffectLocation.AllLeftLocations, castingLocation, targetLocation, wasEnemyCast, isTargettingSameSide); else return GatherLocation(SpellVisualEffects.EffectLocation.AllRightLocations, castingLocation, targetLocation, wasEnemyCast, isTargettingSameSide); case SpellVisualEffects.EffectLocation.AllRightLocations: return enemy_Locs.Where(enemyPos => enemyPos.childCount is not 0 && enemyPos.GetComponent<Enemy>().HasDied is false).ToArray(); case SpellVisualEffects.EffectLocation.AllRightCenter: Transform[] allRightCenter = new Transform[1]; allRightCenter[0] = rightAllLocation; return allRightCenter; case SpellVisualEffects.EffectLocation.AllLeftLocations: return member_Locs.Where(memberPos => memberPos.childCount is not 0 && memberPos.GetComponent<Ally>().HasDied is false) .Concat(player_Loc.Where(playerPos => playerPos.childCount is not 0 && playerPos.GetComponent<Player>().HasDied is false)).ToArray(); case SpellVisualEffects.EffectLocation.AllLeftCenter: Transform[] allLeftCenter = new Transform[1]; allLeftCenter[0] = leftAllLocation; return allLeftCenter; case SpellVisualEffects.EffectLocation.TopOfScreen: Transform[] topScreen = new Transform[1]; topScreen[0] = topOfScreenPosition; return topScreen; case SpellVisualEffects.EffectLocation.CenterOfScreen: Transform[] centerScreen = new Transform[1]; centerScreen[0] = centerOfScreenPosition; return centerScreen; case SpellVisualEffects.EffectLocation.BottomOfScreen: Transform[] bottomScreen = new Transform[1]; bottomScreen[0] = bottomOfScreenPosition; return bottomScreen; default: throw new InvalidEnumArgumentException(); } } public int GetEntityPositionIndex(Entity entity) { if (entity is Player) return 0; else if (entity is Ally) { int index = 1; foreach (Transform memberLocation in member_Locs) { if (memberLocation.childCount > 0) { if (memberLocation.GetChild(0).GetComponent<Ally>().GetUniqueID() == entity.GetUniqueID()) return index; else index++; } } } else { int index = 0; foreach (Transform enemyLocation in enemy_Locs) { if (enemyLocation.childCount > 0) { if (enemyLocation.GetChild(0).GetComponent<Enemy>().GetUniqueID() == entity.GetUniqueID()) return index; } else index++; } } return -1; } public int GetEmptyPosition(Entity spellUser) { if (spellUser is Ally || spellUser is Player) { if (member_Locs[0].childCount is 0) return 1; else if (member_Locs[1].childCount is 0) return 2; else if (member_Locs[2].childCount is 0) return 3; } else { if (enemy_Locs[0].childCount is 0) return 0; else if (enemy_Locs[1].childCount is 0) return 1; else if (enemy_Locs[2].childCount is 0) return 2; else if (enemy_Locs[3].childCount is 0) return 3; } return -1; } }