Compare commits
2 commits
d53a2a47e2
...
ec3f82c591
| Author | SHA1 | Date | |
|---|---|---|---|
| ec3f82c591 | |||
| 404c749a43 |
11 changed files with 197 additions and 110 deletions
|
|
@ -27,7 +27,7 @@ MonoBehaviour:
|
||||||
GroundedOnly: 0
|
GroundedOnly: 0
|
||||||
Damage: 5
|
Damage: 5
|
||||||
Range: 10
|
Range: 10
|
||||||
FireRate: 2
|
AttacksPerSecond: 1.5
|
||||||
SplashRadius: 0
|
SplashRadius: 0
|
||||||
ChainCount: 0
|
ChainCount: 0
|
||||||
ChainRange: 0
|
ChainRange: 0
|
||||||
|
|
|
||||||
|
|
@ -99,7 +99,6 @@ GameObject:
|
||||||
- component: {fileID: 805962841523123163}
|
- component: {fileID: 805962841523123163}
|
||||||
- component: {fileID: 8853488620519990682}
|
- component: {fileID: 8853488620519990682}
|
||||||
- component: {fileID: 4524938955752569428}
|
- component: {fileID: 4524938955752569428}
|
||||||
- component: {fileID: 42814861218671054}
|
|
||||||
- component: {fileID: -2590971686077483651}
|
- component: {fileID: -2590971686077483651}
|
||||||
m_Layer: 0
|
m_Layer: 0
|
||||||
m_Name: Tower_TeslaCoil
|
m_Name: Tower_TeslaCoil
|
||||||
|
|
@ -147,7 +146,7 @@ MonoBehaviour:
|
||||||
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
|
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
|
||||||
m_Name:
|
m_Name:
|
||||||
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject
|
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject
|
||||||
GlobalObjectIdHash: 280718094
|
GlobalObjectIdHash: 1363936954
|
||||||
InScenePlacedSourceGlobalObjectIdHash: 0
|
InScenePlacedSourceGlobalObjectIdHash: 0
|
||||||
DeferredDespawnTick: 0
|
DeferredDespawnTick: 0
|
||||||
Ownership: 1
|
Ownership: 1
|
||||||
|
|
@ -224,103 +223,6 @@ MonoBehaviour:
|
||||||
arcDuration: 0.12
|
arcDuration: 0.12
|
||||||
segmentsPerArc: 6
|
segmentsPerArc: 6
|
||||||
jitter: 0.2
|
jitter: 0.2
|
||||||
--- !u!82 &42814861218671054
|
|
||||||
AudioSource:
|
|
||||||
m_ObjectHideFlags: 0
|
|
||||||
m_CorrespondingSourceObject: {fileID: 0}
|
|
||||||
m_PrefabInstance: {fileID: 0}
|
|
||||||
m_PrefabAsset: {fileID: 0}
|
|
||||||
m_GameObject: {fileID: 6482414459531823157}
|
|
||||||
m_Enabled: 1
|
|
||||||
serializedVersion: 4
|
|
||||||
OutputAudioMixerGroup: {fileID: 0}
|
|
||||||
m_audioClip: {fileID: 0}
|
|
||||||
m_Resource: {fileID: 0}
|
|
||||||
m_PlayOnAwake: 0
|
|
||||||
m_Volume: 0.5
|
|
||||||
m_Pitch: 1
|
|
||||||
Loop: 0
|
|
||||||
Mute: 0
|
|
||||||
Spatialize: 0
|
|
||||||
SpatializePostEffects: 0
|
|
||||||
Priority: 128
|
|
||||||
DopplerLevel: 1
|
|
||||||
MinDistance: 1
|
|
||||||
MaxDistance: 500
|
|
||||||
Pan2D: 0
|
|
||||||
rolloffMode: 0
|
|
||||||
BypassEffects: 0
|
|
||||||
BypassListenerEffects: 0
|
|
||||||
BypassReverbZones: 0
|
|
||||||
rolloffCustomCurve:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Curve:
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 0
|
|
||||||
value: 1
|
|
||||||
inSlope: 0
|
|
||||||
outSlope: 0
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0.33333334
|
|
||||||
outWeight: 0.33333334
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 1
|
|
||||||
value: 0
|
|
||||||
inSlope: 0
|
|
||||||
outSlope: 0
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0.33333334
|
|
||||||
outWeight: 0.33333334
|
|
||||||
m_PreInfinity: 2
|
|
||||||
m_PostInfinity: 2
|
|
||||||
m_RotationOrder: 4
|
|
||||||
panLevelCustomCurve:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Curve:
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 0
|
|
||||||
value: 0
|
|
||||||
inSlope: 0
|
|
||||||
outSlope: 0
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0.33333334
|
|
||||||
outWeight: 0.33333334
|
|
||||||
m_PreInfinity: 2
|
|
||||||
m_PostInfinity: 2
|
|
||||||
m_RotationOrder: 4
|
|
||||||
spreadCustomCurve:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Curve:
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 0
|
|
||||||
value: 0
|
|
||||||
inSlope: 0
|
|
||||||
outSlope: 0
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0.33333334
|
|
||||||
outWeight: 0.33333334
|
|
||||||
m_PreInfinity: 2
|
|
||||||
m_PostInfinity: 2
|
|
||||||
m_RotationOrder: 4
|
|
||||||
reverbZoneMixCustomCurve:
|
|
||||||
serializedVersion: 2
|
|
||||||
m_Curve:
|
|
||||||
- serializedVersion: 3
|
|
||||||
time: 0
|
|
||||||
value: 1
|
|
||||||
inSlope: 0
|
|
||||||
outSlope: 0
|
|
||||||
tangentMode: 0
|
|
||||||
weightedMode: 0
|
|
||||||
inWeight: 0.33333334
|
|
||||||
outWeight: 0.33333334
|
|
||||||
m_PreInfinity: 2
|
|
||||||
m_PostInfinity: 2
|
|
||||||
m_RotationOrder: 4
|
|
||||||
--- !u!114 &-2590971686077483651
|
--- !u!114 &-2590971686077483651
|
||||||
MonoBehaviour:
|
MonoBehaviour:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
|
||||||
|
|
@ -2222,6 +2222,63 @@ Transform:
|
||||||
m_Children: []
|
m_Children: []
|
||||||
m_Father: {fileID: 1097152085}
|
m_Father: {fileID: 1097152085}
|
||||||
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
|
m_LocalEulerAnglesHint: {x: 0, y: 90, z: 0}
|
||||||
|
--- !u!1 &176580460
|
||||||
|
GameObject:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
serializedVersion: 6
|
||||||
|
m_Component:
|
||||||
|
- component: {fileID: 176580462}
|
||||||
|
- component: {fileID: 176580461}
|
||||||
|
m_Layer: 0
|
||||||
|
m_Name: AudioManager
|
||||||
|
m_TagString: Untagged
|
||||||
|
m_Icon: {fileID: 0}
|
||||||
|
m_NavMeshLayer: 0
|
||||||
|
m_StaticEditorFlags: 0
|
||||||
|
m_IsActive: 1
|
||||||
|
--- !u!114 &176580461
|
||||||
|
MonoBehaviour:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 176580460}
|
||||||
|
m_Enabled: 1
|
||||||
|
m_EditorHideFlags: 0
|
||||||
|
m_Script: {fileID: 11500000, guid: 9ec21c01769ef58d1ac26ba89668eeaa, type: 3}
|
||||||
|
m_Name:
|
||||||
|
m_EditorClassIdentifier: Assembly-CSharp::TD.Audio.AudioManager
|
||||||
|
categories:
|
||||||
|
- category: 0
|
||||||
|
maxVoices: 4
|
||||||
|
volume: 0.5
|
||||||
|
- category: 1
|
||||||
|
maxVoices: 4
|
||||||
|
volume: 0.5
|
||||||
|
- category: 2
|
||||||
|
maxVoices: 4
|
||||||
|
volume: 0.5
|
||||||
|
- category: 3
|
||||||
|
maxVoices: 4
|
||||||
|
volume: 0.5
|
||||||
|
--- !u!4 &176580462
|
||||||
|
Transform:
|
||||||
|
m_ObjectHideFlags: 0
|
||||||
|
m_CorrespondingSourceObject: {fileID: 0}
|
||||||
|
m_PrefabInstance: {fileID: 0}
|
||||||
|
m_PrefabAsset: {fileID: 0}
|
||||||
|
m_GameObject: {fileID: 176580460}
|
||||||
|
serializedVersion: 2
|
||||||
|
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||||
|
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||||
|
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||||
|
m_ConstrainProportionsScale: 0
|
||||||
|
m_Children: []
|
||||||
|
m_Father: {fileID: 0}
|
||||||
|
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||||
--- !u!43 &203092944
|
--- !u!43 &203092944
|
||||||
Mesh:
|
Mesh:
|
||||||
m_ObjectHideFlags: 0
|
m_ObjectHideFlags: 0
|
||||||
|
|
@ -28764,3 +28821,4 @@ SceneRoots:
|
||||||
- {fileID: 1097152085}
|
- {fileID: 1097152085}
|
||||||
- {fileID: 1889390964}
|
- {fileID: 1889390964}
|
||||||
- {fileID: 2139601601}
|
- {fileID: 2139601601}
|
||||||
|
- {fileID: 176580462}
|
||||||
|
|
|
||||||
8
Assets/_Project/Scripts/Audio.meta
Normal file
8
Assets/_Project/Scripts/Audio.meta
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: d11cb1aeddfee3009879738a45665945
|
||||||
|
folderAsset: yes
|
||||||
|
DefaultImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
5
Assets/_Project/Scripts/Audio/AudioCategory.cs
Normal file
5
Assets/_Project/Scripts/Audio/AudioCategory.cs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
// Assets/_Project/Scripts/Audio/AudioCategory.cs
|
||||||
|
namespace TD.Audio
|
||||||
|
{
|
||||||
|
public enum AudioCategory { TowerFire, EnemyHitDeath, UI, Music }
|
||||||
|
}
|
||||||
2
Assets/_Project/Scripts/Audio/AudioCategory.cs.meta
Normal file
2
Assets/_Project/Scripts/Audio/AudioCategory.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 2f652b06e3d150798895893892820cc7
|
||||||
74
Assets/_Project/Scripts/Audio/AudioManager.cs
Normal file
74
Assets/_Project/Scripts/Audio/AudioManager.cs
Normal file
|
|
@ -0,0 +1,74 @@
|
||||||
|
// Assets/_Project/Scripts/Audio/AudioManager.cs
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace TD.Audio
|
||||||
|
{
|
||||||
|
public class AudioManager : MonoBehaviour
|
||||||
|
{
|
||||||
|
[System.Serializable]
|
||||||
|
public struct CategoryConfig
|
||||||
|
{
|
||||||
|
public AudioCategory category;
|
||||||
|
public int maxVoices;
|
||||||
|
[Range(0f, 1f)]
|
||||||
|
public float volume;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static AudioManager Instance { get; private set; }
|
||||||
|
|
||||||
|
[SerializeField] private CategoryConfig[] categories;
|
||||||
|
|
||||||
|
private Dictionary<AudioCategory, AudioSource[]> pools;
|
||||||
|
private Dictionary<AudioCategory, int> indices;
|
||||||
|
|
||||||
|
private void Awake()
|
||||||
|
{
|
||||||
|
if (Instance != null)
|
||||||
|
{
|
||||||
|
Destroy(gameObject);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Instance = this;
|
||||||
|
InitializePools();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnDestroy()
|
||||||
|
{
|
||||||
|
if (Instance == this) Instance = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitializePools()
|
||||||
|
{
|
||||||
|
pools = new Dictionary<AudioCategory, AudioSource[]>();
|
||||||
|
indices = new Dictionary<AudioCategory, int>();
|
||||||
|
|
||||||
|
foreach (var config in categories)
|
||||||
|
{
|
||||||
|
var pool = new AudioSource[config.maxVoices];
|
||||||
|
for (int i = 0; i < config.maxVoices; i++)
|
||||||
|
{
|
||||||
|
var src = gameObject.AddComponent<AudioSource>();
|
||||||
|
src.playOnAwake = false;
|
||||||
|
src.volume = config.volume;
|
||||||
|
pool[i] = src;
|
||||||
|
}
|
||||||
|
pools[config.category] = pool;
|
||||||
|
indices[config.category] = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Play(AudioClip clip, AudioCategory category, float pitch = 1f)
|
||||||
|
{
|
||||||
|
if (clip == null) return;
|
||||||
|
if (!pools.TryGetValue(category, out var pool)) return;
|
||||||
|
|
||||||
|
int idx = indices[category];
|
||||||
|
var src = pool[idx % pool.Length];
|
||||||
|
src.pitch = pitch;
|
||||||
|
src.clip = clip;
|
||||||
|
src.Play();
|
||||||
|
indices[category] = idx + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
2
Assets/_Project/Scripts/Audio/AudioManager.cs.meta
Normal file
2
Assets/_Project/Scripts/Audio/AudioManager.cs.meta
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 9ec21c01769ef58d1ac26ba89668eeaa
|
||||||
36
Assets/_Project/Scripts/Audio/README.md
Normal file
36
Assets/_Project/Scripts/Audio/README.md
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
# Audio System
|
||||||
|
|
||||||
|
Centralised voice-limited audio for the game. Lives in `Assets/_Project/Scripts/Audio/`.
|
||||||
|
|
||||||
|
## How it works
|
||||||
|
|
||||||
|
`AudioManager` is a per-scene MonoBehaviour singleton. On `Awake` it pre-allocates a pool of `AudioSource` components (on its own GameObject) for each sound category. Callers request playback via `AudioManager.Instance.Play(clip, category, pitch)` — the manager picks the next source in that category's pool using round-robin, interrupting the oldest sound if all voices are busy.
|
||||||
|
|
||||||
|
## Categories (`AudioCategory` enum)
|
||||||
|
|
||||||
|
| Category | Typical use |
|
||||||
|
|---|---|
|
||||||
|
| `TowerFire` | Tower attack sounds |
|
||||||
|
| `EnemyHitDeath` | Enemy damage and death sounds |
|
||||||
|
| `UI` | Button clicks, placement confirmation, etc. |
|
||||||
|
| `Music` | Background music |
|
||||||
|
|
||||||
|
Voice limits and volume per category are configured in the Inspector on the `AudioManager` scene GameObject.
|
||||||
|
|
||||||
|
## Scene setup
|
||||||
|
|
||||||
|
An empty GameObject named `AudioManager` must exist in each gameplay scene with the `AudioManager` component attached. Configure the `Categories` array in the Inspector — one entry per `AudioCategory` value.
|
||||||
|
|
||||||
|
Suggested defaults:
|
||||||
|
- TowerFire: 4 voices, volume 1.0
|
||||||
|
- EnemyHitDeath: 8 voices, volume 1.0
|
||||||
|
- UI: 4 voices, volume 1.0
|
||||||
|
- Music: 2 voices, volume 0.8
|
||||||
|
|
||||||
|
## Adding a new sound-emitting component
|
||||||
|
|
||||||
|
1. Get a reference to an `AudioClip` via `[SerializeField]`
|
||||||
|
2. Call `AudioManager.Instance?.Play(clip, AudioCategory.YourCategory)` at the point the sound should trigger
|
||||||
|
3. Pitch randomization (if desired) is the caller's responsibility: `Random.Range(minPitch, maxPitch)` passed as the third argument
|
||||||
|
|
||||||
|
See `TeslaTowerFireSound.cs` in `Scripts/Combat/` as a reference implementation.
|
||||||
7
Assets/_Project/Scripts/Audio/README.md.meta
Normal file
7
Assets/_Project/Scripts/Audio/README.md.meta
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
fileFormatVersion: 2
|
||||||
|
guid: 4acf87ebbb79a6ce482e6e4767d27b41
|
||||||
|
TextScriptImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
// Assets/_Project/Scripts/Combat/TeslaTowerFireSound.cs
|
// Assets/_Project/Scripts/Combat/TeslaTowerFireSound.cs
|
||||||
|
using TD.Audio;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
|
||||||
namespace TD.Combat
|
namespace TD.Combat
|
||||||
|
|
@ -14,7 +15,6 @@ namespace TD.Combat
|
||||||
/// as the Tesla Coil gains more audio (idle hum, charge-up, etc.).
|
/// as the Tesla Coil gains more audio (idle hum, charge-up, etc.).
|
||||||
/// </remarks>
|
/// </remarks>
|
||||||
[RequireComponent(typeof(TowerCombat))]
|
[RequireComponent(typeof(TowerCombat))]
|
||||||
[RequireComponent(typeof(AudioSource))]
|
|
||||||
public class TeslaTowerFireSound : MonoBehaviour
|
public class TeslaTowerFireSound : MonoBehaviour
|
||||||
{
|
{
|
||||||
[Tooltip("Sound played each time the coil discharges.")]
|
[Tooltip("Sound played each time the coil discharges.")]
|
||||||
|
|
@ -25,12 +25,10 @@ namespace TD.Combat
|
||||||
[SerializeField] private float maxPitch = 1.07f;
|
[SerializeField] private float maxPitch = 1.07f;
|
||||||
|
|
||||||
private TowerCombat combat;
|
private TowerCombat combat;
|
||||||
private AudioSource audioSource;
|
|
||||||
|
|
||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
combat = GetComponent<TowerCombat>();
|
combat = GetComponent<TowerCombat>();
|
||||||
audioSource = GetComponent<AudioSource>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnEnable()
|
private void OnEnable()
|
||||||
|
|
@ -45,12 +43,7 @@ namespace TD.Combat
|
||||||
|
|
||||||
private void HandleAreaFired(Vector3[] positions)
|
private void HandleAreaFired(Vector3[] positions)
|
||||||
{
|
{
|
||||||
if (fireClip != null)
|
AudioManager.Instance?.Play(fireClip, AudioCategory.TowerFire, Random.Range(minPitch, maxPitch));
|
||||||
{
|
|
||||||
audioSource.pitch = Random.Range(minPitch, maxPitch);
|
|
||||||
audioSource.clip = fireClip;
|
|
||||||
audioSource.Play();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue