Files
5.24BuYu/Assets/MyGame/Scripts/fishResources/TurretResources.cs
T
2026-08-28 19:42:54 +08:00

275 lines
13 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 System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using static UnityEngine.AddressableAssets.Addressables;
/// <summary>
/// 战神预制体用途:战神有两个预制体(展示/游戏内使用),名字相同,靠 Addressables 子标签区分。
/// - Display:Default 子标签(大厅/商城预览模型)
/// - GamePlay:ZSYX 子标签(座位上替代普通炮台的使用模型)
/// </summary>
public enum ZhanShenUsage
{
/// <summary>展示用:大厅/商城预览模型(Default 子标签加载)</summary>
Display = 0,
/// <summary>游戏内用:座位上替代普通炮台的模型(ZSYX 子标签加载)</summary>
GamePlay = 1
}
[Serializable]
public class TurretResourcesData
{
public int turretNumber;
public string turretName; // 中文名称(如"深海之眼")
public int turretType; // 1=普通炮台 2=战神 3=翅膀
public string prefabTurretResourcesPath; // 资源路径(prefab/spine/sprite 共用名)
public int animationType; // 1=spine 2=animator 3=animation
public int prefabType; // 预制体类型(战神分类:1=国色天香 2=西游传说 3=山海奇闻;炮台/翅膀=0)
public int attackAudioID; // 攻击音效 ID
public List<int> bulletID; // 子弹 ID 列表
// ---- Addressables 标签 ----
const string turret_AALabel = "PTCBZS"; // 炮台统一标签(主标签:炮台/翅膀/战神共用)
const string defaultSubLabel = "Default"; // 展示子标签(展示用预制体:普通炮台/翅膀/战神展示)
const string zhanShenGameSubLabel = "ZSYX"; // 战神游戏内子标签(战神的使用预制体,与展示同名靠标签区分)
// ---- 路径→ID 映射(用于 Addressables 加载时反查) ----
private static Dictionary<string, int> turretPrefabPathDic; // prefabPath → turretNumber
private static Dictionary<string, int> turretSpritePathDic; // spritePath → turretNumber
// ---- ID→数据/资源 映射 ----
public static Dictionary<int, TurretResourcesData> turretDataDic; // id → data
private static Dictionary<int, GameObject> turretPrefabDic; // id → 展示用预制体(Default 子标签)
private static Dictionary<int, GameObject> turretGamePrefabDic; // id → 战神游戏内使用预制体(ZSYX 子标签)
private static Dictionary<int, Sprite> turretSpriteDic; // id → sprite
// ---- 保留的 AA Handle(不释放,避免 Build 下资源被卸载)----
private static readonly List<AsyncOperationHandle> _loadedHandles = new List<AsyncOperationHandle>();
static TurretResourcesData()
{
Init();
}
/// <summary>
/// 从 Resources/tbturretresources.json 加载炮台元数据。
/// 表里没有的 turretNumber,调用方用 TurretData 自身的 Inspector 默认值,不报错。
/// </summary>
async static void Init()
{
turretPrefabPathDic = new Dictionary<string, int>();
turretSpritePathDic = new Dictionary<string, int>();
turretDataDic = new Dictionary<int, TurretResourcesData>();
TextAsset jsonAsset = Resources.Load<TextAsset>("tbturretresources");
if (jsonAsset == null)
{
Debug.LogWarning("[TurretResourcesData] 资源表 tbturretresources.json 未找到,炮台数据字典为空,将使用 TurretData 默认值");
return;
}
try
{
var list = JsonConvert.DeserializeObject<List<TurretResourcesData>>(jsonAsset.text);
if (list == null)
{
Debug.LogWarning("[TurretResourcesData] 资源表解析为空,将使用 TurretData 默认值");
return;
}
foreach (var item in list)
{
// 战神(turretType==2)的 prefabTurretResourcesPath 可能为空,不跳过
// 用 turretNumber 构造默认路径,以便 Addressables 按名匹配
if (string.IsNullOrEmpty(item.prefabTurretResourcesPath))
{
if (item.turretType == 2)
item.prefabTurretResourcesPath = item.turretNumber.ToString();
else
continue; // 炮台/翅膀路径为空则跳过
}
turretPrefabPathDic[item.prefabTurretResourcesPath] = item.turretNumber;
turretSpritePathDic[item.prefabTurretResourcesPath] = item.turretNumber;
turretDataDic[item.turretNumber] = item;
Debug.Log($"[TurretResourcesData] 加载炮台: ID={item.turretNumber}, Path={item.prefabTurretResourcesPath}, Type={item.turretType}, PrefabType={item.prefabType}, BulletIDs=[{string.Join(",", item.bulletID)}]");
}
Debug.Log($"[TurretResourcesData] 初始化完成,共 {turretDataDic.Count} 个炮台配置");
}
catch (System.Exception ex)
{
Debug.LogError($"[TurretResourcesData] JSON 解析失败: {ex.Message},炮台数据字典为空,将使用 TurretData 默认值");
}
}
// ==================== 资源加载 ====================
/// <summary>
/// 加载炮台相关 Addressables 资源(两组标签交集):
/// - PT + Default:普通炮台/翅膀/战神展示预制体 → turretPrefabDic;
/// - PT + ZSYX:战神游戏内使用预制体 → turretGamePrefabDic(与展示同名,靠标签区分)。
/// 注意:Handle 必须保留,不能 Release,否则 Build 下资源会被立即卸载,
/// 字典中存的就是已销毁对象的引用(Editor 下因 AssetDatabase 模式不会暴露此问题)。
/// </summary>
public static async Task LoadTurretAssetsData()
{
turretPrefabDic = new Dictionary<int, GameObject>();
turretGamePrefabDic = new Dictionary<int, GameObject>();
turretSpriteDic = new Dictionary<int, Sprite>();
// 清理上一轮残留的 Handle
foreach (var h in _loadedHandles)
{
if (h.IsValid()) Addressables.Release(h);
}
_loadedHandles.Clear();
// 展示用标签组:PT + Default(普通炮台/翅膀/战神展示预制体)
var labels = new List<string> { turret_AALabel, defaultSubLabel };
// 战神游戏内标签组:PT + ZSYX(战神的使用预制体,名字与展示相同)
var zsGameLabels = new List<string> { turret_AALabel, zhanShenGameSubLabel };
Debug.Log("[TurretResourcesData] 开始预下载炮台资源依赖 (PT + Default)...");
var depHandle = Addressables.DownloadDependenciesAsync(labels, MergeMode.Intersection);
await depHandle.Task;
Addressables.Release(depHandle); // 预下载 Handle 可以立即释放,只影响下载缓存
Debug.Log("[TurretResourcesData] 炮台依赖资源预下载完成!");
Debug.Log("[TurretResourcesData] 开始预下载战神游戏内资源依赖 (PT + ZSYX)...");
var zsDepHandle = Addressables.DownloadDependenciesAsync(zsGameLabels, MergeMode.Intersection);
await zsDepHandle.Task;
Addressables.Release(zsDepHandle);
Debug.Log("[TurretResourcesData] 战神游戏内依赖资源预下载完成!");
// ---- 加载炮台 Prefab(展示用)----
var prefabHandle = Addressables.LoadAssetsAsync<GameObject>(labels, prefab =>
{
if (turretPrefabPathDic.TryGetValue(prefab.name, out int id))
{
turretPrefabDic[id] = prefab;
Debug.Log($"[TurretResourcesData] 加载 Prefab: {prefab.name} (ID={id})");
}
}, MergeMode.Intersection);
await prefabHandle.Task;
// 不释放!保留 Handle 以保持资源存活
_loadedHandles.Add(prefabHandle);
Debug.Log($"[TurretResourcesData] 炮台 Prefab 加载完成,共 {turretPrefabDic.Count} 个");
// ---- 加载战神游戏内 Prefab(ZSYX 子标签;与展示同名,靠标签区分)----
var zsPrefabHandle = Addressables.LoadAssetsAsync<GameObject>(zsGameLabels, prefab =>
{
if (turretPrefabPathDic.TryGetValue(prefab.name, out int id)
&& turretDataDic.TryGetValue(id, out var data)
&& data.turretType == 2) // 只收战神(turretType==2)的游戏内使用预制体
{
turretGamePrefabDic[id] = prefab;
Debug.Log($"[TurretResourcesData] 加载战神游戏内 Prefab: {prefab.name} (ID={id})");
}
}, MergeMode.Intersection);
await zsPrefabHandle.Task;
// 不释放!保留 Handle 以保持资源存活
_loadedHandles.Add(zsPrefabHandle);
Debug.Log($"[TurretResourcesData] 战神游戏内 Prefab 加载完成,共 {turretGamePrefabDic.Count} 个");
// ---- 加载炮台 Sprite ----
var spriteHandle = Addressables.LoadAssetsAsync<Sprite>(labels, data =>
{
if (turretSpritePathDic.TryGetValue(data.name, out int id))
{
turretSpriteDic[id] = data;
Debug.Log($"[TurretResourcesData] 加载 Sprite: {data.name} (ID={id})");
}
}, MergeMode.Intersection);
await spriteHandle.Task;
// 不释放!保留 Handle 以保持资源存活
_loadedHandles.Add(spriteHandle);
Debug.Log($"[TurretResourcesData] 炮台 Sprite 加载完成,共 {turretSpriteDic.Count} 个");
Debug.Log("[TurretResourcesData] 所有炮台资源加载完毕!");
}
/// <summary>
/// 卸载炮台 Addressables 资源。
/// 释放 LoadTurretAssetsData 中保留的所有 Handle。
/// </summary>
public static Task UnLoadTurretAssetsData()
{
foreach (var h in _loadedHandles)
{
if (h.IsValid())
{
Addressables.Release(h);
Debug.Log($"[TurretResourcesData] 释放 Handle: {h.DebugName}");
}
}
_loadedHandles.Clear();
turretPrefabDic?.Clear();
turretGamePrefabDic?.Clear();
turretSpriteDic?.Clear();
Debug.Log($"[TurretResourcesData] 卸载完成,剩余 Prefab: {turretPrefabDic?.Count ?? 0}, 战神游戏内: {turretGamePrefabDic?.Count ?? 0}, Sprite: {turretSpriteDic?.Count ?? 0}");
return Task.CompletedTask;
}
// ==================== 查询接口 ====================
/// <summary>根据 ID 获取炮台数据。</summary>
public static TurretResourcesData GetTurretData(int turretNumber)
{
return turretDataDic != null && turretDataDic.TryGetValue(turretNumber, out var data) ? data : null;
}
/// <summary>根据 ID 获取炮台 Prefab。</summary>
public static GameObject GetTurretPrefab(int turretNumber)
{
return turretPrefabDic != null && turretPrefabDic.TryGetValue(turretNumber, out var prefab) ? prefab : null;
}
/// <summary>
/// 根据战神编号获取战神预制体(两种情况二选一)。
/// - Display:展示用(大厅/商城预览,与 GetTurretPrefab 返回同一个展示模型);
/// - GamePlay:游戏内用(座位上替代普通炮台的使用模型)。
/// 未加载、非战神或未配置使用预制体时返回 null。
/// </summary>
public static GameObject GetZhanShenPrefab(int turretNumber, ZhanShenUsage usage = ZhanShenUsage.Display)
{
var dic = usage == ZhanShenUsage.GamePlay ? turretGamePrefabDic : turretPrefabDic;
return dic != null && dic.TryGetValue(turretNumber, out var prefab) ? prefab : null;
}
/// <summary>根据 ID 获取炮台 Sprite。</summary>
public static Sprite GetTurretSprite(int turretNumber)
{
return turretSpriteDic != null && turretSpriteDic.TryGetValue(turretNumber, out var sprite) ? sprite : null;
}
/// <summary>获取所有炮台数据列表。</summary>
public static List<TurretResourcesData> GetAllTurretData()
{
return turretDataDic != null ? new List<TurretResourcesData>(turretDataDic.Values) : new List<TurretResourcesData>();
}
/// <summary>根据类型获取炮台数据(1=普通炮台, 2=战神, 3=翅膀)。</summary>
public static List<TurretResourcesData> GetTurretDataByType(int turretType)
{
var result = new List<TurretResourcesData>();
if (turretDataDic == null) return result;
foreach (var kv in turretDataDic)
{
if (kv.Value.turretType == turretType)
result.Add(kv.Value);
}
return result;
}
}