Added more sound effeects. Added audio manager.

This commit is contained in:
2025-12-28 21:23:23 -05:00
parent 874c263910
commit c4a98ce03d
32 changed files with 550 additions and 37 deletions

View File

@@ -1,4 +1,5 @@
using AlienAttack.MonoGame.GameLoops;
using AlienAttack.MonoGame.Audio;
using AlienAttack.MonoGame.GameLoops;
using AlienAttack.MonoGame.View;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
@@ -20,6 +21,7 @@ public class AlienAttackGame : Game
public SpriteBatch SpriteBatch => _spriteBatch;
public ViewTransform ViewTransform => _viewTransform;
public AudioManager Audio { get; private set; } = new();
private const string SDL = "SDL2.dll";
@@ -47,27 +49,7 @@ public class AlienAttackGame : Game
MaximizeWindow();
PlayBackgroundMusic();
}
private void PlayBackgroundMusic()
{
Song song = Content.Load<Song>($@"Music\Untitled");
// Set whether the song should repeat when finished
MediaPlayer.IsRepeating = true;
// Adjust the volume (0.0f to 1.0f)
MediaPlayer.Volume = 0.5f;
// Check if the media player is already playing, if so, stop it
if (MediaPlayer.State == MediaState.Playing)
{
MediaPlayer.Stop();
}
// Start playing the background music
MediaPlayer.Play(song);
//Audio.PlayMusic(Content, @"Music\Untitled");
}
private void ConfigureWindow()
@@ -91,11 +73,16 @@ public class AlienAttackGame : Game
{
_spriteBatch = new SpriteBatch(GraphicsDevice);
_gameLoop = new GameLoop(this);
// TODO: use this.Content to load your game content here
Audio.LoadContent(Content);
}
protected override void Update(GameTime gameTime)
{
if (IsActive == false)
return;
if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed || Keyboard.GetState().IsKeyDown(Keys.Escape))
Exit();

View File

