基于NGUI的UISprite动态染色自定义实现
本文参考了iwinterice关于NGUI UISprite动态染色的解决方案,并在其基础上进行了调整与扩展。原博文详细阐述了理论依据,这里主要提供修改后的代码实现。
需求描述:在游戏中,角色头像需要根据状态变化显示不同颜色。例如,角色存活时头像正常显示,当角色死亡后,头像变为灰色或半透明状态。
为了避免修改NGUI源码可能带来的负面影响,采用继承方式扩展UISprite功能,保持原库的整洁性。
using UnityEngine;
using System.Collections.Generic;
/// <summary>
/// 继承UISprite,支持动态材质切换实现染色
/// </summary>
[ExecuteInEditMode]
[AddComponentMenu("NGUI/UI/NGUI SpriteExt")]
public class UISpriteExt : UISprite
{
[HideInInspector]
[SerializeField]
private Material mGrayMaterial;
public Material GrayMaterial
{
get { return mGrayMaterial; }
set { mGrayMaterial = value; }
}
[System.NonSerialized]
private bool mEnableGray = false;
public bool EnableGray
{
get { return mEnableGray; }
set { mEnableGray = value; }
}
public override Material material
{
get
{
Material baseMat = base.material;
if (baseMat == null && mAtlas != null)
{
baseMat = mAtlas.spriteMaterial;
}
if (mGrayMaterial != null && mEnableGray)
{
mGrayMaterial.mainTexture = baseMat.mainTexture;
return mGrayMaterial;
}
return baseMat;
}
}
private GameObject FindNearestPanel(Transform trans)
{
if (trans == null) return null;
UIPanel panel = trans.GetComponent<UIPanel>();
if (panel != null)
{
return panel.gameObject;
}
Transform parent = trans.parent;
return parent != null ? FindNearestPanel(parent) : null;
}
private GameObject cachedPanelObj = null;
public bool autoRefresh = true;
public void ForceRefresh()
{
if (!autoRefresh) return;
if (cachedPanelObj == null)
{
cachedPanelObj = FindNearestPanel(transform);
}
if (cachedPanelObj != null)
{
UIPanel panel = cachedPanelObj.GetComponent<UIPanel>();
panel.enabled = false;
panel.enabled = true;
gameObject.SetActive(false);
gameObject.SetActive(true);
}
}
}
编辑器扩展类,用于在Inspector面板中显示新增属性:
using UnityEngine;
using UnityEditor;
[CanEditMultipleObjects]
[CustomEditor(typeof(UISpriteExt), true)]
public class UISpriteExtInspector : UISpriteInspector
{
protected override bool ShouldDrawProperties()
{
base.ShouldDrawProperties();
SerializedProperty grayMat = NGUIEditorTools.DrawProperty(
"Gray Mat", serializedObject, "mGrayMaterial", GUILayout.MinWidth(20f));
GUILayout.Space(6f);
return true;
}
}
使用方式:在Inspector面板的"Gray Mat"属性中拖入灰度材质球。

通过控制EnableGray布尔值来切换显示状态。示例调用代码:
// 切换为灰度效果
public void SetGrayEffect()
{
spriteExt.EnableGray = true;
spriteExt.ForceRefresh();
}
// 恢复原始效果
public void SetNormalEffect()
{
spriteExt.EnableGray = false;
spriteExt.ForceRefresh();
}
效果对比:

后续需求扩展:在灰度基础上实现半透明效果,可以通过调整材质中的Alpha值或额外添加透明度控制逻辑实现。