diff --git a/Assets/GameVariables.asset b/Assets/GameVariables.asset index 325dc25..b50bfce 100644 --- a/Assets/GameVariables.asset +++ b/Assets/GameVariables.asset @@ -59,6 +59,8 @@ MonoBehaviour: scoreValue: 10 width: 7 height: 7 + matchSfx: {fileID: 8300000, guid: 5eee8c96923a90d4a88dcd7369fcbc1a, type: 3} + bombExplodeSfx: {fileID: 8300000, guid: 9dcc9b1297952c446a5571fdb2fb7a2f, type: 3} bombDelay: 2 bombRadius: 2 dropHeight: 2 diff --git a/Assets/Scripts/Presenter/AudioPresenter.cs b/Assets/Scripts/Presenter/AudioPresenter.cs new file mode 100644 index 0000000..fe9d11a --- /dev/null +++ b/Assets/Scripts/Presenter/AudioPresenter.cs @@ -0,0 +1,21 @@ +using Services.Interfaces; +using UnityEngine; + +namespace Presenter { + public class AudioPresenter { + + private readonly IAudioService audioService; + + public AudioPresenter(IAudioService audioService) { + this.audioService = audioService; + } + + public void OnMatch(AudioClip clip) { + this.audioService.PlaySound(clip); + } + + public void OnBombExplosion (AudioClip clip) { + this.audioService.PlaySound(clip); + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Presenter/AudioPresenter.cs.meta b/Assets/Scripts/Presenter/AudioPresenter.cs.meta new file mode 100644 index 0000000..9b5cb1a --- /dev/null +++ b/Assets/Scripts/Presenter/AudioPresenter.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 152ac95510fc404ebbeff098e3214802 +timeCreated: 1765905002 \ No newline at end of file diff --git a/Assets/Scripts/Scopes/LevelLifetimeScope.cs b/Assets/Scripts/Scopes/LevelLifetimeScope.cs index e646406..0817f5f 100644 --- a/Assets/Scripts/Scopes/LevelLifetimeScope.cs +++ b/Assets/Scripts/Scopes/LevelLifetimeScope.cs @@ -35,6 +35,8 @@ namespace Scopes builder.Register(Lifetime.Scoped); + builder.Register(Lifetime.Scoped); + builder.Register(Lifetime.Scoped); builder.Register(Lifetime.Scoped).AsImplementedInterfaces(); diff --git a/Assets/Scripts/Scopes/RootLifetimeScope.cs b/Assets/Scripts/Scopes/RootLifetimeScope.cs index f739e4b..5585a0e 100644 --- a/Assets/Scripts/Scopes/RootLifetimeScope.cs +++ b/Assets/Scripts/Scopes/RootLifetimeScope.cs @@ -9,6 +9,9 @@ namespace Scopes { { builder.RegisterComponentInHierarchy() .As(); + + builder.Register(Lifetime.Scoped) + .AsImplementedInterfaces(); } } } \ No newline at end of file diff --git a/Assets/Scripts/ScriptableObjects/GameVariables.cs b/Assets/Scripts/ScriptableObjects/GameVariables.cs index 1d6406e..3d04031 100644 --- a/Assets/Scripts/ScriptableObjects/GameVariables.cs +++ b/Assets/Scripts/ScriptableObjects/GameVariables.cs @@ -7,10 +7,16 @@ namespace ScriptableObjects { [Header("Prefabs")] public GameObject bgTilePrefabs; public GemTypeValues[] gemsPrefabs; + [Header("Board Setup")] public int width; public int height; + [Header("Audio")] + public AudioClip matchSfx; + + public AudioClip bombExplodeSfx; + [Header("Bomb")] [Tooltip("How long before the gems around the bomb explode")] public float bombDelay = 0.1f; diff --git a/Assets/Scripts/Services/AudioService.cs b/Assets/Scripts/Services/AudioService.cs new file mode 100644 index 0000000..fcc3c4e --- /dev/null +++ b/Assets/Scripts/Services/AudioService.cs @@ -0,0 +1,43 @@ +using System; +using Services.Interfaces; +using UnityEngine; +using VContainer.Unity; + +namespace Services +{ + public sealed class AudioService : IAudioService, IInitializable, IDisposable + { + private readonly float volume = 1f; + private GameObject gameObject; + private AudioSource source; + + public void Initialize() + { + this.gameObject = new GameObject("AudioService"); + UnityEngine.Object.DontDestroyOnLoad(this.gameObject); + + this.source = this.gameObject.AddComponent(); + this.source.playOnAwake = false; + this.source.loop = false; + this.source.volume = this.volume; + } + + public void PlaySound(AudioClip clip) + { + if (clip == null) return; + if (this.source == null) return; // In case called before Initialize in some edge setup + + this.source.PlayOneShot(clip); + } + + public void Dispose() + { + if (this.gameObject != null) + { + UnityEngine.Object.Destroy(this.gameObject); + this.gameObject = null; + this.source = null; + } + } + } +} \ No newline at end of file diff --git a/Assets/Scripts/Services/AudioService.cs.meta b/Assets/Scripts/Services/AudioService.cs.meta new file mode 100644 index 0000000..3561a0c --- /dev/null +++ b/Assets/Scripts/Services/AudioService.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 6f530c8e01a54246bfc83a74bbbb1fc1 +timeCreated: 1765904827 \ No newline at end of file diff --git a/Assets/Scripts/Services/GameBoardService.cs b/Assets/Scripts/Services/GameBoardService.cs index 1b7e062..0d7fa27 100644 --- a/Assets/Scripts/Services/GameBoardService.cs +++ b/Assets/Scripts/Services/GameBoardService.cs @@ -21,6 +21,7 @@ namespace Services { private readonly GameVariables gameVariables; private readonly IMatchService matchService; private readonly IScoreService scoreService; + private readonly AudioPresenter audioPresenter; private readonly IBombService bombService; private readonly IObjectPool objectPool; private readonly Transform gemsHolder; @@ -32,7 +33,7 @@ namespace Services { private GameState currentState = GameState.Move; #endregion - public GameBoardService(IGameBoard gameBoard, GameVariables gameVariables, IMatchService matchService, IScoreService scoreSerivce, IBombService bombService, IObjectPool objectPool, Transform gemsHolder, ScorePresenter scorePresenter) { + public GameBoardService(IGameBoard gameBoard, GameVariables gameVariables, IMatchService matchService, IScoreService scoreSerivce, IBombService bombService, IObjectPool objectPool, Transform gemsHolder, ScorePresenter scorePresenter, AudioPresenter audioPresenter) { this.gameBoard = gameBoard; this.gameVariables = gameVariables; this.matchService = matchService; @@ -41,6 +42,7 @@ namespace Services { this.objectPool = objectPool; this.gemsHolder = gemsHolder; this.scorePresenter = scorePresenter; + this.audioPresenter = audioPresenter; } public void Tick() { @@ -224,6 +226,19 @@ namespace Services { return; } + bool willBreakAnyNonBombGem = false; + foreach (Vector2Int pos in matchPositions) { + Gem gem = GetGem(pos); + if (gem == null) continue; + if (gem.Type == GemType.Bomb) continue; + + willBreakAnyNonBombGem = true; + break; + } + + if (willBreakAnyNonBombGem) + this.audioPresenter.OnMatch(this.gameVariables.matchSfx); + foreach (Vector2Int pos in matchPositions.Distinct().ToList()) { Gem gem = GetGem(pos); if (gem == null) continue; @@ -248,6 +263,9 @@ namespace Services { Gem gem = GetGem(pos); if (gem == null) return UniTask.CompletedTask; + + if (gem.Type == GemType.Bomb) + this.audioPresenter.OnBombExplosion(this.gameVariables.bombExplodeSfx); this.scoreService.ScoreCheck(gem.ScoreValue); DestroyMatchedGems(pos); diff --git a/Assets/Scripts/Services/Interfaces/IAudioService.cs b/Assets/Scripts/Services/Interfaces/IAudioService.cs new file mode 100644 index 0000000..7525d7b --- /dev/null +++ b/Assets/Scripts/Services/Interfaces/IAudioService.cs @@ -0,0 +1,7 @@ +using UnityEngine; + +namespace Services.Interfaces { + public interface IAudioService { + void PlaySound(AudioClip clip); + } +} \ No newline at end of file diff --git a/Assets/Scripts/Services/Interfaces/IAudioService.cs.meta b/Assets/Scripts/Services/Interfaces/IAudioService.cs.meta new file mode 100644 index 0000000..b2d2b5e --- /dev/null +++ b/Assets/Scripts/Services/Interfaces/IAudioService.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: d04aef7bff08494fbae7a04db1fcda22 +timeCreated: 1765904685 \ No newline at end of file diff --git a/Assets/Scripts/Services/LevelEntryPoint.cs b/Assets/Scripts/Services/LevelEntryPoint.cs index 4e56199..602e543 100644 --- a/Assets/Scripts/Services/LevelEntryPoint.cs +++ b/Assets/Scripts/Services/LevelEntryPoint.cs @@ -1,3 +1,4 @@ +using Presenter; using Services.Interfaces; using UnityEngine; using VContainer.Unity; @@ -10,12 +11,14 @@ namespace Services private readonly IObjectPool gemViewPool; private readonly IGameBoardService gameBoardService; private readonly IInputService inputService; + private readonly AudioPresenter audioPresenter; - public LevelEntryPoint(IObjectPool gemViewPool, IGameBoardService gameBoardService, IInputService inputService) + public LevelEntryPoint(IObjectPool gemViewPool, IGameBoardService gameBoardService, IInputService inputService, AudioPresenter audioPresenter) { this.gemViewPool = gemViewPool; this.gameBoardService = gameBoardService; this.inputService = inputService; + this.audioPresenter = audioPresenter; } public void Start()