@@ -0,0 +1,284 @@
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Media;
using System;
namespace AlienAttack.MonoGame.Audio;
public sealed class AudioManager
{
public float MasterVolume { get; set; } = 1f;
public float SfxVolume { get; set; } = 0.8f;
public float MusicVolume { get; set; } = 0.7f;
private readonly Random _random = new(12345);
// Pools
private VariantSoundPool _playerGunPool = default!;
private VariantSoundPool _enemyGunPool = default!;
private VariantSoundPool _explosionPool = default!;
private VariantSoundPool _impactPool = default!;
// Rate limiters (global caps per category/event)
private RateLimiter _playerGunLimiter = new(0.06f); // max ~16 plays/sec
private RateLimiter _enemyGunLimiter = new(0.12f); // max ~8 plays/sec (global for all enemies)
private RateLimiter _impactLimiter = new(0.04f);
// Music
private Song? _currentSong;
private float _musicDuck = 1f; // 1.0 = normal, <1 = ducked
private float _musicDuckTarget = 1f;
private float _musicDuckSpeed = 6f; // how fast it moves toward target (bigger = snappier)
public void LoadContent(ContentManager content)
{
// Load SoundEffects once
LoadPlayerGunPool(content);
LoadEnemyGunPool(content);
LoadImpactPool(content);
LoadExplosionPool(content);
//var playerGun = content.Load<SoundEffect>("Audio/Sfx/player_fire");
//var enemyGun = content.Load<SoundEffect>("Audio/Sfx/enemy_fire");
//var explosion = content.Load<SoundEffect>("Audio/Sfx/explosion");
//var impact = content.Load<SoundEffect>("Audio/Sfx/impact");
// Create pools with sane voice caps
//_playerGunPool = new SoundPool(playerGun, maxVoices: 2);
//_enemyGunPool = new SoundPool(enemyGun, maxVoices: 3);
//_explosionPool = new SoundPool(explosion, maxVoices: 6);
//_impactPool = new SoundPool(impact, maxVoices: 4);
}
private void LoadPlayerGunPool(ContentManager content)
{
var playerGunVariants = new[]
{
content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_01_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_02_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_03_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_04_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_05_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/GUNAuto_Assault Rifle A Fire_06_SFRMS_SCIWPNS")
};
_playerGunPool = new VariantSoundPool(playerGunVariants, voicesPerVariant: 1, rng: _random);
}
private void LoadEnemyGunPool(ContentManager content)
{
var variants = new[]
{
content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_01_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_02_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_03_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_04_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_05_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/Pistol/GUNPis_Pistol Fire_06_SFRMS_SCIWPNS"),
};
_enemyGunPool = new VariantSoundPool(variants, voicesPerVariant: 1, rng: _random);
}
private void LoadImpactPool(ContentManager content)
{
var variants = new[]
{
content.Load<SoundEffect>("Sfx/Impact/BLLTImpt_Impact Object_01_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/Impact/BLLTImpt_Impact Object_02_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/Impact/BLLTImpt_Impact Object_03_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/Impact/BLLTImpt_Impact Object_04_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/Impact/BLLTImpt_Impact Object_05_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/Impact/BLLTImpt_Impact Object_06_SFRMS_SCIWPNS"),
};
_impactPool = new VariantSoundPool(variants, voicesPerVariant: 1, rng: _random);
}
private void LoadExplosionPool(ContentManager content)
{
var variants = new[]
{
content.Load<SoundEffect>("Sfx/Explosions/EXPLDsgn_Explosion Impact_01_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/Explosions/EXPLDsgn_Explosion Impact_02_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/Explosions/EXPLDsgn_Explosion Impact_03_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/Explosions/EXPLDsgn_Explosion Impact_04_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/Explosions/EXPLDsgn_Explosion Impact_05_SFRMS_SCIWPNS"),
content.Load<SoundEffect>("Sfx/Explosions/EXPLDsgn_Explosion Impact_06_SFRMS_SCIWPNS")
};
_explosionPool = new VariantSoundPool(variants, voicesPerVariant: 1, rng: _random);
}
// Call this once per frame
public void Update(GameTime gameTime)
{
float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
_playerGunLimiter.Update(dt);
_enemyGunLimiter.Update(dt);
_impactLimiter.Update(dt);
// Smoothly approach the duck target
_musicDuck = Approach(_musicDuck, _musicDuckTarget, _musicDuckSpeed * dt);
// Apply music volume
MediaPlayer.Volume = Clamp01(MasterVolume * MusicVolume * _musicDuck);
}
// -----------------------
// Public SFX entry points
// -----------------------
public void PlayPlayerFire()
{
if (!_playerGunLimiter.TryConsume()) return;
// Bullet sounds should be short + quiet-ish
float baseVol = 0.35f;
float vol = baseVol * RandRange(0.92f, 1.05f);
float pitch = RandRange(-0.05f, 0.05f);
_playerGunPool.Play(
volume: Clamp01(MasterVolume * SfxVolume * vol),
pitch: pitch
);
}
public void PlayEnemyFire()
{
if (!_enemyGunLimiter.TryConsume()) return;
float baseVol = 0.28f;
float vol = baseVol * RandRange(0.90f, 1.05f);
float pitch = RandRange(-0.07f, 0.07f);
_enemyGunPool.Play(
volume: Clamp01(MasterVolume * SfxVolume * vol),
pitch: pitch
);
}
public void PlayImpact()
{
if (!_impactLimiter.TryConsume()) return;
float baseVol = 0.25f;
float vol = baseVol * RandRange(0.90f, 1.10f);
float pitch = RandRange(-0.08f, 0.08f);
_impactPool.Play(
volume: Clamp01(MasterVolume * SfxVolume * vol),
pitch: pitch
);
}
public void PlayExplosion(bool duckMusic = true)
{
float baseVol = 0.85f;
float vol = baseVol * RandRange(0.95f, 1.05f);
float pitch = RandRange(-0.04f, 0.04f);
_explosionPool.Play(
volume: Clamp01(MasterVolume * SfxVolume * vol),
pitch: pitch
);
if (duckMusic)
{
// Duck music quickly, then let it recover
DuckMusic(amount: 0.55f, holdSeconds: 0.20f, releaseSeconds: 0.35f);
}
}
// -----------------------
// Music
// -----------------------
public void PlayMusic(ContentManager content, string songAssetName, bool loop = true)
{
// Example asset name: "Audio/Music/level1"
_currentSong = content.Load<Song>(songAssetName);
MediaPlayer.IsRepeating = loop;
MediaPlayer.Volume = Clamp01(MasterVolume * MusicVolume * _musicDuck);
MediaPlayer.Play(_currentSong);
}
public void StopMusic() => MediaPlayer.Stop();
public void PauseMusic() => MediaPlayer.Pause();
public void ResumeMusic() => MediaPlayer.Resume();
// Duck helper: amount < 1.0 means quieter music (e.g., 0.55)
public void DuckMusic(float amount, float holdSeconds, float releaseSeconds)
{
amount = Math.Clamp(amount, 0.05f, 1f);
_musicDuckTarget = amount;
// Use a tiny internal timer without introducing a scheduler:
// We'll set a one-shot "return to 1" using a lightweight countdown.
_duckReturnTimer = holdSeconds;
_duckReleaseSeconds = Math.Max(0.01f, releaseSeconds);
}
private float _duckReturnTimer = 0f;
private float _duckReleaseSeconds = 0.35f;
// Call from Update to manage duck release
private void HandleDuckRelease(float dt)
{
if (_musicDuckTarget < 1f)
{
_duckReturnTimer -= dt;
if (_duckReturnTimer <= 0f)
{
// start releasing
_musicDuckTarget = 1f;
_musicDuckSpeed = 1f / _duckReleaseSeconds; // approx
// after it reaches 1, you can restore default speed if you want
}
}
else
{
// restore default “snappiness” once fully normal
if (Math.Abs(_musicDuck - 1f) < 0.001f)
_musicDuckSpeed = 6f;
}
}
// Update override to include duck release handling
public void UpdateWithDuck(GameTime gameTime)
{
float dt = (float)gameTime.ElapsedGameTime.TotalSeconds;
_playerGunLimiter.Update(dt);
_enemyGunLimiter.Update(dt);
_impactLimiter.Update(dt);
HandleDuckRelease(dt);
_musicDuck = Approach(_musicDuck, _musicDuckTarget, _musicDuckSpeed * dt);
MediaPlayer.Volume = Clamp01(MasterVolume * MusicVolume * _musicDuck);
}
// -----------------------
// Utilities
// -----------------------
private float RandRange(float min, float max)
=> (float)(min + _random.NextDouble() * (max - min));
private static float Clamp01(float v) => Math.Clamp(v, 0f, 1f);
private static float Approach(float current, float target, float maxDelta)
{
if (current < target)
return Math.Min(current + maxDelta, target);
if (current > target)
return Math.Max(current - maxDelta, target);
return current;
}
}

