Files
5.24BuYu/Assets/MyGame/Scripts/fishResources/FishResourcesData.cs
T
2026-10-08 17:04:24 +08:00

240 lines
9.2 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using Newtonsoft.Json;
using Spine.Unity;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using static UnityEngine.AddressableAssets.Addressables;
[Serializable]
public class FishResourcesData
{
public int fishNumber;
public string prefabFishResourcesPath;
public string dieEffectAssets;
/// <summary>
/// 出场音频
/// </summary>
public List<int> showAudio;
/// <summary>
/// 移动音频
/// </summary>
public List<int> moveAudio;
/// <summary>
/// 死亡音效 1,2,3
/// </summary>
public List<int> dieAudio;
/// <summary>
/// 爆奖音效
/// </summary>
public Dictionary<string, int> dieGlodAduio;
const string prefabFish_AALabel="FishPrefab";
const string dieSpine_AALabel = "DieSpine";
const string Sprite_AALabel = "TuJian";
private static Dictionary<string,int> FishResourcesPrefabsDic ;//prefabpath--id
private static Dictionary<string,int> FishResourcesSpineDieDic ;//dieSpinepath--id
private static Dictionary<string,int> FishResourcesSpriteDic;//Spritepath--id
static FishResourcesData()
{
Init();
}
async static void Init()
{
string prefabFishPath = Resources.Load<TextAsset>("tbfishresources").text;
var v = JsonConvert.DeserializeObject<List<FishResourcesData>>(prefabFishPath);
FishResourcesPrefabsDic = new Dictionary<string, int>();
fishResourcesDatasDic = new Dictionary<int, FishResourcesData>();
FishResourcesSpineDieDic = new Dictionary<string, int>();
FishResourcesSpriteDic = new Dictionary<string, int>();
foreach (var item in v)
{
if (item.prefabFishResourcesPath != null && item.prefabFishResourcesPath != "")
{
Debug.Log($"添加鱼资源数据: {item.fishNumber} - {item.prefabFishResourcesPath}");
FishResourcesPrefabsDic.Add(item.prefabFishResourcesPath, item.fishNumber);
FishResourcesSpriteDic.Add(item.prefabFishResourcesPath, item.fishNumber);
if (item.dieEffectAssets != null && item.dieEffectAssets != "")
{
FishResourcesSpineDieDic.Add(item.dieEffectAssets, item.fishNumber);
}
fishResourcesDatasDic.Add(item.fishNumber, item);
}
}
}
private static Dictionary<int, GameObject> fishPrefabDic;//id--prefabs
public static Dictionary<int, FishResourcesData> fishResourcesDatasDic;//id--FishResourcesData
public static Dictionary<int, Sprite> fishResourcesSpritesDic;//id--Sprite
private static Dictionary<int, SkeletonDataAsset> diePrefabDic;//id--SkeletonDataAsset
// ⭐ 句柄显式管理(修复"包只增不减"的根源):
// 旧实现加载完立即 Release 句柄,但 fishPrefabDic 还持有 prefab 引用 ——
// 包没被卸载全靠 AudioResourcesData 泄漏的音频句柄"误打误撞"撑着(音频物理上就在鱼包里)。
// 现在:加载时保存句柄(prefab/dieSpine/sprite 三类),离房时 UnLoadFishAssetsData 统一 Release,
// 引用归零后鱼包真正从内存卸载 —— 依次进所有玩法不再累加内存。
private static readonly List<AsyncOperationHandle> _fishHandles = new List<AsyncOperationHandle>();
public static async Task LoadFishAssetsData()
{
// 清空对象池
Pool.Instance.Clear();
fishPrefabDic = new Dictionary<int, GameObject>();
diePrefabDic = new Dictionary<int, SkeletonDataAsset>();
fishResourcesSpritesDic = new Dictionary<int, Sprite>();
// ⭐ 防御:上一轮句柄未释放(如离房流程被跳过)时先释放,避免引用计数累加
foreach (var h in _fishHandles)
{
if (h.IsValid()) Addressables.Release(h);
}
_fishHandles.Clear();
// ---------------- 1. 预下载所有依赖资源(关键) ----------------
var labels = new List<string>
{
prefabFish_AALabel,
dieSpine_AALabel,
Sprite_AALabel,
GameManager.Instance.gameData.currGameType.ToString()
};
Debug.Log("开始预下载所有鱼资源依赖...");
var depHandle = Addressables.DownloadDependenciesAsync(labels, MergeMode.Intersection);
await depHandle.Task;
Addressables.Release(depHandle);
Debug.Log("依赖资源预下载完成!");
// ---------------- 2. 加载 Prefab ----------------
var prefabKeys = new List<string> { prefabFish_AALabel, GameManager.Instance.gameData.currGameType.ToString() };
var prefabHandle = Addressables.LoadAssetsAsync<GameObject>(prefabKeys, prefab =>
{
if (FishResourcesPrefabsDic.TryGetValue(prefab.name, out int id))
{
fishPrefabDic[id] = prefab;
var mc = prefab.GetComponent<MonsterContral>();
if (mc != null)
mc.fishTypeID = id;
// ⭐ 统一用 Pool.Instance 的 poolObj 作为父节点(不再用 CreateFishManager.poolRoot),
// 这样 Pool.Clear() 销毁 poolObj 时能连带销毁所有 poolList_XXX 子节点,避免残留
Pool.Instance.dic[id] = new PoolData(prefab, Pool.Instance.EnsurePoolRoot(), id);
}
}, MergeMode.Intersection);
await prefabHandle.Task;
// ⭐ 不再立即 Release:保存句柄保持包存活,离房时统一卸载
_fishHandles.Add(prefabHandle);
Debug.Log($"Prefab 加载完成,共 {fishPrefabDic.Count} 个");
// ---------------- 3. 加载死亡 Spine 动效 ----------------
// 注意:某些游戏类型下 Addressables 中 "DieSpine"+"游戏类型" 两个 label 可能没有交集资源,
// 会抛 InvalidKeyException。这里用 try-catch 容错,避免单个资源类型加载失败阻塞整体流程。
try
{
var dieKeys = new List<string> { dieSpine_AALabel, GameManager.Instance.gameData.currGameType.ToString() };
var dieHandle = Addressables.LoadAssetsAsync<SkeletonDataAsset>(dieKeys, data =>
{
if (FishResourcesSpineDieDic.TryGetValue(data.name, out int id))
{
diePrefabDic[id] = data;
}
}, MergeMode.Intersection);
await dieHandle.Task;
_fishHandles.Add(dieHandle);
Debug.Log($"死亡 Spine 加载完成,共 {diePrefabDic.Count} 个");
}
catch (Exception e)
{
Debug.LogWarning($"[FishResourcesData] 死亡 Spine 加载失败(游戏类型={GameManager.Instance.gameData.currGameType}),跳过此项: {e.Message}");
}
// ---------------- 4. 加载鱼 Sprite ----------------
try
{
var spriteKeys = new List<string> { Sprite_AALabel, GameManager.Instance.gameData.currGameType.ToString() };
var spriteHandle = Addressables.LoadAssetsAsync<Sprite>(spriteKeys, data =>
{
if (FishResourcesSpriteDic.TryGetValue(data.name, out int id))
{
fishResourcesSpritesDic[id] = data;
}
}, MergeMode.Intersection);
await spriteHandle.Task;
_fishHandles.Add(spriteHandle);
Debug.Log($"Sprite 加载完成,共 {fishResourcesSpritesDic.Count} 个");
}
catch (Exception e)
{
Debug.LogWarning($"[FishResourcesData] Sprite 加载失败(游戏类型={GameManager.Instance.gameData.currGameType}),跳过此项: {e.Message}");
}
Debug.Log("所有鱼资源加载完毕!");
}
public static Task UnLoadFishAssetsData()
{
// ⭐ 真正的卸载:释放加载时保存的全部句柄(引用归零后鱼包才会真正卸载)。
// 旧实现"重新 Load 一遍拿句柄再 Release"是净 0 操作,什么都卸不掉。
Pool.Instance.Clear();
foreach (var h in _fishHandles)
{
if (h.IsValid())
Addressables.Release(h);
}
_fishHandles.Clear();
// ⭐ 清空字典(包卸载后对象已失效,残留引用会指向已销毁资源)
fishPrefabDic?.Clear();
diePrefabDic?.Clear();
fishResourcesSpritesDic?.Clear();
Debug.Log($"[FishResourcesData] 鱼资源卸载完成");
return Task.CompletedTask;
}
public static GameObject GetFishPrefab(int fishNumber)
{
if (fishPrefabDic != null && fishPrefabDic.ContainsKey(fishNumber))
{
return fishPrefabDic[fishNumber];
}
else
{
Debug.LogError($"鱼Prefab未找到: {fishNumber}");
return null;
}
}
public static SkeletonDataAsset GetFishDieSpine(int fishNumber)
{
if (diePrefabDic != null && diePrefabDic.ContainsKey(fishNumber))
{
return diePrefabDic[fishNumber];
}
else
{
Debug.LogError($"鱼死亡动效未找到: {fishNumber}");
return null;
}
}
}