using System.Collections.Generic; using System.Linq; using Cysharp.Threading.Tasks; using Enums; using Models.Interfaces; using ScriptableObjects; using Services.Interfaces; using UnityEngine; using Utils; using Views; using Object = UnityEngine.Object; using Random = UnityEngine.Random; namespace Services { public class GameBoardService : IGameBoardService { private IGameBoard gameBoard; private GameVariables gameVariables; private IMatchService matchService; private IScoreService scoreService; private IObjectPool objectPool; private Transform gemsHolder; public GameBoardService(IGameBoard gameBoard, GameVariables gameVariables, IMatchService matchService, IScoreService scoreSerivce, IObjectPool objectPool, Transform gemsHolder) { this.gameBoard = gameBoard; this.gameVariables = gameVariables; this.matchService = matchService; this.scoreService = scoreSerivce; this.objectPool = objectPool; this.gemsHolder = gemsHolder; } public void Setup() { Debug.Log("Setting up the board"); for (int x = 0; x < this.gameBoard.Width; x++) for (int y = 0; y < this.gameBoard.Height; y++) { Vector2 position = new Vector2(x, y); GameObject backgroundTile = Object.Instantiate(this.gameVariables.bgTilePrefabs, position, Quaternion.identity); backgroundTile.transform.SetParent(this.gemsHolder); backgroundTile.name = "BG Tile - " + x + ", " + y; int gemToUse = RandomUtils.RandomGemTypeAsInt(); int iterations = 0; while (this.matchService.MatchesAt(new Vector2Int(x, y), (GemType)gemToUse) && iterations < 100) { gemToUse = RandomUtils.RandomGemTypeAsInt(); iterations++; } SpawnGem(new Vector2Int(x, y), this.gameVariables.gemsPrefabs[gemToUse], (GemType)gemToUse); } } public void SpawnGem(Vector2Int position, GemView gemPrefab, GemType gemType) { Debug.Log("Spawning gem at " + position + " with type " + gemType + ""); if (Random.Range(0, 100f) < this.gameVariables.bombChance) gemPrefab = this.gameVariables.bombPrefab; GemView gemView = this.objectPool.Get(gemType, position, this.gameVariables.dropHeight); gemView.name = "Gem - " + position.x + ", " + position.y; SetGem(new Vector2Int(position.x,position.y), new Gem(gemType, position)); } public void SetGem(Vector2Int position, Gem gem) { this.gameBoard.SetGemAt(new Vector2Int(position.x, position.y), gem); } public Gem GetGem(Vector2Int position) { return this.gameBoard.GetGemAt(position); } public void DestroyMatches() { for (int i = 0; i < this.matchService.CurrentMatches.Count; i++) if (this.matchService.CurrentMatches[i] != null) { this.scoreService.ScoreCheck(this.matchService.CurrentMatches[i].ScoreValue); DestroyMatchedGems(this.matchService.CurrentMatches[i].Position); } MoveGemsDown(); } public async UniTask MoveGemsDown() { await UniTask.Delay(2); // why the delay though? // yield return new WaitForSeconds(.2f); int nullCounter = 0; for (int x = 0; x < this.gameBoard.Width; x++) { for (int y = 0; y < this.gameBoard.Height; y++) { Gem currentGem = this.gameBoard.GetGemAt(new Vector2Int(x, y)); if (currentGem == null) { nullCounter++; } else if (nullCounter > 0) { currentGem.SetPosition(new Vector2Int(currentGem.Position.x, currentGem.Position.y - nullCounter)); SetGem(currentGem.Position, currentGem); SetGem(new Vector2Int(x,y), null); } } nullCounter = 0; } } public async UniTask FillBoard() { await UniTask.Delay(5); RefillBoard(); await UniTask.Delay(5); this.matchService.FindAllMatches(); if (this.matchService.CurrentMatches.Count > 0) { await UniTask.Delay(5); DestroyMatches(); } else { await UniTask.Delay(5); // currentState = GameState.Move; } } public void RefillBoard() { for (int x = 0; x < this.gameBoard.Width; x++) { for (int y = 0; y < this.gameBoard.Height; y++) { Gem currentGem = this.gameBoard.GetGemAt(new Vector2Int(x,y)); if (currentGem == null) { int gemToUse = RandomUtils.RandomGemTypeAsInt(); SpawnGem(new Vector2Int(x, y), this.gameVariables.gemsPrefabs[gemToUse], (GemType)gemToUse); } } } CheckMisplacedGems(); } public void CheckMisplacedGems() { List gemsViews = GemsViews(); for (int x = 0; x < this.gameBoard.Width; x++) { for (int y = 0; y < this.gameBoard.Height; y++) { Gem currentGem = this.gameBoard.GetGemAt(new Vector2Int(x,y)); GemView gemView = gemsViews.FirstOrDefault(gv => gv.Gem == currentGem); if (gemView != null) { gemsViews.Remove(gemView); } } } foreach (GemView g in gemsViews) Object.Destroy(g.gameObject); } public void DestroyMatchedGems(Vector2Int position) { List gemsViews = GemsViews(); Gem currentGem = this.gameBoard.GetGemAt(position); if (currentGem != null) { GemView gemView = gemsViews.FirstOrDefault(gv => gv.Gem == currentGem); if(this.gameVariables.destroyEffectPrefabs.Length > 0) Object.Instantiate(this.gameVariables.destroyEffectPrefabs[(int)currentGem.Type], new Vector2(position.x, position.y), Quaternion.identity); Object.Destroy(gemView!.gameObject); SetGem(position, null); } } private List GemsViews() { return this.gemsHolder.GetComponentsInChildren().ToList(); } } }