View File

@@ -0,0 +1,25 @@
namespace AlienAttack.MonoGame.Audio;
public sealed class RateLimiter(float cooldownSeconds)
{
private readonly float _cooldownSeconds = cooldownSeconds <= 0 ? 0.0001f : cooldownSeconds;
private float _timer = 0f;
public void Update(float deltaTime)
{
_timer -= deltaTime;
if (_timer < 0f)
_timer = 0f;
}
public bool TryConsume()
{
if (_timer > 0f)
return false;
_timer = _cooldownSeconds;
return true;
}
}

View File

@@ -0,0 +1,37 @@
using Microsoft.Xna.Framework.Audio;
using System;
namespace AlienAttack.MonoGame.Audio;
public sealed class SoundPool
{
private readonly SoundEffectInstance[] _voices;
private int _cursor;
public SoundPool(SoundEffect effect, int maxVoices)
{
ArgumentOutOfRangeException.ThrowIfLessThan(maxVoices, 1);
_voices = new SoundEffectInstance[maxVoices];
for (int i = 0; i < maxVoices; i++)
_voices[i] = effect.CreateInstance();
}
public void Play(float volume = 1f, float pitch = 0f, float pan = 0f)
{
SoundEffectInstance instance = _voices[_cursor];
_cursor = (_cursor + 1) % _voices.Length;
// "Voice stealing": stop if currently playing, then reuse immediately
if (instance.State == SoundState.Playing)
instance.Stop();
instance.Volume = Math.Clamp(volume, 0f, 1f);
instance.Pitch = Math.Clamp(pitch, -1f, 1f);
instance.Pan = Math.Clamp(pan, -1f, 1f);
instance.Play();
}
}

View File

