From 2a3bcf7423d8a29be6ac0edc1baa7dffbd655327 Mon Sep 17 00:00:00 2001 From: Jesus Castro Date: Mon, 15 Dec 2025 03:44:53 +0800 Subject: [PATCH] Cleanup --- Assets/GameVariables.asset | 11 +- Assets/Scripts/Models/Gem.cs | 11 +- Assets/Scripts/Presenter/GemPresenter.cs | 4 +- Assets/Scripts/Presenter/ScorePresenter.cs | 4 +- .../ScriptableObjects/GameVariables.cs | 11 +- Assets/Scripts/Services/GameBoardService.cs | 181 +++++++++++++++--- .../Services/Interfaces/IMatchService.cs | 5 +- Assets/Scripts/Services/MatchService.cs | 181 ++++++++++++------ Assets/Scripts/Structs/BombSpawnRequest.cs | 14 ++ .../Scripts/Structs/BombSpawnRequest.cs.meta | 3 + Assets/Scripts/Views/GemView.cs | 4 +- Assets/Scripts/Views/ScoreView.cs | 4 +- 12 files changed, 326 insertions(+), 107 deletions(-) create mode 100644 Assets/Scripts/Structs/BombSpawnRequest.cs create mode 100644 Assets/Scripts/Structs/BombSpawnRequest.cs.meta diff --git a/Assets/GameVariables.asset b/Assets/GameVariables.asset index 98fbe4b..d007be0 100644 --- a/Assets/GameVariables.asset +++ b/Assets/GameVariables.asset @@ -51,12 +51,11 @@ MonoBehaviour: explosionPrefab: {fileID: 8968486364681163996, guid: 05c754e3d4f9fd349ac1def58d17670f, type: 3} scoreValue: 10 - bonusAmount: 0.5 - bombChance: 2 + bombDelay: 0.75 + bombSelfDelay: 0.25 + bombRadius: 2 dropHeight: 1 - gemSpeed: 7 - scoreSpeed: 5 + gemSpeed: 0.05 + scoreSpeed: 1 width: 7 height: 7 - rowsSize: 7 - colsSize: 7 diff --git a/Assets/Scripts/Models/Gem.cs b/Assets/Scripts/Models/Gem.cs index 7d6788b..3fa3366 100644 --- a/Assets/Scripts/Models/Gem.cs +++ b/Assets/Scripts/Models/Gem.cs @@ -5,19 +5,22 @@ namespace Services { public class Gem { private GemType type; private Vector2Int position; - public GemType Type => this.type; public Vector2Int Position => this.position; private int scoreValue; public int ScoreValue => this.scoreValue; - - public bool isMatch = false; - public Gem(GemType type, Vector2Int position, int scoreValue) { + private GemType colorType; + + public GemType MatchColor => this.type == GemType.Bomb ? this.colorType : this.type; + + public Gem(GemType type, Vector2Int position, int scoreValue, GemType? colorType = null) { this.type = type; this.position = position; this.scoreValue = scoreValue; + + this.colorType = colorType ?? type; } public void SetPosition(Vector2Int position) { diff --git a/Assets/Scripts/Presenter/GemPresenter.cs b/Assets/Scripts/Presenter/GemPresenter.cs index 3a192dd..7205a6f 100644 --- a/Assets/Scripts/Presenter/GemPresenter.cs +++ b/Assets/Scripts/Presenter/GemPresenter.cs @@ -17,13 +17,13 @@ namespace Presenter { this.gemView = gemView; } - public void Tick() { + public void Tick(float gemSpeed) { if (this.gemView == null) { return; } if (!this.gem.Position.Compare(this.gemView.transform.localPosition)) { - this.gemView.UpdatePosition(this.gem.Position); + this.gemView.UpdatePosition(this.gem.Position, gemSpeed); } } } diff --git a/Assets/Scripts/Presenter/ScorePresenter.cs b/Assets/Scripts/Presenter/ScorePresenter.cs index 579c5bf..2581acd 100644 --- a/Assets/Scripts/Presenter/ScorePresenter.cs +++ b/Assets/Scripts/Presenter/ScorePresenter.cs @@ -15,8 +15,8 @@ namespace Presenter { this.scoreView.SetScore(this.scoreService.Score); } - public void Tick() { - this.scoreView.UpdateScore(); + public void Tick(float scoreSpeed) { + this.scoreView.UpdateScore(scoreSpeed); } private void OnScoreChanged(int score) { diff --git a/Assets/Scripts/ScriptableObjects/GameVariables.cs b/Assets/Scripts/ScriptableObjects/GameVariables.cs index b0bf637..ba4e70b 100644 --- a/Assets/Scripts/ScriptableObjects/GameVariables.cs +++ b/Assets/Scripts/ScriptableObjects/GameVariables.cs @@ -5,23 +5,18 @@ using Structs; using UnityEngine; using Views; -//Done, moved to GameVariables scriptable object namespace ScriptableObjects { [CreateAssetMenu(fileName = "GameVariables", menuName = "Game Variables")] public class GameVariables : ScriptableObject { public GameObject bgTilePrefabs; public GemTypeValues[] gemsPrefabs; - public float bonusAmount = 0.5f; - public float bombChance = 2f; + public float bombDelay = 0.1f; + public float bombSelfDelay = 0.05f; + public int bombRadius = 1; public int dropHeight = 1; public float gemSpeed = 0.1f; public float scoreSpeed = 5; public int width; public int height; - - [HideInInspector] - public int rowsSize = 7; - [HideInInspector] - public int colsSize = 7; } } \ No newline at end of file diff --git a/Assets/Scripts/Services/GameBoardService.cs b/Assets/Scripts/Services/GameBoardService.cs index e3e34e8..4043038 100644 --- a/Assets/Scripts/Services/GameBoardService.cs +++ b/Assets/Scripts/Services/GameBoardService.cs @@ -7,6 +7,7 @@ using Models.Interfaces; using Presenter; using ScriptableObjects; using Services.Interfaces; +using Structs; using UnityEngine; using Utils; using VContainer.Unity; @@ -43,10 +44,10 @@ namespace Services { public void Tick() { foreach (GemPresenter gemPresenter in gemPresenters) { - gemPresenter.Tick(); + gemPresenter.Tick(this.gameVariables.gemSpeed); } - this.scorePresenter.Tick(); + this.scorePresenter.Tick(this.gameVariables.scoreSpeed); } //Instantiates background tiles and calls SpawnGems @@ -77,16 +78,32 @@ namespace Services { //Uses the ObjectPool to spawn a gem at the given position private void SpawnGem(Vector2Int position, GemType gemType) { - if (Random.Range(0, 100f) < this.gameVariables.bombChance) - gemType = GemType.Bomb; - GemView gemView = this.objectPool.Get(gemType, position, this.gameVariables.dropHeight); gemView.name = "Gem - " + position.x + ", " + position.y + ' ' + gemType; - Gem gem = new Gem(gemType, position, 50); + + // If we randomly spawned a bomb, give it a random color group (so it can match by color). + int scoreValue = GemUtils.GetGemValues(gemType, this.gameVariables.gemsPrefabs).scoreValue; + Gem gem = new Gem(gemType, position, scoreValue); + gemView.Bind(gem); - + this.gemPresenters.Add(new GemPresenter(gem, gemView)); - SetGem(new Vector2Int(position.x,position.y), gem); + SetGem(new Vector2Int(position.x, position.y), gem); + } + + private void SpawnBomb(Vector2Int position, GemType color) { + // remove existing gem/view at that position + DestroyMatchedGems(position); + + GemView gemView = this.objectPool.Get(GemType.Bomb, position, this.gameVariables.dropHeight); + gemView.name = "Gem - " + position.x + ", " + position.y + ' ' + GemType.Bomb; + + int scoreValue = GemUtils.GetGemValues(color, this.gameVariables.gemsPrefabs).scoreValue; + Gem bombGem = new Gem(GemType.Bomb, position, scoreValue, color); + gemView.Bind(bombGem); + + this.gemPresenters.Add(new GemPresenter(bombGem, gemView)); + SetGem(position, bombGem); } //Sets the gem on the GameBoard @@ -121,7 +138,7 @@ namespace Services { ApplySwap(from, to, fromGem, toGem); await UniTask.Delay(600); - + this.matchService.SetLastSwap(from, to); this.matchService.FindAllMatches(); bool hasMatch = this.matchService.CurrentMatches.Count > 0; @@ -131,8 +148,10 @@ namespace Services { this.currentState = GameState.Move; return false; } + + List protectedPositions = ApplyPendingBombSpawns(); - DestroyMatches(); + await DestroyMatchesAsync(protectedPositions); this.currentState = GameState.Move; return true; } @@ -146,17 +165,131 @@ namespace Services { SetGem(posA, gemB); SetGem(posB, gemA); } + + private List ApplyPendingBombSpawns() { + List positions = new List(); - //If there are matches, destroys them and moves the gems down - private 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); + foreach (BombSpawnRequest bomSpawnRequest in this.matchService.PendingBombSpawns) { + positions.Add(bomSpawnRequest.Position); + SpawnBomb(bomSpawnRequest.Position, bomSpawnRequest.Color); + } + + this.matchService.ClearPendingBombs(); + return positions; + } + + private async UniTask DestroyMatchesAsync(List protectedPositions) { + // Build initial queues from current matches + Queue bombsToProcess = new Queue(); + List processedBombs = new List(); + List regularToDestroy = new List(); + + for (int i = 0; i < this.matchService.CurrentMatches.Count; i++) { + Gem matchedGem = this.matchService.CurrentMatches[i]; + if (matchedGem == null) + continue; + + Vector2Int pos = matchedGem.Position; + + // If a bomb was spawned at this cell due to 4+ creation, it must survive this destruction pass. + if (protectedPositions != null && protectedPositions.Contains(pos)) + continue; + + Gem current = GetGem(pos); + if (current == null) + continue; + + if (current.Type == GemType.Bomb) { + bombsToProcess.Enqueue(pos); + } else { + regularToDestroy.Add(pos); + } + } + + // Process bombs: neighbors first (after delay), then the bomb itself (after delay). + while (bombsToProcess.Count > 0) { + Vector2Int bombPos = bombsToProcess.Dequeue(); + if (processedBombs.Contains(bombPos)) + continue; + + Gem bomb = GetGem(bombPos); + if (bomb is not { Type: GemType.Bomb }) + continue; + + processedBombs.Add(bombPos); + + // Delay before destroying neighbor group + if (this.gameVariables.bombDelay > 0f) { + int msDelay = Mathf.RoundToInt(this.gameVariables.bombDelay * 1000f); + await UniTask.Delay(msDelay); } - MoveGemsDown(); + // Collect cross neighbors + foreach (Vector2Int neighborPosition in CrossNeighbors(bombPos, this.gameVariables.bombRadius)) { + if (!InBounds(neighborPosition)) + continue; + + Gem g = GetGem(neighborPosition); + if (g == null) + continue; + + // If we encounter another bomb, queue it (so it explodes too). + if (g.Type == GemType.Bomb) { + if (!processedBombs.Contains(neighborPosition)) + bombsToProcess.Enqueue(neighborPosition); + continue; + } + + regularToDestroy.Add(neighborPosition); + } + + // Destroy the neighbor group now + foreach (Vector2Int position in regularToDestroy.ToList()) { + Gem gem = GetGem(position); + if (gem == null) + continue; + + this.scoreService.ScoreCheck(gem.ScoreValue); + DestroyMatchedGems(position); + } + regularToDestroy.Clear(); + + // Delay before destroying the bomb itself + if (this.gameVariables.bombSelfDelay > 0f) { + int ms = Mathf.RoundToInt(this.gameVariables.bombSelfDelay * 1000f); + await UniTask.Delay(ms); + } + + // Destroy the bomb + Gem b = GetGem(bombPos); + if (b != null && b.Type == GemType.Bomb) { + this.scoreService.ScoreCheck(b.ScoreValue); + DestroyMatchedGems(bombPos); + } + } + + // Destroy any remaining regular matches (non-bomb) after bomb processing + foreach (Vector2Int pos in regularToDestroy) { + Gem g = GetGem(pos); + if (g == null) + continue; + + this.scoreService.ScoreCheck(g.ScoreValue); + DestroyMatchedGems(pos); + } + + // Now we can cascade + await MoveGemsDown(); + } + + private static IEnumerable CrossNeighbors(Vector2Int center, int radius) { + // center excluded for "neighbors first" + for (int i = 1; i <= radius; i++) { + yield return center + Vector2Int.left * i; + yield return center + Vector2Int.right * i; + yield return center + Vector2Int.up * i; + yield return center + Vector2Int.down * i; + } } private async UniTask MoveGemsDown() { @@ -189,14 +322,14 @@ namespace Services { await UniTask.Delay(5); RefillBoard(); await UniTask.Delay(5); + this.matchService.FindAllMatches(); - if (this.matchService.CurrentMatches.Count > 0) - { + if (this.matchService.CurrentMatches.Count > 0) { await UniTask.Delay(5); - DestroyMatches(); - } - else - { + + // In cascades, there is no "creating slot" bomb protection. + await DestroyMatchesAsync(new List()); + } else { await UniTask.Delay(5); this.currentState = GameState.Move; } diff --git a/Assets/Scripts/Services/Interfaces/IMatchService.cs b/Assets/Scripts/Services/Interfaces/IMatchService.cs index cb59130..9206c2a 100644 --- a/Assets/Scripts/Services/Interfaces/IMatchService.cs +++ b/Assets/Scripts/Services/Interfaces/IMatchService.cs @@ -1,12 +1,15 @@ using System.Collections.Generic; using UnityEngine; using Enums; +using Structs; namespace Services.Interfaces { public interface IMatchService { List CurrentMatches { get; } + IReadOnlyList PendingBombSpawns { get; } bool MatchesAt(Vector2Int positionToCheck, GemType gemTypeToCheck); void FindAllMatches(); - void MarkBombArea(Vector2Int bombPosition, int blastSize); + void SetLastSwap(Vector2Int from, Vector2Int to); + void ClearPendingBombs(); } } \ No newline at end of file diff --git a/Assets/Scripts/Services/MatchService.cs b/Assets/Scripts/Services/MatchService.cs index 24f1290..d582661 100644 --- a/Assets/Scripts/Services/MatchService.cs +++ b/Assets/Scripts/Services/MatchService.cs @@ -3,21 +3,41 @@ using System.Linq; using Enums; using Models.Interfaces; using Services.Interfaces; +using Structs; using UnityEngine; namespace Services { public class MatchService : IMatchService { private List currentMatches = new List(); public List CurrentMatches => this.currentMatches; + + public List pendingBombSpawns = new List(); + public IReadOnlyList PendingBombSpawns => this.pendingBombSpawns; + + private Vector2Int lastSwapFrom; + private Vector2Int lastSwapTo; private IGameBoard gameBoard; public MatchService(IGameBoard gameBoard) { this.gameBoard = gameBoard; } + + public void SetLastSwap(Vector2Int from, Vector2Int to) { + this.lastSwapFrom = from; + this.lastSwapTo = to; + } + + public void ClearPendingBombs() { + this.pendingBombSpawns.Clear(); + } public bool MatchesAt(Vector2Int positionToCheck, GemType gemTypeToCheck) { Gem[,] gems = this.gameBoard.GemsGrid; + + if (gemTypeToCheck == GemType.Bomb) + return false; + if (positionToCheck.x > 1) { if (gems[positionToCheck.x - 1, positionToCheck.y].Type == gemTypeToCheck && gems[positionToCheck.x - 2, positionToCheck.y].Type == gemTypeToCheck) @@ -35,59 +55,102 @@ namespace Services { public void FindAllMatches() { this.currentMatches.Clear(); + this.pendingBombSpawns.Clear(); for (int x = 0; x < this.gameBoard.Width; x++) - for (int y = 0; y < this.gameBoard.Height; y++) - { + for (int y = 0; y < this.gameBoard.Height; y++) { Gem currentGem = this.gameBoard.GemsGrid[x, y]; - if (currentGem != null) - { - if (x > 0 && x < this.gameBoard.Width - 1) - { - Gem leftGem = this.gameBoard.GemsGrid[x - 1, y]; - Gem rightGem = this.gameBoard.GemsGrid[x + 1, y]; - //checking no empty spots - if (leftGem != null && rightGem != null) - { - //Match - if (leftGem.Type == currentGem.Type && rightGem.Type == currentGem.Type) - { - currentGem.isMatch = true; - leftGem.isMatch = true; - rightGem.isMatch = true; - this.currentMatches.Add(currentGem); - this.currentMatches.Add(leftGem); - this.currentMatches.Add(rightGem); - } + if (currentGem == null) + continue; + + if (x > 0 && x < this.gameBoard.Width - 1) { + Gem leftGem = this.gameBoard.GemsGrid[x - 1, y]; + Gem rightGem = this.gameBoard.GemsGrid[x + 1, y]; + if (leftGem != null && rightGem != null) { + if (leftGem.MatchColor == currentGem.MatchColor && rightGem.MatchColor == currentGem.MatchColor) { + this.currentMatches.Add(currentGem); + this.currentMatches.Add(leftGem); + this.currentMatches.Add(rightGem); } } + } - if (y > 0 && y < this.gameBoard.Height - 1) - { - Gem aboveGem = this.gameBoard.GemsGrid[x, y - 1]; - Gem bellowGem = this.gameBoard.GemsGrid[x, y + 1]; - //checking no empty spots - if (aboveGem != null && bellowGem != null) - { - //Match - if (aboveGem.Type == currentGem.Type && bellowGem.Type == currentGem.Type) - { - currentGem.isMatch = true; - aboveGem.isMatch = true; - bellowGem.isMatch = true; - this.currentMatches.Add(currentGem); - this.currentMatches.Add(aboveGem); - this.currentMatches.Add(bellowGem); - } + if (y > 0 && y < this.gameBoard.Height - 1) { + Gem aboveGem = this.gameBoard.GemsGrid[x, y - 1]; + Gem bellowGem = this.gameBoard.GemsGrid[x, y + 1]; + if (aboveGem != null && bellowGem != null) { + if (aboveGem.MatchColor == currentGem.MatchColor && bellowGem.MatchColor == currentGem.MatchColor) { + this.currentMatches.Add(currentGem); + this.currentMatches.Add(aboveGem); + this.currentMatches.Add(bellowGem); } } } } - if (this.currentMatches.Count > 0) this.currentMatches = this.currentMatches.Distinct().ToList(); + if (this.currentMatches.Count > 0) + this.currentMatches = this.currentMatches.Distinct().ToList(); + DetectBombSpawnFromLastSwap(); CheckForBombs(); } + + private void DetectBombSpawnFromLastSwap() { + Vector2Int from = this.lastSwapFrom; + Vector2Int to = this.lastSwapTo; + + TryCreateBombSpawnAt(from); + TryCreateBombSpawnAt(to); + } + + private void TryCreateBombSpawnAt(Vector2Int pivot) { + Gem pivotGem = this.gameBoard.GetGemAt(pivot); + if (pivotGem == null) + return; + + // If it's already a bomb, don't create another. + if (pivotGem.Type == GemType.Bomb) + return; + + if (this.currentMatches.All(g => g.Position != pivot)) + return; + + int horizontal = CountLine(pivot, Vector2Int.left) + 1 + CountLine(pivot, Vector2Int.right); + int vertical = CountLine(pivot, Vector2Int.up) + 1 + CountLine(pivot, Vector2Int.down); + + int best = Mathf.Max(horizontal, vertical); + if (best < 4) + return; + + // Spawn a bomb on the creating slot with the same color group. + // Prevent duplicates for the same cell. + if (this.pendingBombSpawns.Any(b => b.Position == pivot)) + return; + + this.pendingBombSpawns.Add(new BombSpawnRequest(pivot, pivotGem.MatchColor)); + } + + private int CountLine(Vector2Int start, Vector2Int direction) { + Gem startGem = this.gameBoard.GetGemAt(start); + if (startGem == null) + return 0; + + GemType color = startGem.MatchColor; + + int count = 0; + Vector2Int position = start + direction; + + while (position.x >= 0 && position.x < this.gameBoard.Width && position.y >= 0 && position.y < this.gameBoard.Height) { + Gem g = this.gameBoard.GetGemAt(position); + if (g == null || g.MatchColor != color) + break; + + count++; + position += direction; + } + + return count; + } private void CheckForBombs() { Gem[,] gems = this.gameBoard.GemsGrid; @@ -118,32 +181,38 @@ namespace Services { Gem neighbor = gems[newX, newY]; if (neighbor?.Type == GemType.Bomb) - MarkBombArea(new Vector2Int(newX, newY), 1); + MarkBombCross(new Vector2Int(newX, newY), 1); } } } - - public void MarkBombArea(Vector2Int bombPosition, int blastSize) { + + private void MarkBombCross(Vector2Int bombPosition, int radius) { Gem[,] gems = this.gameBoard.GemsGrid; int width = this.gameBoard.Width; int height = this.gameBoard.Height; - - for (int x = bombPosition.x - blastSize; x <= bombPosition.x + blastSize; x++) - { - for (int y = bombPosition.y - blastSize; y <= bombPosition.y + blastSize; y++) - { - if (x >= 0 && x < width && y >= 0 && y < height) - { - if (gems[x, y] != null) - { - gems[x, y].isMatch = true; - this.currentMatches.Add(gems[x, y]); - } - } - } + + void Mark(Vector2Int p) { + if (p.x < 0 || p.x >= width || p.y < 0 || p.y >= height) + return; + Gem g = gems[p.x, p.y]; + if (g == null) + return; + + this.currentMatches.Add(g); + } + + Mark(bombPosition); + + for (int i = 1; i <= radius; i++) { + Mark(bombPosition + Vector2Int.left * i); + Mark(bombPosition + Vector2Int.right * i); + Mark(bombPosition + Vector2Int.up * i); + Mark(bombPosition + Vector2Int.down * i); } this.currentMatches = this.currentMatches.Distinct().ToList(); } } + + } \ No newline at end of file diff --git a/Assets/Scripts/Structs/BombSpawnRequest.cs b/Assets/Scripts/Structs/BombSpawnRequest.cs new file mode 100644 index 0000000..2c6ce8a --- /dev/null +++ b/Assets/Scripts/Structs/BombSpawnRequest.cs @@ -0,0 +1,14 @@ +using Enums; +using UnityEngine; + +namespace Structs { + public readonly struct BombSpawnRequest { + public Vector2Int Position { get; } + public GemType Color { get; } + + public BombSpawnRequest(Vector2Int position, GemType color) { + Position = position; + Color = color; + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Structs/BombSpawnRequest.cs.meta b/Assets/Scripts/Structs/BombSpawnRequest.cs.meta new file mode 100644 index 0000000..803cbac --- /dev/null +++ b/Assets/Scripts/Structs/BombSpawnRequest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: c2f038fd08be49a58b1db5f2b7adc9d9 +timeCreated: 1765740408 \ No newline at end of file diff --git a/Assets/Scripts/Views/GemView.cs b/Assets/Scripts/Views/GemView.cs index d9a1c4c..9b3ccef 100644 --- a/Assets/Scripts/Views/GemView.cs +++ b/Assets/Scripts/Views/GemView.cs @@ -28,7 +28,7 @@ namespace Views { this.isFalling = true; } - public async UniTaskVoid UpdatePosition(Vector2Int positionBasedOnIndex) { + public async UniTaskVoid UpdatePosition(Vector2Int positionBasedOnIndex, float gemSpeed) { if (!this.isFalling) { await FallDelay(); } @@ -37,7 +37,7 @@ namespace Views { return; if (Vector2.Distance(this.transform.position, positionBasedOnIndex.ToVector2()) > 0.01f) { - this.transform.position = Vector2.Lerp(this.transform.position, positionBasedOnIndex.ToVector2(), 0.05f); + this.transform.position = Vector2.Lerp(this.transform.position, positionBasedOnIndex.ToVector2(), gemSpeed); } } } diff --git a/Assets/Scripts/Views/ScoreView.cs b/Assets/Scripts/Views/ScoreView.cs index f33dbf4..0c8fba2 100644 --- a/Assets/Scripts/Views/ScoreView.cs +++ b/Assets/Scripts/Views/ScoreView.cs @@ -12,8 +12,8 @@ namespace Views { this.scoreText = GetComponentInChildren(); } - public void UpdateScore() { - this.displayScore = Mathf.Lerp(this.displayScore, this.actualScore, 5 * Time.deltaTime); + public void UpdateScore(float scoreSpeed) { + this.displayScore = Mathf.Lerp(this.displayScore, this.actualScore, scoreSpeed * Time.deltaTime); this.scoreText.text = this.displayScore.ToString("0"); }