531 lines
24 KiB
C#
531 lines
24 KiB
C#
using AlienAttack.MonoGame.Things.Bullets;
|
|
using AlienAttack.MonoGame.Things.Items;
|
|
using Microsoft.Xna.Framework;
|
|
using Microsoft.Xna.Framework.Audio;
|
|
using Microsoft.Xna.Framework.Content;
|
|
using Microsoft.Xna.Framework.Media;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
|
|
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 readonly Dictionary<BulletKind, VariantSoundPool> _playerGunPool2 = [];
|
|
|
|
private VariantSoundPool _enemyGunPool = default!;
|
|
private readonly Dictionary<BulletKind, VariantSoundPool> _enemyGunPool2 = [];
|
|
|
|
private VariantSoundPool _explosionPool = default!;
|
|
private VariantSoundPool _impactPool = default!;
|
|
private readonly Dictionary<PickupKind, VariantSoundPool> _pickupPool = [];
|
|
|
|
// 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);
|
|
LoadGunPools(content);
|
|
LoadEnemyGunPool(content);
|
|
LoadImpactPool(content);
|
|
LoadExplosionPool(content);
|
|
|
|
LoadShieldPickupPool(content);
|
|
LoadAmmoPickupPool(content);
|
|
LoadRocketsPickupPool(content);
|
|
LoadPlasmaPickupPool(content);
|
|
}
|
|
|
|
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 LoadGunPools(ContentManager content)
|
|
{
|
|
var minigunSmallVariants = 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")
|
|
};
|
|
|
|
var minigunLargeVariants = 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")
|
|
};
|
|
|
|
// Laser
|
|
|
|
//LASRGun_Alien Handgun Fire Light_01_SFRMS_SCIWPNS
|
|
|
|
var laserSmallVariants = new[]
|
|
{
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Light_01_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Light_02_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Light_03_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Light_04_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Light_05_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Light_06_SFRMS_SCIWPNS")
|
|
};
|
|
|
|
var laserMediumVariants = new[]
|
|
{
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_01_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_02_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_03_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_04_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_05_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_06_SFRMS_SCIWPNS")
|
|
};
|
|
|
|
var laserLargeVariants = new[]
|
|
{
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_01_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_02_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_03_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_04_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_05_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Alien Handgun/LASRGun_Alien Handgun Fire Heavy_06_SFRMS_SCIWPNS")
|
|
};
|
|
|
|
// Plasma
|
|
|
|
//GUNAuto_Plasmid Machinegun Single_01_SFRMS_SCIWPNS
|
|
//GUNAuto_Plasmid Machinegun B Single_01_SFRMS_SCIWPNS
|
|
|
|
var plasmaSmallVariants = new[]
|
|
{
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun/GUNAuto_Plasmid Machinegun Single_01_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun/GUNAuto_Plasmid Machinegun Single_02_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun/GUNAuto_Plasmid Machinegun Single_03_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun/GUNAuto_Plasmid Machinegun Single_04_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun/GUNAuto_Plasmid Machinegun Single_05_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun/GUNAuto_Plasmid Machinegun Single_06_SFRMS_SCIWPNS")
|
|
};
|
|
|
|
var plasmaMediumVariants = new[]
|
|
{
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun B/GUNAuto_Plasmid Machinegun B Single_01_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun B/GUNAuto_Plasmid Machinegun B Single_02_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun B/GUNAuto_Plasmid Machinegun B Single_03_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun B/GUNAuto_Plasmid Machinegun B Single_04_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun B/GUNAuto_Plasmid Machinegun B Single_05_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun B/GUNAuto_Plasmid Machinegun B Single_06_SFRMS_SCIWPNS")
|
|
};
|
|
|
|
var plasmaLargeVariants = new[]
|
|
{
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun C/GUNAuto_Plasmid Machinegun C Single_01_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun C/GUNAuto_Plasmid Machinegun C Single_02_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun C/GUNAuto_Plasmid Machinegun C Single_03_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun C/GUNAuto_Plasmid Machinegun C Single_04_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun C/GUNAuto_Plasmid Machinegun C Single_05_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Plasmid Machinegun C/GUNAuto_Plasmid Machinegun C Single_06_SFRMS_SCIWPNS")
|
|
};
|
|
|
|
// Proton
|
|
|
|
var protonSmallVariants = new[]
|
|
{
|
|
content.Load<SoundEffect>("Sfx/RPU1/GUNAuto_RPU1 Fire_01_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/RPU1/GUNAuto_RPU1 Fire_02_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/RPU1/GUNAuto_RPU1 Fire_03_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/RPU1/GUNAuto_RPU1 Fire_04_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/RPU1/GUNAuto_RPU1 Fire_05_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/RPU1/GUNAuto_RPU1 Fire_06_SFRMS_SCIWPNS")
|
|
};
|
|
|
|
var protonMediumVariants = new[]
|
|
{
|
|
content.Load<SoundEffect>("Sfx/RPU1 B/GUNAuto_RPU1 B Fire_01_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/RPU1 B/GUNAuto_RPU1 B Fire_02_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/RPU1 B/GUNAuto_RPU1 B Fire_03_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/RPU1 B/GUNAuto_RPU1 B Fire_04_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/RPU1 B/GUNAuto_RPU1 B Fire_05_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/RPU1 B/GUNAuto_RPU1 B Fire_06_SFRMS_SCIWPNS")
|
|
};
|
|
|
|
var protonLargeVariants = new[]
|
|
{
|
|
content.Load<SoundEffect>("Sfx/RPU1 C/GUNAuto_RPU1 C Fire_01_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/RPU1 C/GUNAuto_RPU1 C Fire_02_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/RPU1 C/GUNAuto_RPU1 C Fire_03_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/RPU1 C/GUNAuto_RPU1 C Fire_04_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/RPU1 C/GUNAuto_RPU1 C Fire_05_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/RPU1 C/GUNAuto_RPU1 C Fire_06_SFRMS_SCIWPNS")
|
|
};
|
|
|
|
//GUNAuto_RPU1 Fire_01_SFRMS_SCIWPNS
|
|
|
|
_playerGunPool2.Add(BulletKind.MinigunSmall, new VariantSoundPool(minigunSmallVariants, voicesPerVariant: 1, rng: _random));
|
|
//_playerGunPool2.Add(BulletKind.MinigunMedium, new VariantSoundPool(minigunLargeVariants, voicesPerVariant: 1, rng: _random));
|
|
_playerGunPool2.Add(BulletKind.MinigunLarge, new VariantSoundPool(minigunLargeVariants, voicesPerVariant: 1, rng: _random));
|
|
|
|
_playerGunPool2.Add(BulletKind.LaserSmall, new VariantSoundPool(laserSmallVariants, voicesPerVariant: 1, rng: _random));
|
|
_playerGunPool2.Add(BulletKind.LaserMedium, new VariantSoundPool(laserMediumVariants, voicesPerVariant: 1, rng: _random));
|
|
_playerGunPool2.Add(BulletKind.LaserLarge, new VariantSoundPool(laserLargeVariants, voicesPerVariant: 1, rng: _random));
|
|
|
|
_playerGunPool2.Add(BulletKind.PlasmaSmall, new VariantSoundPool(plasmaSmallVariants, voicesPerVariant: 1, rng: _random));
|
|
_playerGunPool2.Add(BulletKind.PlasmaMedium, new VariantSoundPool(plasmaMediumVariants, voicesPerVariant: 1, rng: _random));
|
|
_playerGunPool2.Add(BulletKind.PlasmaLarge, new VariantSoundPool(plasmaLargeVariants, voicesPerVariant: 1, rng: _random));
|
|
|
|
_playerGunPool2.Add(BulletKind.ProtonSmall, new VariantSoundPool(protonSmallVariants, voicesPerVariant: 1, rng: _random));
|
|
_playerGunPool2.Add(BulletKind.ProtonMedium, new VariantSoundPool(protonMediumVariants, voicesPerVariant: 1, rng: _random));
|
|
_playerGunPool2.Add(BulletKind.ProtonLarge, new VariantSoundPool(protonLargeVariants, 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);
|
|
}
|
|
|
|
private void LoadShieldPickupPool(ContentManager content)
|
|
{
|
|
var shieldVariants = new[]
|
|
{
|
|
content.Load<SoundEffect>("Sfx/Shield/SCIEnrg_Shield Activate_01_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Shield/SCIEnrg_Shield Activate_02_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Shield/SCIEnrg_Shield Activate_03_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Shield/SCIEnrg_Shield Activate_04_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Shield/SCIEnrg_Shield Activate_05_SFRMS_SCIWPNS")
|
|
};
|
|
|
|
_pickupPool.Add(PickupKind.Shield, new VariantSoundPool(shieldVariants, voicesPerVariant: 1, rng: _random));
|
|
}
|
|
|
|
private void LoadAmmoPickupPool(ContentManager content)
|
|
{
|
|
var variants = new[]
|
|
{
|
|
content.Load<SoundEffect>("Sfx/Reload/GUNMech_Insert Clip_01_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Reload/GUNMech_Insert Clip_02_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Reload/GUNMech_Insert Clip_03_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Reload/GUNMech_Insert Clip_04_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Reload/GUNMech_Insert Clip_05_SFRMS_SCIWPNS")
|
|
};
|
|
|
|
_pickupPool.Add(PickupKind.Ammo, new VariantSoundPool(variants, voicesPerVariant: 1, rng: _random));
|
|
}
|
|
|
|
private void LoadRocketsPickupPool(ContentManager content)
|
|
{
|
|
var variants = new[]
|
|
{
|
|
content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_01_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_02_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_03_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_04_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_05_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_06_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_07_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_08_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_09_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_10_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Rocket Launcher/GUNMech_Rocket Launcher Reload_11_SFRMS_SCIWPNS"),
|
|
};
|
|
|
|
_pickupPool.Add(PickupKind.Rockets, new VariantSoundPool(variants, voicesPerVariant: 1, rng: _random));
|
|
}
|
|
|
|
//SCIMisc_Sci Fi Shotgun Reload_01_SFRMS_SCIWPNS
|
|
|
|
private void LoadPlasmaPickupPool(ContentManager content)
|
|
{
|
|
var variants = new[]
|
|
{
|
|
content.Load<SoundEffect>("Sfx/Sci Fi Shotgun/SCIMisc_Sci Fi Shotgun Reload_01_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Sci Fi Shotgun/SCIMisc_Sci Fi Shotgun Reload_02_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Sci Fi Shotgun/SCIMisc_Sci Fi Shotgun Reload_03_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Sci Fi Shotgun/SCIMisc_Sci Fi Shotgun Reload_04_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Sci Fi Shotgun/SCIMisc_Sci Fi Shotgun Reload_05_SFRMS_SCIWPNS"),
|
|
content.Load<SoundEffect>("Sfx/Sci Fi Shotgun/SCIMisc_Sci Fi Shotgun Reload_06_SFRMS_SCIWPNS"),
|
|
};
|
|
|
|
_pickupPool.Add(PickupKind.Plasma, new VariantSoundPool(variants, voicesPerVariant: 1, rng: _random));
|
|
}
|
|
|
|
//GUNMech_Rocket Launcher Reload_01_SFRMS_SCIWPNS
|
|
|
|
// 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 PlayPlayerFire(BulletKind bulletKind)
|
|
{
|
|
if (!_playerGunLimiter.TryConsume())
|
|
return;
|
|
|
|
if (_playerGunPool2.TryGetValue(bulletKind, out VariantSoundPool soundPool) == false)
|
|
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);
|
|
|
|
soundPool.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);
|
|
}
|
|
}
|
|
|
|
public void PlayPickup(PickupKind kind)
|
|
{
|
|
if (_pickupPool.TryGetValue(kind, out VariantSoundPool pool) == false)
|
|
return;
|
|
|
|
float baseVol = 0.85f;
|
|
float vol = baseVol * RandRange(0.95f, 1.05f);
|
|
float pitch = RandRange(-0.04f, 0.04f);
|
|
|
|
pool.Play(
|
|
volume: Clamp01(MasterVolume * SfxVolume * vol),
|
|
pitch: pitch
|
|
);
|
|
}
|
|
|
|
// -----------------------
|
|
// 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;
|
|
}
|
|
} |