@@ -0,0 +1,48 @@
using Microsoft.Xna.Framework.Audio;
using System;
namespace AlienAttack.MonoGame.Audio;
public sealed class VariantSoundPool
{
private readonly SoundPool[] _variantPools;
private readonly Random _rng;
private int _lastIndex = -1;
public VariantSoundPool(SoundEffect[] variants, int voicesPerVariant, Random rng)
{
if (variants == null || variants.Length == 0)
throw new ArgumentException("At least one variant is required.", nameof(variants));
ArgumentOutOfRangeException.ThrowIfLessThan(voicesPerVariant, 1);
_rng = rng ?? throw new ArgumentNullException(nameof(rng));
_variantPools = new SoundPool[variants.Length];
for (int i = 0; i < variants.Length; i++)
_variantPools[i] = new SoundPool(variants[i], voicesPerVariant);
}
public void Play(float volume = 1f, float pitch = 0f, float pan = 0f, bool avoidImmediateRepeat = true)
{
int idx = PickVariantIndex(avoidImmediateRepeat);
_variantPools[idx].Play(volume, pitch, pan);
}
private int PickVariantIndex(bool avoidImmediateRepeat)
{
if (_variantPools.Length == 1)
return 0;
int idx = _rng.Next(_variantPools.Length);
if (!avoidImmediateRepeat) { _lastIndex = idx; return idx; }
// Avoid playing the exact same sample twice in a row (nice polish)
if (idx == _lastIndex)
idx = (idx + 1 + _rng.Next(_variantPools.Length - 1)) % _variantPools.Length;
_lastIndex = idx;
return idx;
}
}

View File

@@ -151,6 +151,78 @@
/processorParam:Quality=Best
/build:Sfx/GUNPis_Pistol Fire_06_SFRMS_SCIWPNS.wav
#begin Sfx/Impact/BLLTImpt_Impact Object_01_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Impact/BLLTImpt_Impact Object_01_SFRMS_SCIWPNS.wav;Sfx/Impact/BLLTImpt_Impact Object_01_SFRMS_SCIWPNS
#begin Sfx/Impact/BLLTImpt_Impact Object_02_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Impact/BLLTImpt_Impact Object_02_SFRMS_SCIWPNS.wav;Sfx/Impact/BLLTImpt_Impact Object_02_SFRMS_SCIWPNS
#begin Sfx/Impact/BLLTImpt_Impact Object_03_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Impact/BLLTImpt_Impact Object_03_SFRMS_SCIWPNS.wav;Sfx/Impact/BLLTImpt_Impact Object_03_SFRMS_SCIWPNS
#begin Sfx/Impact/BLLTImpt_Impact Object_04_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Impact/BLLTImpt_Impact Object_04_SFRMS_SCIWPNS.wav;Sfx/Impact/BLLTImpt_Impact Object_04_SFRMS_SCIWPNS
#begin Sfx/Impact/BLLTImpt_Impact Object_05_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Impact/BLLTImpt_Impact Object_05_SFRMS_SCIWPNS.wav;Sfx/Impact/BLLTImpt_Impact Object_05_SFRMS_SCIWPNS
#begin Sfx/Impact/BLLTImpt_Impact Object_06_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Impact/BLLTImpt_Impact Object_06_SFRMS_SCIWPNS.wav;Sfx/Impact/BLLTImpt_Impact Object_06_SFRMS_SCIWPNS
#begin Sfx/Pistol/GUNPis_Pistol Fire_01_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Pistol/GUNPis_Pistol Fire_01_SFRMS_SCIWPNS.wav;Sfx/Pistol/GUNPis_Pistol Fire_01_SFRMS_SCIWPNS
#begin Sfx/Pistol/GUNPis_Pistol Fire_02_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Pistol/GUNPis_Pistol Fire_02_SFRMS_SCIWPNS.wav;Sfx/Pistol/GUNPis_Pistol Fire_02_SFRMS_SCIWPNS
#begin Sfx/Pistol/GUNPis_Pistol Fire_03_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Pistol/GUNPis_Pistol Fire_03_SFRMS_SCIWPNS.wav;Sfx/Pistol/GUNPis_Pistol Fire_03_SFRMS_SCIWPNS
#begin Sfx/Pistol/GUNPis_Pistol Fire_04_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Pistol/GUNPis_Pistol Fire_04_SFRMS_SCIWPNS.wav;Sfx/Pistol/GUNPis_Pistol Fire_04_SFRMS_SCIWPNS
#begin Sfx/Pistol/GUNPis_Pistol Fire_05_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Pistol/GUNPis_Pistol Fire_05_SFRMS_SCIWPNS.wav;Sfx/Pistol/GUNPis_Pistol Fire_05_SFRMS_SCIWPNS
#begin Sfx/Pistol/GUNPis_Pistol Fire_06_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Pistol/GUNPis_Pistol Fire_06_SFRMS_SCIWPNS.wav;Sfx/Pistol/GUNPis_Pistol Fire_06_SFRMS_SCIWPNS
#begin Sfx/Shield/SCIEnrg_Shield Activate_01_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
@@ -181,6 +253,42 @@
/processorParam:Quality=Best
/build:Sfx/Shield/SCIEnrg_Shield Activate_05_SFRMS_SCIWPNS.wav;Sfx/Shield/SCIEnrg_Shield Activate_05_SFRMS_SCIWPNS
#begin Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_01_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_01_SFRMS_SCIWPNS.wav;Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_01_SFRMS_SCIWPNS
#begin Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_02_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_02_SFRMS_SCIWPNS.wav;Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_02_SFRMS_SCIWPNS
#begin Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_03_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_03_SFRMS_SCIWPNS.wav;Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_03_SFRMS_SCIWPNS
#begin Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_04_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_04_SFRMS_SCIWPNS.wav;Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_04_SFRMS_SCIWPNS
#begin Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_05_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_05_SFRMS_SCIWPNS.wav;Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_05_SFRMS_SCIWPNS
#begin Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_06_SFRMS_SCIWPNS.wav
/importer:WavImporter
/processor:SoundEffectProcessor
/processorParam:Quality=Best
/build:Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_06_SFRMS_SCIWPNS.wav;Sfx/Silenced Pistol/GUNSupr_Silenced Pistol Fire Short_06_SFRMS_SCIWPNS
#begin Sprites/Asteroid 01_png_processed.png
/importer:TextureImporter
/processor:TextureProcessor

