备份,准备做双端

This commit is contained in:
2026-07-30 23:15:58 +08:00
parent add675e45d
commit ec4ec53545
88 changed files with 4050 additions and 872 deletions
@@ -59,6 +59,39 @@ public class teamUIController : MonoBehaviour
public float flashFadeDuration = 0.2f;
private static readonly int SaturationID = Shader.PropertyToID("_Saturation");
// Per-Image cached grayscale material instances. Previously each enemy-death / victory /
// ally-death event did `image.material = new Material(grayScaleMaterial)` and never
// destroyed the clone, leaking one material per event and giving each Image a unique
// material. Now we create at most one clone per Image, reuse it, and destroy all clones on teardown.
private readonly Dictionary<Image, Material> _grayscaleMaterialInstances = new Dictionary<Image, Material>();
private Material ApplyGrayscaleMaterial(Image image, float saturation)
{
if (image == null || grayScaleMaterial == null) return null;
if (!_grayscaleMaterialInstances.TryGetValue(image, out Material mat) || mat == null)
{
mat = new Material(grayScaleMaterial);
_grayscaleMaterialInstances[image] = mat;
}
image.material = mat;
mat.SetFloat(SaturationID, saturation);
return mat;
}
private void DestroyGrayscaleMaterialInstances()
{
foreach (var kv in _grayscaleMaterialInstances)
{
if (kv.Value != null) Destroy(kv.Value);
}
_grayscaleMaterialInstances.Clear();
}
private void OnDestroy()
{
DestroyGrayscaleMaterialInstances();
}
[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 };
@@ -1576,12 +1609,26 @@ public class teamUIController : MonoBehaviour
/// <summary>
/// Documentation text normalized.
/// </summary>
// Precomputed adjacency for the fixed 5-slot layout. All callers only read/iterate the
// result (never mutate it), so returning shared static arrays avoids a new List + ToArray
// allocation on every call — this is invoked from many per-skill/per-event code paths.
private static readonly int[][] s_adjacentAllyIndices =
{
new[] { 1 }, // slot 0 -> {1}
new[] { 0, 2 }, // slot 1 -> {0,2}
new[] { 1, 3 }, // slot 2 -> {1,3}
new[] { 2, 4 }, // slot 3 -> {2,4}
new[] { 3 }, // slot 4 -> {3}
};
private static readonly int[] s_adjacentAllyIndicesEmpty = new int[0];
public int[] GetAdjacentAllyIndices(int slotIndex)
{
var list = new List<int>();
if (slotIndex - 1 >= 0) list.Add(slotIndex - 1);
if (slotIndex + 1 <= 4) list.Add(slotIndex + 1);
return list.ToArray();
if (slotIndex < 0 || slotIndex > 4)
{
return s_adjacentAllyIndicesEmpty;
}
return s_adjacentAllyIndices[slotIndex];
}
/// <summary>
@@ -1889,12 +1936,8 @@ public class teamUIController : MonoBehaviour
: (so.enemy_Image != null ? so.enemy_Image : (so.enemy_Profile != null ? so.enemy_Profile : null));
currentEnemy_characterImage.sprite = sprite;
// Apply grayscale material
if (grayScaleMaterial != null)
{
currentEnemy_characterImage.material = new Material(grayScaleMaterial);
currentEnemy_characterImage.material.SetFloat(SaturationID, 0f); // 0 means grayscale
}
// Apply grayscale material (0 = grayscale). Reuses a cached clone per Image.
ApplyGrayscaleMaterial(currentEnemy_characterImage, 0f);
// Start with alpha 0 for fade in
Color c = currentEnemy_characterImage.color;
@@ -2195,14 +2238,15 @@ public class teamUIController : MonoBehaviour
{
if (_victorySaturationCoroutine != null) StopCoroutine(_victorySaturationCoroutine);
// Assign material only when victory occurs
// Assign cached grayscale clone and immediately set saturation to 0 (grayscale).
if (grayScaleMaterial != null)
{
victorySaturationImage.material = new Material(grayScaleMaterial);
ApplyGrayscaleMaterial(victorySaturationImage, 0f);
}
else if (victorySaturationImage.material != null)
{
victorySaturationImage.material.SetFloat(SaturationID, 0f);
}
// Immediately set saturation to 0 (Grayscale)
victorySaturationImage.material.SetFloat(SaturationID, 0f);
}
}
@@ -3059,11 +3103,11 @@ public class teamUIController : MonoBehaviour
public IEnumerator AllyDeathGrayscale(Image characterImage)
{
if (characterImage == null || grayScaleMaterial == null) yield break;
// Documentation text normalized.
Material instanceMat = new Material(grayScaleMaterial);
characterImage.material = instanceMat;
// Reuse a cached grayscale clone bound to this Image instead of leaking a new one per death.
Material instanceMat = ApplyGrayscaleMaterial(characterImage, 1f);
if (instanceMat == null) yield break;
float dur = 1.0f;
float t = 0f;
while (t < dur)