Audio.cs 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. /**
  2. * 魔力宝贝图档解析脚本 - CGTool
  3. *
  4. * @Author HonorLee (dev@honorlee.me)
  5. * @Version 1.0 (2023-08-26)
  6. * @License GPL-3.0
  7. *
  8. * AudioTool.cs 音频工具
  9. * 本工具用于加载音频AudioClip,音频文件位于Assets/Resources/Audio目录下并使用Resources.Load加载
  10. * 请将Crossgate的音频目录bgm、se拷贝到Assets/Resources/Audio目录下
  11. * 如有其他需要可调整加载方式
  12. */
  13. using System;
  14. using System.Collections;
  15. using System.Collections.Generic;
  16. using System.IO;
  17. using Unity.VisualScripting;
  18. using UnityEngine;
  19. using UnityEngine.Networking;
  20. namespace CrossgateToolkit
  21. {
  22. public class EffectPlayer : MonoBehaviour
  23. {
  24. public AudioSource audioSource;
  25. public delegate void OnAudioPlayEnd();
  26. public OnAudioPlayEnd onAudioPlayEnd;
  27. private void Awake()
  28. {
  29. audioSource = gameObject.AddComponent<AudioSource>();
  30. audioSource.loop = false;
  31. audioSource.playOnAwake = false;
  32. }
  33. public void Play(AudioClip clip)
  34. {
  35. audioSource.clip = clip;
  36. audioSource.Play();
  37. StartCoroutine(wait(clip.length));
  38. }
  39. IEnumerator wait(float length)
  40. {
  41. yield return new WaitForSeconds(length + 0.3f);
  42. onAudioPlayEnd?.Invoke();
  43. }
  44. }
  45. public static class Audio
  46. {
  47. // 背景音频缓存
  48. private static Dictionary<int, AudioClip> _bgmDic = new Dictionary<int, AudioClip>();
  49. // 声效音频缓存
  50. private static Dictionary<int, AudioClip> _effectDic = new Dictionary<int, AudioClip>();
  51. private static Queue<EffectPlayer> _effectPlayerPool = new Queue<EffectPlayer>();
  52. private static GameObject _effectPlayerContainer;
  53. private static int lastEffectId = -1;
  54. private static int lastEffectTime = -1;
  55. public static float EffectVolume = 1f;
  56. public enum Type
  57. {
  58. BGM,
  59. EFFECT
  60. }
  61. // 播放指定类型、编号的音频AudioClip
  62. public static void Play(AudioSource audioSource,Type type, int id)
  63. {
  64. // 对于同时间大量同一音效的播放,只播放一次
  65. if (type == Type.EFFECT && id == lastEffectId && Time.time - lastEffectTime < 0.1f) return;
  66. AudioClip audioClip;
  67. Dictionary<int,AudioClip> dic = type == Type.BGM ? _bgmDic : _effectDic;
  68. if (dic.TryGetValue(id, out audioClip))
  69. {
  70. _playAudio(type,audioSource, audioClip);
  71. }
  72. else
  73. {
  74. Dictionary<int,string> map = type == Type.BGM ? _bgmMap : _effectMap;
  75. if(map.TryGetValue(id, out string audioName))
  76. {
  77. string path = type == Type.BGM ? CGTool.PATH.BGM : CGTool.PATH.AUDIO;
  78. if (string.IsNullOrEmpty(path))
  79. {
  80. path = type == Type.BGM ? "Audio/bgm" : "Audio/se";
  81. audioClip = Resources.Load<AudioClip>(path + "/" + audioName);
  82. if (audioClip == null) return;
  83. dic[id] = audioClip;
  84. _playAudio(type,audioSource, audioClip);
  85. }
  86. else
  87. {
  88. DirectoryInfo directoryInfo = new DirectoryInfo(path);
  89. if(!directoryInfo.Exists) return;
  90. FileInfo[] files = directoryInfo.GetFiles(audioName + ".wav", SearchOption.AllDirectories);
  91. if (files.Length > 0)
  92. {
  93. string filePath = files[0].FullName;
  94. CoroutineRunner.instance.StartCoroutine(LoadAudioClipAsync(filePath, loadedAudioClip =>
  95. {
  96. if (loadedAudioClip != null)
  97. {
  98. dic[id] = loadedAudioClip;
  99. _playAudio(type,audioSource, loadedAudioClip);
  100. }
  101. }));
  102. }
  103. }
  104. }
  105. }
  106. }
  107. private static void _playAudio(Type type,AudioSource audioSource, AudioClip audioClip)
  108. {
  109. if (type == Type.EFFECT && audioSource == null)
  110. {
  111. if(_effectPlayerContainer==null) _effectPlayerContainer = new GameObject("EffectPlayerContainer");
  112. EffectPlayer effectPlayer = null;
  113. if (_effectPlayerPool.Count > 0)
  114. {
  115. effectPlayer = _effectPlayerPool.Dequeue();
  116. }
  117. else
  118. {
  119. effectPlayer = new GameObject("EffectPlayer").AddComponent<EffectPlayer>();
  120. effectPlayer.transform.SetParent(_effectPlayerContainer.transform);
  121. effectPlayer.onAudioPlayEnd = () =>
  122. {
  123. effectPlayer.audioSource.clip = null;
  124. _effectPlayerPool.Enqueue(effectPlayer);
  125. };
  126. }
  127. effectPlayer.audioSource.volume = EffectVolume;
  128. effectPlayer.Play(audioClip);
  129. }
  130. else
  131. {
  132. audioSource.Stop();
  133. audioSource.clip = audioClip;
  134. audioSource.Play();
  135. }
  136. }
  137. private delegate void AudioClipLoaded(AudioClip audioClip);
  138. private static IEnumerator LoadAudioClipAsync(string filePath, AudioClipLoaded onAudioLoaded)
  139. {
  140. if (File.Exists(filePath))
  141. {
  142. string audioURL = "file://" + filePath;
  143. using (UnityWebRequest www = UnityWebRequestMultimedia.GetAudioClip(audioURL, AudioType.UNKNOWN))
  144. {
  145. yield return www.SendWebRequest();
  146. if (www.result == UnityWebRequest.Result.Success)
  147. {
  148. AudioClip audioClip = DownloadHandlerAudioClip.GetContent(www);
  149. onAudioLoaded?.Invoke(audioClip);
  150. }
  151. else
  152. {
  153. onAudioLoaded?.Invoke(null);
  154. }
  155. }
  156. }
  157. else
  158. {
  159. onAudioLoaded?.Invoke(null);
  160. }
  161. }
  162. private static Dictionary<int, string> _bgmMap = new Dictionary<int, string>()
  163. {
  164. [200] = "cgbgm_m0",
  165. [201] = "cgbgm_m1",
  166. [202] = "cgbgm_m2",
  167. [203] = "cgbgm_m3",
  168. [204] = "cgbgm_m4",
  169. [209] = "cgbgm_f0",
  170. [210] = "cgbgm_f1",
  171. [211] = "cgbgm_f2",
  172. [212] = "cgbgm_d0",
  173. [213] = "cgbgm_d1",
  174. [214] = "cgbgm_d2",
  175. [215] = "cgbgm_d3",
  176. [216] = "cgbgm_d4",
  177. [205] = "cgbgm_b0",
  178. [206] = "cgbgm_b1",
  179. [207] = "cgbgm_b2",
  180. [208] = "cgbgm_b3",
  181. [217] = "cgbgm_t0",
  182. [219] = "exbgm_s0",
  183. [220] = "exbgm_f0",
  184. [221] = "exbgm_m0",
  185. [222] = "v2bgm_f0",
  186. [223] = "v2bgm_m0",
  187. [224] = "v2bgm_ex",
  188. [225] = "v2bgm_ex",
  189. [226] = "puk2_battle1",
  190. [227] = "puk2_battle2",
  191. [228] = "puk2_field1",
  192. [229] = "puk2_mati",
  193. [230] = "puk2_sinden",
  194. [231] = "puk2_yama",
  195. [232] = "puk2_haikyo",
  196. [233] = "puk2_m_town",
  197. [234] = "puk2_OP",
  198. [235] = "puk3_battle1",
  199. [236] = "puk3_battle2",
  200. [237] = "puk3_dungeon",
  201. [238] = "puk3_kame",
  202. [239] = "puk3_kujira",
  203. [240] = "puk3_kumo",
  204. [241] = "puk3_love",
  205. [242] = "puk3_playerbattle",
  206. [243] = "PUK3_title",
  207. };
  208. private static Dictionary<int, string> _effectMap = new Dictionary<int, string>()
  209. {
  210. [1] = "cgnat00",//环境音 流水
  211. [2] = "cgnat01",//环境音 流水
  212. [3] = "cgnat02",//环境音 港口船边
  213. [4] = "cgnat03",//环境音 风声(火山顶那种)
  214. [5] = "cgnat04",//环境音 (火山)
  215. [6] = "cgnat05a",//环境音 洞穴滴水
  216. [7] = "cgnat05b",//环境音 洞穴滴水
  217. [8] = "cgnat06a",//环境音 草丛
  218. [9] = "cgnat06b",//环境音 草丛
  219. [10] = "cgnat07",//环境音 树林
  220. [11] = "cgnat08",//环境音 树林
  221. [12] = "cgnat09",//环境音 瀑布
  222. [13] = "cgnat10",//环境音 篝火
  223. [14] = "cgnat11",//环境音 火旁
  224. [15] = "exnat00",//环境音 穿行驶时甲板上
  225. [16] = "v2mon150a",//环境音 雷声
  226. [17] = "34sand_clock",//环境音 不知道
  227. [18] = "35sand_clock",//环境音 不知道
  228. [19] = "36wind",//环境音 不知道
  229. [20] = "37bird",//环境音 鸟叫
  230. [21] = "puk3_Wind01",// 无
  231. [22] = "puk3_Wind02",// 无
  232. [23] = "puk3_Wind03",// 无
  233. [24] = "puk3_gaya01",//无
  234. [25] = "puk3_drop01",//无
  235. [26] = "puk3_drop02",//无
  236. [51] = "cgsys00",//鼠标左键点击
  237. [52] = "cgsys01",//鼠标左键点击道具
  238. [53] = "cgsys02",//点击登录
  239. [54] = "cgsys03",//点击返回
  240. [55] = "cgsys04",//点选不能使用的道具
  241. [56] = "cgsys05",//弹窗
  242. [57] = "cgsys06",//选择道具使用目标
  243. [58] = "cgsys07",//翻页
  244. [59] = "cgsys08",//登录角色
  245. [60] = "cgsys09",//登出
  246. [61] = "cgsys10a",//暗杀
  247. [62] = "cgsys10b",//暗杀
  248. [63] = "cgsys11",//邮件
  249. [64] = "cgsys12",//宠物升级
  250. [65] = "cgsys13a",//未知
  251. [66] = "cgsys13b",//丢钱在地上
  252. [67] = "cgsys13c",//丢钱在地上
  253. [68] = "cgsys14",//捡起地上物品
  254. [69] = "cgsys15",//扔地上物品
  255. [71] = "cgsys17",//加入队伍
  256. [72] = "cgsys18",//退出队伍
  257. [73] = "cgsys19",//换名片
  258. [74] = "cgsys20",//频道说话
  259. [75] = "cgsys21",//未知
  260. [76] = "cgsys22",//打开道具如果里面没东西
  261. [77] = "cgsys23",//使用料理
  262. [78] = "cgsys24",//使用道具给队友
  263. [79] = "cgsys25",//使用道具给队友
  264. [101] = "cgply00a",
  265. [102] = "cgply00b",
  266. [103] = "cgply01a",
  267. [104] = "cgply01b",
  268. [105] = "cgply02a",
  269. [106] = "cgply02b",
  270. [107] = "cgply03a",//空手MIS
  271. [108] = "cgply03b",
  272. [109] = "cgply04a",
  273. [110] = "cgply04b",
  274. [111] = "cgply05a",
  275. [112] = "cgply05b",
  276. [113] = "cgply06a1",
  277. [114] = "cgply06b1",
  278. [115] = "cgply06a2",
  279. [116] = "cgply06b2",//冰冻5-7(冰的声音先出 然后是这个)
  280. [117] = "cgply07a",
  281. [118] = "cgply07b",
  282. [131] = "cgply06a2",
  283. [132] = "cgply06b2",
  284. [133] = "cgply11a",
  285. [134] = "cgply11b",
  286. [135] = "cgply12a",
  287. [136] = "cgply12b",
  288. [137] = "cgply13a",
  289. [138] = "cgply13b",
  290. [139] = "cgply14a",
  291. [140] = "cgply14b",
  292. [141] = "cgply15",
  293. [142] = "cgply16",
  294. [143] = "cgply17",
  295. [147] = "cgply00a",
  296. [150] = "cgply11b",
  297. [151] = "cgmon00a",
  298. [152] = "cgmon00b",
  299. [153] = "cgmon01",
  300. [154] = "cgmon02a",
  301. [155] = "cgmon02b",
  302. [156] = "cgmon03b",
  303. [157] = "cgmon10",
  304. [158] = "cgmon20",
  305. [159] = "cgmon24",
  306. [160] = "cgmon30",
  307. [161] = "cgmon31",
  308. [162] = "cgmon41",
  309. [163] = "cgmon43",
  310. [164] = "cgmon50a",
  311. [165] = "cgmon50b",
  312. [166] = "cgmon51",
  313. [167] = "cgmon52",
  314. [168] = "cgmon60",
  315. [169] = "cgmon61",
  316. [171] = "cgmon63",
  317. [172] = "cgmon90",
  318. [173] = "cgmon91",
  319. [174] = "cgmon92",
  320. [175] = "cgmon93",
  321. [180] = "cgmon_bs1",
  322. [181] = "cgmon_bs2",
  323. [182] = "cgmon_bs3",
  324. [183] = "cgmon_bs4",
  325. [184] = "cgmon_bh1",
  326. [185] = "cgmon_bh2",
  327. [186] = "cgmon_bh3",
  328. [187] = "cgmon_bh4",
  329. [190] = "cgmon_m00",
  330. [191] = "cgmon_m01",
  331. [192] = "cgmon_m02",
  332. [198] = "cgmon_sample01",
  333. [199] = "cgmon_sample02",
  334. [200] = "cgmon_sample03",
  335. [201] = "cgbtl00",//遇敌进入战斗
  336. [202] = "cgbtl01",//倒数快到时
  337. [204] = "cgbtl03",//召唤宠物
  338. [205] = "cgbtl04",//收回宠物
  339. [206] = "cgbtl05",//战斗中技能升级
  340. [207] = "cgbtl06",//击飞
  341. [208] = "cgbtl07",//击飞过程碰壁
  342. [209] = "cgbtl08",//战斗中换武器
  343. [210] = "cgbtl09",//战斗中换位置
  344. [211] = "cgbtl10",//逃跑
  345. [212] = "cgbtl11",//封印扔卡
  346. [213] = "cgbtl12",//封印捕捉中
  347. [214] = "cgbtl13",//装备击碎
  348. [215] = "cgbtl14",//死亡
  349. [216] = "cgbtl15",//未知
  350. [217] = "cgbtl16",//使用道具前置
  351. [218] = "cgbtl17",//怪物死亡气泡
  352. [251] = "cgefc00",//物理技能使用前置(绿光)
  353. [252] = "cgefc01",//未知
  354. [253] = "cgefc02",//反击
  355. [254] = "cgefc03",//气功弹飞的过程中
  356. [255] = "cgefc04",//气功弹打到身上
  357. [256] = "cgefc05",//明镜止水出恢复数字时
  358. [257] = "cgefc06",//偷窃成功
  359. [258] = "cgefc07",//偷窃失败
  360. [259] = "cgefc08",//魔法施法
  361. [260] = "cgefc09",//状态技能 各种吸无反施法
  362. [261] = "cgefc10",//传教施法
  363. [262] = "cgefc11",//陨石魔法下落
  364. [263] = "cgefc12",//10级陨石打身上时
  365. [264] = "cgefc13",//冰冻魔法为造成伤害的前置动画声音
  366. [266] = "cgefc15",//1-4火
  367. [267] = "cgefc16",//5-7火
  368. [268] = "cgefc17",//1-4风
  369. [269] = "cgefc18",//5-7风
  370. [270] = "cgefc19",//吸血造成伤害时
  371. [271] = "cgefc20",//吸血回复血量时
  372. [272] = "cgefc21",//咒术怪物时气泡
  373. [273] = "cgefc22",//毒咒掉血时
  374. [274] = "cgefc23",//酒醉掉魔时
  375. [275] = "cgefc24",//祈祷魔封动画展开时
  376. [276] = "cgefc25",//属性反转
  377. [277] = "cgefc26",//功无攻反等套身上时
  378. [278] = "cgefc27",//补血魔法补血时
  379. [279] = "cgefc28",//恢复魔法恢复时
  380. [280] = "cgefc29",//气绝
  381. [281] = "cgefc30",//洁净
  382. [282] = "cgefc31",//10火
  383. [283] = "cgefc32",//跳舞10级
  384. [284] = "cgefc33",//祭死
  385. [285] = "cgefc34",//未知
  386. [286] = "cgefc35",//功无魔无抵挡时
  387. [287] = "cgefc36",//正常反击
  388. [288] = "cgefc37a",//自爆变大中
  389. [289] = "cgefc37b",//自爆准备爆炸
  390. [290] = "cgefc37c",//自爆爆炸
  391. [291] = "cgefc38",//恢复套的过程
  392. [296] = "v2monex1",
  393. [297] = "v2monex2",
  394. [298] = "v2monex3",
  395. [300] = "v2mon100",
  396. [301] = "v2mon110",
  397. [302] = "v2mon111a",
  398. [303] = "v2mon111b",
  399. [304] = "v2mon120",
  400. [305] = "v2mon121a",
  401. [306] = "v2mon121b",
  402. [307] = "v2mon121c",
  403. [308] = "v2mon130",
  404. [309] = "v2mon140",
  405. [310] = "v2mon150a",
  406. [311] = "v2mon150b",
  407. [312] = "v2mon161",
  408. [313] = "v2mon170a",
  409. [314] = "v2mon170b",
  410. [315] = "v2mon171a",
  411. [316] = "v2mon171b",
  412. [317] = "v2mon190",
  413. [318] = "v2mon191",
  414. [319] = "v2monex0",
  415. [400] = "01small_amae_new",
  416. [401] = "02small_normal",
  417. [402] = "02small_normal_new",
  418. [403] = "03small_iyaiya",
  419. [404] = "03small_iyaiya_new",
  420. [405] = "04fish_normal",
  421. [406] = "05fish_shout",
  422. [407] = "06fish_amae",
  423. [408] = "09kame_amae",
  424. [409] = "10yagi_shout",
  425. [410] = "11yagi_normal",
  426. [411] = "12yagi_amae",
  427. [412] = "13bird_normal",
  428. [413] = "14bird_shout",
  429. [414] = "15bird_amae",
  430. [415] = "16fish_normal",
  431. [416] = "17fish_shout",
  432. [417] = "18kame_normal",
  433. [418] = "19kame_shout",
  434. [419] = "20animal_normal",
  435. [420] = "21animal_shout",
  436. [421] = "22bird_normal",
  437. [422] = "23bird_shout",
  438. [423] = "24Monstor",
  439. [424] = "25_1_off",
  440. [425] = "26ground_on",
  441. [426] = "27ground_off",
  442. [427] = "28_water_on",
  443. [428] = "29_water_of",
  444. [429] = "30fire_on",
  445. [430] = "31fire_of",
  446. [431] = "32_wind_on",
  447. [432] = "32_wind_on2",
  448. [433] = "33_wind_off",
  449. [435] = "36wind",
  450. [436] = "37bird",
  451. [437] = "38make_gild",//升级
  452. [438] = "39levelup",
  453. [500] = "cgply10a",
  454. [501] = "cgply10b",
  455. };
  456. }
  457. }