View File

@@ -1,4 +1,5 @@
using AlienAttack.MonoGame.View;
using AlienAttack.MonoGame.Audio;
using AlienAttack.MonoGame.View;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
@@ -11,6 +12,7 @@ internal abstract class GameLoopBase(AlienAttackGame game) : IGameLoop
protected readonly ContentManager Content = game.Content;
protected readonly SpriteBatch SpriteBatch = game.SpriteBatch;
protected readonly ViewTransform ViewTransform = game.ViewTransform;
protected readonly AudioManager Audio = game.Audio;
public void Draw(GameTime gameTime)
{
@@ -23,6 +25,7 @@ internal abstract class GameLoopBase(AlienAttackGame game) : IGameLoop
public void Update(GameTime gameTime)
{
Audio.UpdateWithDuck(gameTime);
OnUpdate(gameTime);
}

View File

@@ -47,5 +47,7 @@ internal class Bullet(float x, float y, float xVel, float yVel, Sprite owner) :
}
context.SpawnSprite(new MiniExplosion((int)XPosition, (int)YPosition, xVel, yVel));
context.AudioManager.PlayImpact();
}
}

View File

@@ -88,6 +88,8 @@ internal class GreenEnemy : EnemyShip
context.SpawnSprite(new MinigunBulletSmall(originX + 14, YPosition + BoundBox.Height - 12, 0, 2 + YVelocity, this));
CurrentFireThreshold = FireThreshold;
context.AudioManager.PlayEnemyFire();
}
//CheckMove(context);
@@ -100,10 +102,12 @@ internal class GreenEnemy : EnemyShip
{
context.SpawnSprite(new Explosion((int)XPosition, (int)YPosition, XVelocity, YVelocity));
int number = context.Random.Next(1, 7);
//int number = context.Random.Next(1, 7);
SoundEffect soundEffect = context.Content.Load<SoundEffect>(@$"Sfx\Explosions\EXPLDsgn_Explosion Impact_0{number}_SFRMS_SCIWPNS");
soundEffect.Play(0.95f, (float)(context.Random.NextDouble() * 0.1 - 0.05), 0);
//SoundEffect soundEffect = context.Content.Load<SoundEffect>(@$"Sfx\Explosions\EXPLDsgn_Explosion Impact_0{number}_SFRMS_SCIWPNS");
//soundEffect.Play(0.95f, (float)(context.Random.NextDouble() * 0.1 - 0.05), 0);
context.AudioManager.PlayExplosion();
}
private void CheckFire(SpriteUpdateContext context)

View File

