备份,准备做双端
This commit is contained in:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user