为了避免策划有屏幕上显示多个boss的血条的需求,设计血条需要考虑多个的情况。
例如:
利用列表的control child size和item里面的锚点定好来实现。
在分享一段boss多段血条加上血条缓冲的代码:
[LuaCallCSharp]
public class BossBlood:MonoBehaviour
{
private static int s_lastID;
private static BossBlood s_target;
public static void OnObj(int nID)
{
if(s_lastID!=nID)
{
//获得s_target
}
}
public static void ResetBlood(int nID)
{
OnObj(nID);
s_target.ResetBlood();
}
public static void InitBlood(int nID,Int64 uid)
{
OnObj(nID);
s_target.InitBlood(uid);
}
public static void Play(int nID)
{
OnObj(nID);
s_target.Play();
}
struct BloodState
{
public int curHp;
public int maxHp;
public int topColorIndex;
public int bloodLayer;
}
public Image img_top;
public Image img_buffer;
public Image img_bottom;
public TextMeshProUGUI text_bloodNum;
private IMonster monster;
private cfg_Monster cfg;
private bool isPlay = false;
private BloodState bloodState; //播完之后终止的状态
public void ResetBlood()
{
isPlay = false;
img_top.color = new Color(img_top.color.r,img_top.color.g,img_top.color.b,0);
img_bottom.color = new Color(img_bottom.color.r, img_bottom.color.g, img_bottom.color.b, 0);
this.monster = null;
}
public void InitBlood(Int64 uid)
{
this.monster = rkt.Common.GameHelp.GetEntityByUID(uid) as IMonster;
int curHp = monster.GetNumProp((int)EMCREATURE_PROP.CREATURE_PROP_CUR_HP);
int maxHp = monster.GetNumProp((int)EMCREATURE_PROP.CREATURE_PROP_MAX_HP);
if(curHp<=0)
{
Debug.LogError($"init , curhp == 0");
ResetBlood();
return;
}
int decreaseHp = maxHp - curHp; // 当前减少的血量
cfg = this.monster.GetMonsterCfg();
int totalBloodNum = GetCfgBloodNum(cfg);
float stepBloodValue = 1 / (float)totalBloodNum * maxHp;
int decreaseBloodNum = Mathf.FloorToInt(decreaseHp / stepBloodValue);
int remainBloodNum = totalBloodNum - decreaseBloodNum;
text_bloodNum.SetText("X"+remainBloodNum);
int topColorIndex = GetTopColorIndex(decreaseBloodNum);
SetHpColor(img_top,topColorIndex);
float topHpRate = 1- (decreaseHp - decreaseBloodNum * stepBloodValue) / (float)stepBloodValue;
SetHpRate(img_top, topHpRate);
SetHpRate(img_buffer, topHpRate);
int bottomColorIndex = GetBottomColorIndex(topColorIndex, remainBloodNum);
SetHpColor(img_bottom, bottomColorIndex);
SetHpRate(img_bottom, 1);
SaveBloodState(maxHp,curHp, remainBloodNum, topColorIndex);
}
private int GetCfgBloodNum(cfg_Monster cfg)
{
if (cfg.nBloodNum > 0)
return cfg.nBloodNum;
return 1;
}
private void SaveBloodState(int maxHp,int curHp,int bloodLayer,int topColorIndex)
{
bloodState.maxHp = maxHp;
bloodState.curHp = curHp;
bloodState.bloodLayer = bloodLayer;
bloodState.topColorIndex = topColorIndex;
}
public void Play()
{
if (IsNeedInitBlood()) //是否跨段
{
//加血
InitBlood(monster.GetUID());
return;
}
isPlay = true;
}
private bool IsNeedInitBlood()
{
int curHp = monster.GetNumProp((int)EMCREATURE_PROP.CREATURE_PROP_CUR_HP);
int maxHp = monster.GetNumProp((int)EMCREATURE_PROP.CREATURE_PROP_MAX_HP);
int decreaseHp = maxHp - curHp; // 当前减少的血量
int totalBloodNum = GetCfgBloodNum(cfg);
float stepBloodValue = 1 / (float)totalBloodNum * maxHp;
int decreaseBloodNum = Mathf.FloorToInt(decreaseHp / stepBloodValue);
int remainBloodNum = totalBloodNum - decreaseBloodNum;
if (remainBloodNum > bloodState.bloodLayer)
{
return true;
}
if(!isPlay)
{
if(curHp > this.bloodState.curHp)
{
return true;
}
if(maxHp!=this.bloodState.maxHp)
{
return true;
}
}
return false;
}
private bool SetBloodBuffer()
{
float needRate = this.img_top.fillAmount;
float nowRate = this.img_buffer.fillAmount;
if (nowRate <= needRate)
{
this.img_buffer.fillAmount = needRate;
return true;
}
if(Mathf.Abs(needRate-nowRate)<0.01f)
{
this.img_buffer.fillAmount = needRate;
return true;
}
nowRate = Mathf.Lerp(nowRate, needRate, Time.deltaTime*5);
this.img_buffer.fillAmount = nowRate;
return false;
}
public void Update()
{
if(isPlay)
{
int curHp = monster.GetNumProp((int)EMCREATURE_PROP.CREATURE_PROP_CUR_HP);
int maxHp = monster.GetNumProp((int)EMCREATURE_PROP.CREATURE_PROP_MAX_HP);
if (curHp <= 0)
{
Debug.LogError($"update , curhp == 0");
ResetBlood();
return;
}
int decreaseHp = maxHp - curHp; // 当前减少的血量
int totalBloodNum = GetCfgBloodNum(cfg);
float stepBloodValue = 1 / (float)totalBloodNum * maxHp;
int decreaseBloodNum = Mathf.FloorToInt(decreaseHp / stepBloodValue);
int remainBloodNum = totalBloodNum - decreaseBloodNum;
if(remainBloodNum<bloodState.bloodLayer)
{
SetHpRate(img_top, 0);
if(SetBloodBuffer())
{
// 读完一段
SaveBloodState(maxHp,curHp, remainBloodNum, GetTopColorIndex(decreaseBloodNum));
int topColorIndex = GetTopColorIndex(decreaseBloodNum);
SetHpColor(img_top, topColorIndex);
SetHpRate(img_top,1);
SetHpColor(img_bottom, GetBottomColorIndex(topColorIndex, remainBloodNum));
SetHpRate(img_bottom, 1);
text_bloodNum.SetText("X" + remainBloodNum);
}
return;
}
else if(remainBloodNum>bloodState.bloodLayer)
{
Debug.LogError($"{remainBloodNum}大于当前层数,不可能");
}
float topHpRate =1- (decreaseHp - decreaseBloodNum * stepBloodValue) / (float)stepBloodValue;
SetHpRate(img_top,topHpRate);
if(SetBloodBuffer())
{
SaveBloodState(maxHp,curHp,remainBloodNum,GetTopColorIndex(decreaseBloodNum));
isPlay = false;
}
}
}
private void SetHpRate(Image img,float rate) {
img.fillAmount = rate;
}
private void SetHpColor(Image img,int colorIndex)
{
if(colorIndex!=-1)
{
SpriteSwitcher target = img.GetComponent<SpriteSwitcher>();
if (target)
target.Switch(colorIndex);
img.color = new Color(img.color.r,img.color.g,img.color.b,1);
}
else
{
img.color = new Color(img.color.r, img.color.g, img.color.b, 0);
}
}
private int GetBottomColorIndex(int topColorIndex,int remainBloodNum)
{
int result = topColorIndex - 1<0?4:topColorIndex-1;
if(remainBloodNum==1)
{
result = -1;
}
return result;
}
private int GetTopColorIndex(int decreaseBloodNum)
{
int totalBloodNum = GetCfgBloodNum(cfg);
int result = totalBloodNum - 1;
if (result > 5)
{
int resultNum = totalBloodNum % 5;
result = resultNum == 0 ? 4 : resultNum - 1;
}// 起始位置
while (decreaseBloodNum>0)
{
result--;
if (result < 0) result = 4;
--decreaseBloodNum;
}
return result;
}
}