@@ -73,10 +73,12 @@ internal class RedEnemy : EnemyShip
{
context.SpawnSprite(new Explosion((int)XPosition, (int)YPosition, XVelocity, YVelocity));
int number = context.Random.Next(1, 7);
//int number = context.Random.Next(1, 7);
SoundEffect soundEffect = context.Content.Load<SoundEffect>(@$"Sfx\Explosions\EXPLDsgn_Explosion Impact_0{number}_SFRMS_SCIWPNS");
soundEffect.Play(0.95f, (float)(context.Random.NextDouble() * 0.1 - 0.05), 0);
//SoundEffect soundEffect = context.Content.Load<SoundEffect>(@$"Sfx\Explosions\EXPLDsgn_Explosion Impact_0{number}_SFRMS_SCIWPNS");
//soundEffect.Play(0.95f, (float)(context.Random.NextDouble() * 0.1 - 0.05), 0);
context.AudioManager.PlayExplosion();
}
private void TryFire(SpriteUpdateContext context)
@@ -94,6 +96,8 @@ internal class RedEnemy : EnemyShip
context.SpawnSprite(new MinigunBulletSmall(originX + 14, YPosition + BoundBox.Height - 12, 0, 2 + YVelocity, this));
CurrentFireThreshold = FireThreshold;
context.AudioManager.PlayEnemyFire();
}
}

View File

@@ -66,10 +66,12 @@ internal class TealEnemy : EnemyShip
{
context.SpawnSprite(new Explosion((int)XPosition, (int)YPosition, XVelocity, YVelocity));
int number = context.Random.Next(1, 7);
//int number = context.Random.Next(1, 7);
SoundEffect soundEffect = context.Content.Load<SoundEffect>(@$"Sfx\Explosions\EXPLDsgn_Explosion Impact_0{number}_SFRMS_SCIWPNS");
soundEffect.Play(0.95f, (float)(context.Random.NextDouble() * 0.1 - 0.05), 0);
//SoundEffect soundEffect = context.Content.Load<SoundEffect>(@$"Sfx\Explosions\EXPLDsgn_Explosion Impact_0{number}_SFRMS_SCIWPNS");
//soundEffect.Play(0.95f, (float)(context.Random.NextDouble() * 0.1 - 0.05), 0);
context.AudioManager.PlayExplosion();
}
private void TryFire(SpriteUpdateContext context)
@@ -87,6 +89,8 @@ internal class TealEnemy : EnemyShip
context.SpawnSprite(new MinigunBulletSmall(originX + 14, YPosition + BoundBox.Height - 12, 0, 2 + YVelocity, this));
CurrentFireThreshold = FireThreshold;
context.AudioManager.PlayEnemyFire();
}
}

View File

@@ -97,11 +97,13 @@ internal class Player : MoveableSprite
public override void Update(SpriteUpdateContext context)
{
base.Update(context);
//UpdateExhaustAnimationThreshold();
CheckMove(context);
CheckFire(context);
base.Update(context);
//base.Update(context);
}
private void UpdateExhaustAnimationThreshold()

View File

@@ -1,4 +1,5 @@
using AlienAttack.MonoGame.View;
using AlienAttack.MonoGame.Audio;
using AlienAttack.MonoGame.View;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using System;
@@ -12,6 +13,7 @@ public class SpriteUpdateContext(AlienAttackGame game)
public required Random Random { get; init; }
public required GameTime GameTime { get; init; }
public required ContentManager Content { get; init; }
public AudioManager AudioManager => game.Audio;
}
public class SpriteCollisionContext(AlienAttackGame game)
@@ -21,4 +23,5 @@ public class SpriteCollisionContext(AlienAttackGame game)
public required Action<Sprite> SpawnSprite { get; init; }
public required Random Random { get; init; }
public required ContentManager Content { get; init; }
public AudioManager AudioManager => game.Audio;
}

View File

@@ -22,10 +22,12 @@ public class Minigun : Weapon
context.SpawnSprite(bullet1);
context.SpawnSprite(bullet2);
int number = context.Random.Next(1, 7);
//int number = context.Random.Next(1, 7);
SoundEffect soundEffect = context.Content.Load<SoundEffect>(@$"Sfx\GUNAuto_Assault Rifle A Fire_0{number}_SFRMS_SCIWPNS");
soundEffect.Play(0.25f, (float)(context.Random.NextDouble() * 0.1 - 0.05), 0);
//SoundEffect soundEffect = context.Content.Load<SoundEffect>(@$"Sfx\GUNAuto_Assault Rifle A Fire_0{number}_SFRMS_SCIWPNS");
//soundEffect.Play(0.25f, (float)(context.Random.NextDouble() * 0.1 - 0.05), 0);
context.AudioManager.PlayPlayerFire();
}
}