我感觉这个思路的有两个:
1、面向对象思维:每一个变色封装成一个对象,对对象进行操作
2、优先级:变色对象有优先级,优先级高的先执行
应用场景:战斗单位收到多个状态,这时面线对象和优先级的好处就体现出来了
using System;
using System.Collections.Generic;
using UnityEngine;
public enum StateMaterial
{
NORMAL = 0,
ONHIT = 10,
}
public class MaterialMgr
{
public delegate void MaterialUpdate(List<Material> matList, float time);
public class MaterialUnit
{
public MaterialUpdate mUpdateCallBack;
public int mTimeCount;
public StateMaterial stateMaterial;
public MaterialUnit(StateMaterial state, int time, MaterialUpdate updateCallBack)
{
stateMaterial = state;
mTimeCount = time;
mUpdateCallBack = updateCallBack;
}
}
GameObject modelObj;
List<MaterialUnit> matUnitList;
List<Material> matList;
List<Color> cacheCorlor;
Color hitColor;
public MaterialMgr(GameObject model)
{
matUnitList = new List<MaterialUnit>();
matList = new List<Material>();
cacheCorlor = new List<Color>();
hitColor = new Color(255 / 255f, 192 / 255f, 192 / 255f);
modelObj = model;
}
#region 生命周期
/// <summary>
/// 初始化
/// </summary>
public void Init()
{
InitMat();
}
public void MatUpdate(float deltaTime)
{
if (matList.Count <= 0)
return;
if (matUnitList.Count <= 0)
return;
try
{
foreach (var item in matUnitList)
{
item.mTimeCount -= (int)(deltaTime * 1000);
}
RemoveMatUnit();
var matUnit = GetCurMatUnit();
if (matUnit != null)
if (matUnit.mUpdateCallBack != null)
matUnit.mUpdateCallBack(matList, matUnit.mTimeCount);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
public void Dispose()
{
ResetMat();
matList.Clear();
matUnitList.Clear();
cacheCorlor.Clear();
modelObj = null;
}
#endregion
#region 内部接口
/// <summary>
/// 初始化材质球列表
/// </summary>
void InitMat()
{
SkinnedMeshRenderer[] renderList = modelObj.GetComponentsInChildren<SkinnedMeshRenderer>();
foreach (var render in renderList)
{
foreach (var mat in render.materials)
{
matList.Add(mat);
cacheCorlor.Add(mat.color);
}
}
}
/// <summary>
/// 获取当前
/// </summary>
/// <returns></returns>
MaterialUnit GetCurMatUnit()
{
MaterialUnit materialUnit = null;
StateMaterial state = StateMaterial.NORMAL;
foreach (var matUnit in matUnitList)
{
if ((int)state < (int)matUnit.stateMaterial)
materialUnit = matUnit;
}
return materialUnit;
}
/// <summary>
/// 移除
/// </summary>
void RemoveMatUnit()
{
for (int i = 0; i < matUnitList.Count; i++)
{
if (matUnitList[i].mTimeCount <= 0)
{
matUnitList.Remove(matUnitList[i]);
break;
}
}
if (matUnitList.Count <= 0)
ResetMat();
}
/// <summary>
/// 获取对象
/// </summary>
/// <param name="stateMaterial"></param>
/// <returns></returns>
MaterialUnit GetMaterialUnit(StateMaterial stateMaterial)
{
MaterialUnit materialUnit = null;
foreach (var item in matUnitList)
{
if(item.stateMaterial == stateMaterial)
{
materialUnit = item;
break;
}
}
return materialUnit;
}
#endregion
#region 外部接口
/// <summary>
/// 重置色值
/// </summary>
public void ResetMat()
{
if (matList.Count <= 0)
return;
if (cacheCorlor.Count <= 0)
return;
try
{
int i = 0;
foreach (var mat in matList)
{
mat.color = cacheCorlor[i];
i++;
}
}
catch (Exception)
{
throw new Exception("matList 有问题");
}
}
/// <summary>
/// 添加色值改变dic
/// </summary>
/// <param name="state"></param>
/// <param name="time"></param>
/// <param name="materialUpdate"></param>
public void AddMatUnit(StateMaterial state, int time, MaterialUpdate materialUpdate = null)
{
if (matList.Count <= 0)
return;
MaterialUnit matUnit = GetMaterialUnit(state);
if (matUnit != null)
{
matUnit.mTimeCount = time;
}
else
{
matUnit = new MaterialUnit(state, time, materialUpdate);
matUnitList.Add(matUnit);
}
}
/// <summary>
/// 受击色值变化
/// </summary>
/// <param name="state"></param>
/// <param name="time"></param>
/// <param name="updateCallBack"></param>
public void OnHit(StateMaterial state, int time)
{
if (matList.Count <= 0)
return;
AddMatUnit(state, time, (materList, remainTime) =>
{
if(remainTime > 0)
{
foreach (var mat in materList)
{
mat.color = hitColor;
}
}
});
}
#endregion
}
改版:目的是优化材质球使用,由操作材质变成操作材质属性块。
上代码
using System;
using System.Collections.Generic;
using UnityEngine;
public enum StateMaterial
{
NORMAL = 0,
ONHIT = 10,
}
public class MaterialMgr
{
public delegate void MaterialUpdate(SkinnedMeshRenderer[] renderList, float time);
public class MaterialUnit
{
public MaterialUpdate mUpdateCallBack;
public int mTimeCount;
public StateMaterial stateMaterial;
public MaterialUnit(StateMaterial state, int time, MaterialUpdate updateCallBack)
{
stateMaterial = state;
mTimeCount = time;
mUpdateCallBack = updateCallBack;
}
}
GameObject modelObj;
List<MaterialUnit> matUnitList;
Color hitColor;
Color defaultColor;
SkinnedMeshRenderer[] renderList;
MaterialPropertyBlock prop;
int colorID;
public MaterialMgr(GameObject model)
{
matUnitList = new List<MaterialUnit>();
hitColor = new Color(255 / 255f, 192 / 255f, 192 / 255f);
defaultColor = new Color(255 / 255f, 255 / 255f, 255 / 255f);
modelObj = model;
prop = new MaterialPropertyBlock();
colorID = Shader.PropertyToID("_Color");
}
#region 生命周期
/// <summary>
/// 初始化
/// </summary>
public void Init()
{
InitMat();
}
public void MatUpdate(float deltaTime)
{
if (renderList.Length <= 0)
return;
if (matUnitList.Count <= 0)
return;
try
{
foreach (var item in matUnitList)
{
item.mTimeCount -= (int)(deltaTime * 1000);
}
RemoveMatUnit();
var matUnit = GetCurMatUnit();
if (matUnit != null)
if (matUnit.mUpdateCallBack != null)
matUnit.mUpdateCallBack(renderList, matUnit.mTimeCount);
}
catch (Exception e)
{
throw new Exception(e.Message);
}
}
public void Dispose()
{
ResetMat();
matUnitList.Clear();
modelObj = null;
renderList = null;
}
#endregion
#region 内部接口
/// <summary>
/// 初始化材质球列表
/// </summary>
void InitMat()
{
renderList = modelObj.GetComponentsInChildren<SkinnedMeshRenderer>();
}
/// <summary>
/// 获取当前
/// </summary>
/// <returns></returns>
MaterialUnit GetCurMatUnit()
{
MaterialUnit materialUnit = null;
StateMaterial state = StateMaterial.NORMAL;
foreach (var matUnit in matUnitList)
{
if ((int)state < (int)matUnit.stateMaterial)
materialUnit = matUnit;
}
return materialUnit;
}
/// <summary>
/// 移除
/// </summary>
void RemoveMatUnit()
{
for (int i = 0; i < matUnitList.Count; i++)
{
if (matUnitList[i].mTimeCount <= 0)
{
matUnitList.Remove(matUnitList[i]);
break;
}
}
if (matUnitList.Count <= 0)
ResetMat();
}
/// <summary>
/// 获取对象
/// </summary>
/// <param name="stateMaterial"></param>
/// <returns></returns>
MaterialUnit GetMaterialUnit(StateMaterial stateMaterial)
{
MaterialUnit materialUnit = null;
foreach (var item in matUnitList)
{
if(item.stateMaterial == stateMaterial)
{
materialUnit = item;
break;
}
}
return materialUnit;
}
#endregion
#region 外部接口
/// <summary>
/// 重置色值
/// </summary>
public void ResetMat()
{
if (renderList.Length <= 0)
return;
try
{
foreach (var render in renderList)
{
render.GetPropertyBlock(prop);
prop.SetColor(colorID, defaultColor);
render.SetPropertyBlock(prop);
}
}
catch (Exception)
{
throw new Exception("matList 有问题");
}
}
/// <summary>
/// 添加色值改变dic
/// </summary>
/// <param name="state"></param>
/// <param name="time"></param>
/// <param name="materialUpdate"></param>
public void AddMatUnit(StateMaterial state, int time, MaterialUpdate materialUpdate = null)
{
if (renderList.Length <= 0)
return;
MaterialUnit matUnit = GetMaterialUnit(state);
if (matUnit != null)
{
matUnit.mTimeCount = time;
}
else
{
matUnit = new MaterialUnit(state, time, materialUpdate);
matUnitList.Add(matUnit);
}
}
/// <summary>
/// 受击色值变化
/// </summary>
/// <param name="state"></param>
/// <param name="time"></param>
/// <param name="updateCallBack"></param>
public void OnHit(StateMaterial state, int time)
{
if (renderList.Length <= 0)
return;
AddMatUnit(state, time, (renderList, remainTime) =>
{
if(remainTime > 0)
{
foreach (var render in renderList)
{
render.GetPropertyBlock(prop);
prop.SetColor(colorID, hitColor);
render.SetPropertyBlock(prop);
}
}
});
}
#endregion
}
主要改动是设置材质属性,而不是去收集材质球,直接改色值。
直接操作材质会让内存中又生成一份材质:material(Instance),但是直接操作材质属性快却不会,所以这一步优化还是值得引用的。
MaterialPropertyBlock()方法的官方解释:
文档是这样说的,材质属性块被用于Graphics.DrawMesh 和 Renderer.SetPropertyBlock两个API,当我们想要绘制许多相同材质但不同属性的对象时可以使用它。例如你想改变每个绘制网格的颜色,但是它却不会改变渲染器的状态。
这一点用来仅用来改变材质的色值,是再适合不过了。