成就系统 巨大修改 新的ui 黑白效果 等一堆

This commit is contained in:
FloatGaming
2026-01-23 18:43:23 +08:00
parent f3ece026ca
commit 0e47864569
256 changed files with 134131 additions and 31192 deletions
+290 -170
View File
@@ -16,28 +16,37 @@ public class teamUIController : MonoBehaviour
}
// --- 新增:队伍槽 ID 列表(从上到下 5 个友军) ---
// --- ID бϵ 5 Ѿ ---
[Header("UI Effects")]
public Material grayScaleMaterial;
public Color hurtColor = Color.red;
public Color healColor = Color.green;
public Color manaColor = Color.blue;
[Range(0f, 1f)]
public float flashStartAlpha = 1f;
private static readonly int SaturationID = Shader.PropertyToID("_Saturation");
[Header("Runtime ally configuration")]
[Tooltip("IDs for the 5 ally slots (top to bottom). These are used by PopulateAllySOsFromIds to resolve SOs into currentAllySOs.")]
public List<int> allySlotIds = new List<int> { 0, 0, 0, 0, 0 };
// --- 新增:敌人队列槽 ID 列表(按出场顺序) ---
// --- ˶в ID б˳ ---
[Header("Runtime enemy configuration")]
[Tooltip("IDs for enemies to appear in sequence. All enemies share a single GameObject and will be initialized from these SOs in order.")]
public List<int> enemySlotIds = new List<int>() { 0, 0, 0, 0, 0 };
// --- 新增:解析后的当前五个 SO 引用(按顺序) ---
// --- ĵǰ SO ã˳ ---
private TeamCharacterDataInfo[] currentAllySOs = new TeamCharacterDataInfo[5];
// 新增:解析后的当前敌人 SO 列表(按出场顺序)
// ĵǰ SO б˳
private EnemyData_SO[] currentEnemySOs = new EnemyData_SO[0];
// 新增:仅包含已解析到的、有效的敌人 SO(不包含 id==0 或未找到的项)
// ѽġЧĵ SO id==0 δҵ
private EnemyData_SO[] recognizedEnemySOs = new EnemyData_SO[0];
// previous active flags for detecting external changes
private bool[] prevAllyActive = new bool[5];
// 两个路径字段:一个用于编辑器查找(可以填写 Assets/Resources/so/ally 或磁盘绝对路径),
// 一个用于运行时代码查找(Resources 相对路径,例如 so/ally
// ·ֶΣһڱ༭ңд Assets/Resources/so/ally ̾·
// һʱңResources · so/ally
[Header("SO folder paths")]
[Tooltip("Editor-only: project path or absolute disk path to the folder that contains SOs. Example: Assets/Resources/so/ally")]
public string editorSOFolderPath = "Assets/Resources/so/ally";
@@ -45,7 +54,7 @@ public class teamUIController : MonoBehaviour
[Tooltip("Runtime: Resources subfolder path (no 'Resources/' prefix). Example: so/ally")]
public string runtimeResourcesFolderPath = "so/ally";
// 新增:敌人 SO 路径(Editor / Runtime
// SO ·Editor / Runtime
[Tooltip("Editor-only: project path or absolute disk path to the folder that contains enemy SOs. Example: Assets/Resources/so/enemies")]
public string editorEnemySOFolderPath = "Assets/Resources/so/enemies";
@@ -60,20 +69,66 @@ public class teamUIController : MonoBehaviour
public GameObject ally04_object;
public GameObject ally05_object;
// 兼容旧字段(可选)
[Header("Ally Statistics (Real-time)")]
[Tooltip("Total damage dealt to enemies by each of the 5 ally slots.")]
public float[] totalDamageDealt = new float[5];
[Tooltip("Total HP restored by each of the 5 ally slots.")]
public float[] totalHealProvided = new float[5];
[Tooltip("Total Mana restored by each of the 5 ally slots.")]
public float[] totalManaRestored = new float[5];
[Tooltip("Total damage taken by each of the 5 ally slots.")]
public float[] totalDamageTaken = new float[5];
/// <summary>
/// Record damage dealt by an ally slot.
/// </summary>
public void RecordDamage(int slotIndex, float amount)
{
if (slotIndex >= 0 && slotIndex < 5)
totalDamageDealt[slotIndex] += amount;
}
/// <summary>
/// Record damage taken by an ally slot.
/// </summary>
public void RecordDamageTaken(int slotIndex, float amount)
{
if (slotIndex >= 0 && slotIndex < 5)
totalDamageTaken[slotIndex] += amount;
}
/// <summary>
/// Record healing provided by an ally slot.
/// </summary>
public void RecordHeal(int slotIndex, float amount)
{
if (slotIndex >= 0 && slotIndex < 5)
totalHealProvided[slotIndex] += amount;
}
/// <summary>
/// Record mana restored by an ally slot.
/// </summary>
public void RecordMana(int slotIndex, float amount)
{
if (slotIndex >= 0 && slotIndex < 5)
totalManaRestored[slotIndex] += amount;
}
// ݾֶΣѡ
[Header("Editor folder load (Editor only)")]
[Tooltip("Deprecated: kept for compatibility. Use editorSOFolderPath or runtimeResourcesFolderPath instead.")]
public string selectedProjectFolderPath = string.Empty;
/// <summary>
/// 在运行/编辑器中调用:根据 allySlotIds(5 个 int)在指定文件夹中搜索对应的 TeamCharacterDataInfo 资产。
/// Editor: 使用 editorSOFolderPath / selectedProjectFolderPathRuntime: 使用 runtimeResourcesFolderPath / selectedProjectFolderPath
/// /еã allySlotIds5 intָļӦ TeamCharacterDataInfo ʲ
/// Editor: ʹ editorSOFolderPath / selectedProjectFolderPathRuntime: ʹ runtimeResourcesFolderPath / selectedProjectFolderPath
/// </summary>
public void PopulateAllySOsFromIds()
{
if (allySlotIds == null || allySlotIds.Count < 5)
{
Debug.LogWarning("allySlotIds 未正确设置,自动填充为 5 个占位 ID");
Debug.LogWarning("allySlotIds δȷãԶΪ 5 ռλ ID");
allySlotIds = new List<int> { 0, 0, 0, 0, 0 };
}
@@ -96,7 +151,7 @@ public class teamUIController : MonoBehaviour
}
else
{
Debug.LogWarning("editorSOFolderPath 必须位于项目的 Assets 文件夹下以便进行查询(建议填写 Assets/Resources/so/ally)。回退到全局列表查找。路径也可填写为磁盘绝对路径。");
Debug.LogWarning("editorSOFolderPath λĿ Assets ļԱвѯд Assets/Resources/so/ally˵ȫбҡ·ҲдΪ̾·");
}
}
@@ -147,7 +202,7 @@ public class teamUIController : MonoBehaviour
int id = allySlotIds[i];
TeamCharacterDataInfo found = null;
// 如果 slot ID 0 -> 关闭对应 ally UI 并跳过
// slot ID Ϊ 0 -> رնӦ ally UI
if (id == 0)
{
currentAllySOs[i] = null;
@@ -164,7 +219,7 @@ public class teamUIController : MonoBehaviour
continue;
}
// 只要 asset 的路径或名称包含 id 即可引用(Editor
// ֻҪ asset ·ư id ãEditor
for (int j = 0; j < discovered.Count; j++)
{
var obj = discovered[j];
@@ -195,14 +250,14 @@ public class teamUIController : MonoBehaviour
}
}
// 回退到全局 teamCharacterList
// ˵ȫ teamCharacterList
if (found == null && globalList != null && globalList.characters != null)
{
for (int j = 0; j < globalList.characters.Count; j++)
{
var so = globalList.characters[j];
if (so == null) continue;
// globalList 中也以 name 包含 id 为准
// globalList Ҳ name id Ϊ׼
if (!string.IsNullOrEmpty(so.name) && so.name.Contains(id.ToString()))
{
found = so;
@@ -215,7 +270,7 @@ public class teamUIController : MonoBehaviour
if (found == null)
{
Debug.LogWarning($"[teamUIController] 未找到 id={id} 对应的 SO (slot {i + 1})");
Debug.LogWarning($"[teamUIController] δҵ id={id} Ӧ SO (slot {i + 1})");
// disable UI slot when not found
switch (i)
{
@@ -230,7 +285,7 @@ public class teamUIController : MonoBehaviour
else
{
Debug.Log($"[teamUIController] (Editor) slot {i + 1} resolved to SO: {found.name} (id={found.CharacterID})");
// 确保对应 UI slot 被开启
// ȷӦ UI slot
switch (i)
{
case 0: isAlly01_active = true; break;
@@ -316,7 +371,7 @@ public class teamUIController : MonoBehaviour
int id = allySlotIds[i];
TeamCharacterDataInfo found = null;
// 如果 slot ID 0 -> 关闭对应 ally UI 并跳过
// slot ID Ϊ 0 -> رնӦ ally UI
if (id == 0)
{
currentAllySOs[i] = null;
@@ -335,7 +390,7 @@ public class teamUIController : MonoBehaviour
continue;
}
// 只要资源名包含 id 即可引用(Runtime)。支持 TeamCharacterDataInfo AllyHero_SO
// ֻҪԴ id ãRuntime֧ TeamCharacterDataInfo AllyHero_SO
string runtimeSourceInfo = string.Empty;
for (int j = 0; j < runtimeDiscovered.Count; j++)
{
@@ -376,7 +431,7 @@ public class teamUIController : MonoBehaviour
}
}
// 回退到全局 teamCharacterList
// ˵ȫ teamCharacterList
if (found == null && globalList != null && globalList.characters != null)
{
for (int j = 0; j < globalList.characters.Count; j++)
@@ -412,7 +467,7 @@ public class teamUIController : MonoBehaviour
if (found == null)
{
Debug.LogWarning($"[teamUIController] (Runtime) 未找到 id={id} 对应的 SO (slot {i + 1})");
Debug.LogWarning($"[teamUIController] (Runtime) δҵ id={id} Ӧ SO (slot {i + 1})");
switch (i)
{
case 0: isAlly01_active = false; break;
@@ -641,7 +696,7 @@ public class teamUIController : MonoBehaviour
if (enemyCurrentCount > enemyCounterMax) enemyCurrentCount = enemyCounterMax;
}
// 返回解析到的敌人 SO 列表(副本)
// ؽĵ SO б
public EnemyData_SO[] GetCurrentEnemySOs()
{
return (EnemyData_SO[])currentEnemySOs.Clone();
@@ -658,30 +713,30 @@ public class teamUIController : MonoBehaviour
}
/// <summary>
/// 返回当前解析到的 SO 列表(数组副本)
/// صǰ SO б
/// </summary>
public TeamCharacterDataInfo[] GetCurrentAllySOs()
{
return (TeamCharacterDataInfo[])currentAllySOs.Clone();
}
[Header("基本文本")]
[Header("ı")]
[Tooltip("title")]
public TextMeshProUGUI songNametitle;
public TextMeshProUGUI difficultyName;
public TextMeshProUGUI difficultyID;
public TextMeshProUGUI constructionName;
[Tooltip("连击计数")]
[Tooltip("")]
public Text comboCounter;
[Tooltip("敌人出场数量")]
[Tooltip("˳")]
public Text enemyCounter;
[SerializeField] private int enemyCounterMax; // 本局游戏敌人最大数
[SerializeField] private int enemyCurrentCount; // 现在的敌人顺序
[Tooltip("当前总分")]
[SerializeField] private int enemyCounterMax; // Ϸ
[SerializeField] private int enemyCurrentCount; // ڵĵ˳
[Tooltip("ǰܷ")]
public TextMeshProUGUI currentTotalScore;
[Header("谱面总分")]
[Header("ܷ")]
public TextMeshProUGUI allSum_pmScore;
[Header("爱豆总分")]
[Header("ܷ")]
public TextMeshProUGUI allSum_idolScore;
// new: runtime enemy instance and UI sync fields
@@ -692,11 +747,11 @@ public class teamUIController : MonoBehaviour
private int prevEnemyMana = -1;
// For total enemy health bar
private int totalMaxHP = 0; // 保留现有 totalMaxHP
private int totalMaxHP = 0; // totalMaxHP
private Coroutine totalFadeHealthCoroutine;
// 移除 private float prevTotalHealthFill = 1f;
// Ƴ private float prevTotalHealthFill = 1f;
[Header("Combo判定最低要求")]
[Header("ComboжҪ")]
public ComboJudgeType comboJudgeType = ComboJudgeType.Perfect;
private int combo = 0;
@@ -710,37 +765,37 @@ public class teamUIController : MonoBehaviour
}
[Header("teammate01")]
[Tooltip("父物体-控制整体显隐")]
[Tooltip("-")]
public GameObject objectFather_ally01;
[Tooltip("开关")]
[Tooltip("")]
public bool isAlly01_active = true;
[Tooltip("角色图")]
[Tooltip("ɫͼ")]
public Image teammate01_characterImage;
[Tooltip("血条")]
[Tooltip("Ѫ")]
public Image teammate01_healthImage;
[Tooltip("虚血条")]
[Tooltip("Ѫ")]
public Image teammate01_fadehealthImage;
[Tooltip("法力条")]
[Tooltip("")]
public Image teammate01_manaImage;
[Tooltip("虚法力条")]
[Tooltip("")]
public Image teammate01_fadeManaImage;
[Tooltip("名字文本")]
[Tooltip("ı")]
public TextMeshProUGUI teammate01_nameText;
[Tooltip("当前生命值/最大生命值")]
[Tooltip("ǰֵ/ֵ")]
public TextMeshProUGUI teammate01_healthRate;
[Tooltip("当前分数/轨道分数上限")]
[Tooltip("ǰ/")]
public TextMeshProUGUI teammate01_current_scoreText; // rate : now score / max score
[Tooltip("角色唯一识别码")]
[Tooltip("ɫΨһʶ")]
[SerializeField] private int ally01_id;
[Tooltip("受击闪红")]
[Tooltip("ܻ")]
public Image teammate01_hurtRedImage;
[Tooltip("当前生命值")]
[Tooltip("ǰֵ")]
[SerializeField] private int teammate01_currentHP;
[Tooltip("最大生命值")]
[Tooltip("ֵ")]
[SerializeField] private int teammate01_maxHP;
[Tooltip("当前法力值")]
[Tooltip("ǰֵ")]
[SerializeField] private int teammate01_currentMana;
[Tooltip("最大法力值")]
[Tooltip("ֵ")]
[SerializeField] private int teammate01_maxMana;
[Header("pmScore")]
public TextMeshProUGUI red_pmScore_sum;
@@ -748,37 +803,37 @@ public class teamUIController : MonoBehaviour
public TextMeshProUGUI red_idolScore_sum;
[Header("teammate02")]
[Tooltip("父物体-控制整体显隐")]
[Tooltip("-")]
public GameObject objectFather_ally02;
[Tooltip("开关")]
[Tooltip("")]
public bool isAlly02_active = true;
[Tooltip("角色图")]
[Tooltip("ɫͼ")]
public Image teammate02_characterImage;
[Tooltip("血条")]
[Tooltip("Ѫ")]
public Image teammate02_healthImage;
[Tooltip("虚血条")]
[Tooltip("Ѫ")]
public Image teammate02_fadehealthImage;
[Tooltip("法力条")]
[Tooltip("")]
public Image teammate02_manaImage;
[Tooltip("虚法力条")]
[Tooltip("")]
public Image teammate02_fadeManaImage;
[Tooltip("名字文本")]
[Tooltip("ı")]
public TextMeshProUGUI teammate02_nameText;
[Tooltip("当前生命值/最大生命值")]
[Tooltip("ǰֵ/ֵ")]
public TextMeshProUGUI teammate02_healthRate;
[Tooltip("当前分数/轨道分数上限")]
[Tooltip("ǰ/")]
public TextMeshProUGUI teammate02_current_scoreText; // rate : now score / max score
[Tooltip("角色唯一识别码")]
[Tooltip("ɫΨһʶ")]
[SerializeField] private int ally02_id;
[Tooltip("受击闪红")]
[Tooltip("ܻ")]
public Image teammate02_hurtRedImage;
[Tooltip("当前生命值")]
[Tooltip("ǰֵ")]
[SerializeField] private int teammate02_currentHP;
[Tooltip("最大生命值")]
[Tooltip("ֵ")]
[SerializeField] private int teammate02_maxHP;
[Tooltip("当前法力值")]
[Tooltip("ǰֵ")]
[SerializeField] private int teammate02_currentMana;
[Tooltip("最大法力值")]
[Tooltip("ֵ")]
[SerializeField] private int teammate02_maxMana;
[Header("pmScore")]
public TextMeshProUGUI green_pmScore_sum;
@@ -786,37 +841,37 @@ public class teamUIController : MonoBehaviour
public TextMeshProUGUI green_idolScore_sum;
[Header("teammate03")]
[Tooltip("父物体-控制整体显隐")]
[Tooltip("-")]
public GameObject objectFather_ally03;
[Tooltip("开关")]
[Tooltip("")]
public bool isAlly03_active = true;
[Tooltip("角色图")]
[Tooltip("ɫͼ")]
public Image teammate03_characterImage;
[Tooltip("血条")]
[Tooltip("Ѫ")]
public Image teammate03_healthImage;
[Tooltip("虚血条")]
[Tooltip("Ѫ")]
public Image teammate03_fadehealthImage;
[Tooltip("法力条")]
[Tooltip("")]
public Image teammate03_manaImage;
[Tooltip("虚法力条")]
[Tooltip("")]
public Image teammate03_fadeManaImage;
[Tooltip("名字文本")]
[Tooltip("ı")]
public TextMeshProUGUI teammate03_nameText;
[Tooltip("当前生命值/最大生命值")]
[Tooltip("ǰֵ/ֵ")]
public TextMeshProUGUI teammate03_healthRate;
[Tooltip("当前分数/轨道分数上限")]
[Tooltip("ǰ/")]
public TextMeshProUGUI teammate03_current_scoreText; // rate : now score / max score
[Tooltip("角色唯一识别码")]
[Tooltip("ɫΨһʶ")]
[SerializeField] private int ally03_id;
[Tooltip("受击闪红")]
[Tooltip("ܻ")]
public Image teammate03_hurtRedImage;
[Tooltip("当前生命值")]
[Tooltip("ǰֵ")]
[SerializeField] private int teammate03_currentHP;
[Tooltip("最大生命值")]
[Tooltip("ֵ")]
[SerializeField] private int teammate03_maxHP;
[Tooltip("当前法力值")]
[Tooltip("ǰֵ")]
[SerializeField] private int teammate03_currentMana;
[Tooltip("最大法力值")]
[Tooltip("ֵ")]
[SerializeField] private int teammate03_maxMana;
[Header("pmScore")]
public TextMeshProUGUI yellow_pmScore_sum;
@@ -824,37 +879,37 @@ public class teamUIController : MonoBehaviour
public TextMeshProUGUI yellow_idolScore_sum;
[Header("teammate04")]
[Tooltip("父物体-控制整体显隐")]
[Tooltip("-")]
public GameObject objectFather_ally04;
[Tooltip("开关")]
[Tooltip("")]
public bool isAlly04_active = true;
[Tooltip("角色图")]
[Tooltip("ɫͼ")]
public Image teammate04_characterImage;
[Tooltip("血条")]
[Tooltip("Ѫ")]
public Image teammate04_healthImage;
[Tooltip("虚血条")]
[Tooltip("Ѫ")]
public Image teammate04_fadehealthImage;
[Tooltip("法力条")]
[Tooltip("")]
public Image teammate04_manaImage;
[Tooltip("虚法力条")]
[Tooltip("")]
public Image teammate04_fadeManaImage;
[Tooltip("名字文本")]
[Tooltip("ı")]
public TextMeshProUGUI teammate04_nameText;
[Tooltip("当前生命值/最大生命值")]
[Tooltip("ǰֵ/ֵ")]
public TextMeshProUGUI teammate04_healthRate;
[Tooltip("当前分数/轨道分数上限")]
[Tooltip("ǰ/")]
public TextMeshProUGUI teammate04_current_scoreText; // rate : now score / max score
[Tooltip("角色唯一识别码")]
[Tooltip("ɫΨһʶ")]
[SerializeField] private int ally04_id;
[Tooltip("受击闪红")]
[Tooltip("ܻ")]
public Image teammate04_hurtRedImage;
[Tooltip("当前生命值")]
[Tooltip("ǰֵ")]
[SerializeField] private int teammate04_currentHP;
[Tooltip("最大生命值")]
[Tooltip("ֵ")]
[SerializeField] private int teammate04_maxHP;
[Tooltip("当前法力值")]
[Tooltip("ǰֵ")]
[SerializeField] private int teammate04_currentMana;
[Tooltip("最大法力值")]
[Tooltip("ֵ")]
[SerializeField] private int teammate04_maxMana;
[Header("pmScore")]
public TextMeshProUGUI purple_pmScore_sum;
@@ -862,37 +917,37 @@ public class teamUIController : MonoBehaviour
public TextMeshProUGUI purple_idolScore_sum;
[Header("teammate05")]
[Tooltip("父物体-控制整体显隐")]
[Tooltip("-")]
public GameObject objectFather_ally05;
[Tooltip("开关")]
[Tooltip("")]
public bool isAlly05_active = true;
[Tooltip("角色图")]
[Tooltip("ɫͼ")]
public Image teammate05_characterImage;
[Tooltip("血条")]
[Tooltip("Ѫ")]
public Image teammate05_healthImage;
[Tooltip("虚血条")]
[Tooltip("Ѫ")]
public Image teammate05_fadehealthImage;
[Tooltip("法力条")]
[Tooltip("")]
public Image teammate05_manaImage;
[Tooltip("虚法力条")]
[Tooltip("")]
public Image teammate05_fadeManaImage;
[Tooltip("名字文本")]
[Tooltip("ı")]
public TextMeshProUGUI teammate05_nameText;
[Tooltip("当前生命值/最大生命值")]
[Tooltip("ǰֵ/ֵ")]
public TextMeshProUGUI teammate05_healthRate;
[Tooltip("当前分数/轨道分数上限")]
[Tooltip("ǰ/")]
public TextMeshProUGUI teammate05_current_scoreText; // rate : now score / max score
[Tooltip("角色唯一识别码")]
[Tooltip("ɫΨһʶ")]
[SerializeField] private int ally05_id;
[Tooltip("受击闪红")]
[Tooltip("ܻ")]
public Image teammate05_hurtRedImage;
[Tooltip("当前生命值")]
[Tooltip("ǰֵ")]
[SerializeField] private int teammate05_currentHP;
[Tooltip("最大生命值")]
[Tooltip("ֵ")]
[SerializeField] private int teammate05_maxHP;
[Tooltip("当前法力值")]
[Tooltip("ǰֵ")]
[SerializeField] private int teammate05_currentMana;
[Tooltip("最大法力值")]
[Tooltip("ֵ")]
[SerializeField] private int teammate05_maxMana;
[Header("pmScore")]
public TextMeshProUGUI blue_pmScore_sum;
@@ -900,41 +955,41 @@ public class teamUIController : MonoBehaviour
public TextMeshProUGUI blue_idolScore_sum;
[Header("currentEnemy")]
[Tooltip("父物体-控制整体显隐")]
[Tooltip("-")]
public GameObject objectFather_enemy;
[Tooltip("开关")]
[Tooltip("")]
public bool isEnemy_active = true;
[Tooltip("角色图")]
[Tooltip("ɫͼ")]
public Image currentEnemy_characterImage;
[Tooltip("血条")]
[Tooltip("Ѫ")]
public Image currentEnemy_healthImage;
[Tooltip("虚血条")]
[Tooltip("Ѫ")]
public Image currentEnemy_fadehealthImage;
[Tooltip("法力条")]
[Tooltip("")]
public Image currentEnemy_manaImage;
[Tooltip("虚法力条")]
[Tooltip("")]
public Image currentEnemy_fademanaImage;
[Tooltip("共计血条")]
[Tooltip("Ѫ")]
public Image allEnemy_totalHealthImage;
[Tooltip("共计虚血条")]
[Tooltip("Ѫ")]
public Image allEnemy_totalFadehealthImage;
[Tooltip("名字文本")]
[Tooltip("ı")]
public Text currentEnemy_nameText;
[Tooltip("类型文本")]
[Tooltip("ı")]
public Text currentEnemy_typeText;
[Tooltip("当前敌人生命值/最大生命值")]
[Tooltip("ǰֵ/ֵ")]
public TextMeshProUGUI currentEnemy_healthRate;
[Tooltip("所有敌人生命值/最大生命值总计")]
[Tooltip("еֵ/ֵܼ")]
public TextMeshProUGUI totalEnemy_healthRate;
[Tooltip("当前敌人法力值/最大法力值")]
[Tooltip("ǰ˷ֵ/ֵ")]
public TextMeshProUGUI currentEnemy_manaRate;
[Tooltip("当前分数/轨道分数上限")]
[Tooltip("ǰ/")]
public TextMeshProUGUI currentEnemy_current_scoreText; // rate : now score / max score
[Tooltip("敌人唯一识别码")]
[Tooltip("Ψһʶ")]
[SerializeField] private int enemy_id;
[Tooltip("受击闪红")]
[Tooltip("ܻ")]
public Image currentEnemy_hurtRedImage;
[Tooltip("敌人排队")]
[Tooltip("Ŷ")]
public TextMeshProUGUI enemyList_rateText;
// Start is called once before the first execution of Update after the MonoBehaviour is created
@@ -993,7 +1048,7 @@ public class teamUIController : MonoBehaviour
if (prevEnemyHP != hp)
{
UpdateEnemyHealthVisuals(prevEnemyHP, hp, true);
// 当当前敌人的 HP 变化时,也需要更新总血条
// ǰ˵ HP 仯ʱҲҪѪ
UpdateAllEnemyTotalHealthUIOnHpChange(hp);
prevEnemyHP = hp;
}
@@ -1019,7 +1074,7 @@ public class teamUIController : MonoBehaviour
}
/// <summary>
/// 由判定系统调用,传入判定结果(如"Perfect""Great""Good""Miss"
/// жϵͳãж"Perfect""Great""Good""Miss"
/// </summary>
public void OnJudgeResult(string result)
{
@@ -1033,10 +1088,24 @@ public class teamUIController : MonoBehaviour
}
if (comboCounter != null)
comboCounter.text = combo.ToString();
// --- Statistics: Update achievement tracking for combo ---
if (InGamePerformanceManager.Instance != null)
{
InGamePerformanceManager.Instance.UpdateCombo(combo);
}
else
{
// Only log once to avoid spamming every frame, or only on combo milestones
if (combo > 0 && combo % 10 == 0)
{
Debug.LogWarning("[teamUIController] InGamePerformanceManager.Instance is null! Cannot update achievements.");
}
}
}
/// <summary>
/// 判断当前判定结果是否达到combo要求
/// жϵǰжǷcomboҪ
/// </summary>
private bool IsCombo(string result)
{
@@ -1205,7 +1274,7 @@ public class teamUIController : MonoBehaviour
}
/// <summary>
/// 返回相邻的友军槽索引(左右),边侧只有一侧
/// ڵѾңֻ߲һ
/// </summary>
public int[] GetAdjacentAllyIndices(int slotIndex)
{
@@ -1216,7 +1285,7 @@ public class teamUIController : MonoBehaviour
}
/// <summary>
/// 返回指定槽位对应的友军 GameObject(优先返回 allyX_object,否则返回 objectFather_allyXX),可能为 null
/// ָλӦѾ GameObjectȷ allyX_object򷵻 objectFather_allyXXΪ null
/// </summary>
public GameObject GetAllyObjectBySlot(int slotIndex)
{
@@ -1284,9 +1353,9 @@ public class teamUIController : MonoBehaviour
if (currentEnemy_manaImage != null) currentEnemy_manaImage.fillAmount = 0f;
if (currentEnemy_fademanaImage != null) currentEnemy_fademanaImage.fillAmount = 0f;
if (enemyCounter != null) enemyCounter.text = "0/0";
if (currentEnemy_typeText != null) currentEnemy_typeText.text = "(普通)";
if (currentEnemy_typeText != null) currentEnemy_typeText.text = "(ͨ)";
UpdateEnemyListText();
// 刷新总血条,在没有敌人时显示 0/TotalMax
// ˢѪûеʱʾ 0/TotalMax
UpdateAllEnemyTotalHealthUIImmediate();
return;
}
@@ -1304,9 +1373,9 @@ public class teamUIController : MonoBehaviour
if (currentEnemy_manaImage != null) currentEnemy_manaImage.fillAmount = 0f;
if (currentEnemy_fademanaImage != null) currentEnemy_fademanaImage.fillAmount = 0f;
if (enemyCounter != null) enemyCounter.text = "0/" + enemyCounterMax.ToString();
if (currentEnemy_typeText != null) currentEnemy_typeText.text = "(普通)";
if (currentEnemy_typeText != null) currentEnemy_typeText.text = "(ͨ)";
UpdateEnemyListText();
// 刷新总血条,在所有敌人死亡时显示 0/TotalMax
// ˢѪеʱʾ 0/TotalMax
UpdateAllEnemyTotalHealthUIImmediate();
return;
}
@@ -1339,16 +1408,16 @@ public class teamUIController : MonoBehaviour
switch (so.enemyType)
{
case EnemyData_SO.EnemyType.Elite:
currentEnemy_typeText.text = "(精英)";
currentEnemy_typeText.text = "(Ӣ)";
break;
case EnemyData_SO.EnemyType.Boss:
currentEnemy_typeText.text = "(首领)";
currentEnemy_typeText.text = "()";
break;
case EnemyData_SO.EnemyType.Legend:
currentEnemy_typeText.text = "(ʷʫ)";
break;
default:
currentEnemy_typeText.text = "(普通)";
currentEnemy_typeText.text = "(ͨ)";
break;
}
}
@@ -1399,54 +1468,54 @@ public class teamUIController : MonoBehaviour
UpdateEnemyUIImmediate();
}
// teamUIController.cs - 【新增】
// teamUIController.cs -
// =========================================================
// BeatmapManager 调用的方法:设置单个敌人 HP
// BeatmapManager õķõ HP
// =========================================================
/// <summary>
/// 将计算得到的单个敌人最大生命值写入到所有已识别的敌人 Scriptable Object 中。
/// õĵֵдʶĵ Scriptable Object С
/// </summary>
public void ApplyCalculatedEnemyHP(int individualMaxHP)
{
// 确保 recognizedEnemySOs 数组不为空
// ȷ recognizedEnemySOs 鲻Ϊ
if (recognizedEnemySOs != null && recognizedEnemySOs.Length > 0)
{
Debug.Log($"[teamUIController] Applying calculated HP: {individualMaxHP} to {recognizedEnemySOs.Length} recognized enemies.");
// 1. 修改 SO 数据:遍历所有已识别的敌人 SO,并设置其最大生命值
// 1. ޸ SO ݣʶĵ SOֵ
foreach (var so in recognizedEnemySOs)
{
// 假设 EnemyData_SO 包含 public int enemy_maxHP; 字段
// EnemyData_SO public int enemy_maxHP; ֶ
if (so != null)
{
so.enemy_maxHP = individualMaxHP;
}
}
// 2. 重新计算总血量并更新总血条
// 2. ¼ѪѪ
RecalculateTotalMaxHP();
// 3. 强制刷新当前生成的敌人实例
// 因为 Populate 已经在 Apply 之前生成了旧数据的敌人,所以需要重置
// 3. ǿˢµǰɵĵʵ
// Ϊ Populate Ѿ Apply ֮ǰ˾ݵĵˣҪ
if (enemyCombatantInstance != null && enemyCurrentCount >= 0 && enemyCurrentCount < recognizedEnemySOs.Length)
{
var currentSO = recognizedEnemySOs[enemyCurrentCount];
if (currentSO != null)
{
Debug.Log($"[teamUIController] Re-initializing current enemy instance with new HP: {individualMaxHP}");
enemyCombatantInstance.InitializeFromSO(currentSO); // 重新使用新的 SO 数据初始化实例
UpdateEnemyUIImmediate(); // 立即刷新 UI
enemyCombatantInstance.InitializeFromSO(currentSO); // ʹµ SO ݳʼʵ
UpdateEnemyUIImmediate(); // ˢ UI
}
}
}
}
// =========================================================
// 【新增】总生命值重新计算方法(封装原有的累加逻辑)
// ֵ¼װԭеۼ߼
// =========================================================
/// <summary>
/// 遍历所有已识别敌人的 SO,累加它们的生命值,更新 totalMaxHP,并立即刷新总血条。
/// ʶ˵ SOۼǵֵ totalMaxHPˢѪ
/// </summary>
private void RecalculateTotalMaxHP()
{
@@ -1459,16 +1528,16 @@ public class teamUIController : MonoBehaviour
}
}
Debug.Log($"[teamUIController] Total Max HP has been recalculated to: {totalMaxHP}");
// 刷新总血条上限显示,防止出现延迟
// ˢѪʾֹӳ
UpdateAllEnemyTotalHealthUIImmediate();
}
// 新增:在当前敌人 HP 变化时,更新总血条 UI
// ڵǰ HP 仯ʱѪ UI
private void UpdateAllEnemyTotalHealthUIOnHpChange(int newCurrentHP)
{
if (allEnemy_totalHealthImage == null) return;
// 重新计算总当前血量(currentEnemySOs 保持不变,但 active enemy current HP 改变了)
// ¼ܵǰѪcurrentEnemySOs ֲ active enemy current HP ıˣ
int totalCur = 0;
if (currentEnemySOs != null)
{
@@ -1477,14 +1546,14 @@ public class teamUIController : MonoBehaviour
var so = currentEnemySOs[i];
if (so == null) continue;
// 仅更新当前活跃敌人的血量,后续敌人保持 Max HP
// µǰԾ˵Ѫ˱ Max HP
if (i == enemyCurrentCount) totalCur += newCurrentHP; else totalCur += so.enemy_maxHP;
}
}
float newFill = totalMaxHP > 0 ? (float)totalCur / totalMaxHP : 0f;
// 1. 更新实血条
// 1. ʵѪ
allEnemy_totalHealthImage.fillAmount = newFill;
if (totalEnemy_healthRate != null) totalEnemy_healthRate.text = $"{totalCur}/{totalMaxHP}";
@@ -1512,7 +1581,7 @@ public class teamUIController : MonoBehaviour
}
}
// 新增:用于在 SpawnNextEnemy/No Enemy 时立即更新总血条(不使用动画逻辑)
// SpawnNextEnemy/No Enemy ʱѪʹö߼
private void UpdateAllEnemyTotalHealthUIImmediate()
{
if (allEnemy_totalHealthImage == null) return;
@@ -1525,10 +1594,10 @@ public class teamUIController : MonoBehaviour
var so = currentEnemySOs[i];
if (so == null) continue;
// 仅更新当前活跃敌人的血量,后续敌人保持 Max HP
// µǰԾ˵Ѫ˱ Max HP
if (i == enemyCurrentCount)
{
// 使用 Combatant 实例的当前 HP
// ʹ Combatant ʵĵǰ HP
if (enemyCombatantInstance != null) totalCur += enemyCombatantInstance.currentHP;
else totalCur += so.enemy_maxHP; // Fallback
}
@@ -1541,12 +1610,12 @@ public class teamUIController : MonoBehaviour
float newFill = totalMaxHP > 0 ? (float)totalCur / totalMaxHP : 0f;
// 立即更新实血条和虚血条
// ʵѪѪ
allEnemy_totalHealthImage.fillAmount = newFill;
if (allEnemy_totalFadehealthImage != null) allEnemy_totalFadehealthImage.fillAmount = newFill;
if (totalEnemy_healthRate != null) totalEnemy_healthRate.text = $"{totalCur}/{totalMaxHP}";
// 停止可能正在运行的虚血条动画
// ֹͣеѪ
if (totalFadeHealthCoroutine != null) StopCoroutine(totalFadeHealthCoroutine);
}
@@ -1690,4 +1759,55 @@ public class teamUIController : MonoBehaviour
}
allEnemy_totalFadehealthImage.fillAmount = targetFill;
}
}
// 1. ͨõ˸߼ܻѪ̵ȣ
// 1. 通用的图像闪烁效果(受击闪红、回血闪绿、回蓝闪蓝等)
// 1. 通用的图像闪烁效果(受击闪红、回血闪绿、回蓝闪蓝等)
public IEnumerator AllyImageFlash(Image hurtImage, Color targetColor)
{
if (hurtImage == null) yield break;
float startAlpha = flashStartAlpha;
Color c = targetColor;
c.a = startAlpha;
hurtImage.color = c;
yield return new WaitForSeconds(0.2f);
float dur = 0.4f;
float t = 0f;
while (t < dur)
{
t += Time.deltaTime;
c.a = Mathf.Lerp(startAlpha, 0f, t / dur);
hurtImage.color = c;
yield return null;
}
c.a = 0f;
hurtImage.color = c;
}
// 2. ڰ׽߼
// 2. 死亡黑白渐变逻辑
public IEnumerator AllyDeathGrayscale(Image characterImage)
{
if (characterImage == null || grayScaleMaterial == null) yield break;
// 创建材质实例以避免影响其他使用相同材质的物体
Material instanceMat = new Material(grayScaleMaterial);
characterImage.material = instanceMat;
float dur = 1.0f;
float t = 0f;
while (t < dur)
{
t += Time.deltaTime;
float sat = Mathf.Lerp(1f, 0f, t / dur);
instanceMat.SetFloat(SaturationID, sat);
yield return null;
}
instanceMat.SetFloat(SaturationID, 0f);
}
// ʵȾԭʼ
}