You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
317 lines
12 KiB
317 lines
12 KiB
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
using Entitas;
|
|
using Entitas.CodeGeneration.Attributes;
|
|
using UnityEngine;
|
|
|
|
namespace CoreGame.Render
|
|
{
|
|
[Combat, Unique]
|
|
public class JumpTextComponent : IComponent, IReset
|
|
{
|
|
public Queue<HurtData> hurtDatas = new Queue<HurtData>();
|
|
private readonly Dictionary<int, JumpTextParam> m_JumpTextListDict = new();
|
|
private const string SpriteTextPath = "Model/JumpText/SpriteJumpText";
|
|
private const string CriticalTextPath = "Model/JumpText/CritJumpText";
|
|
private const string NormalTextPath = "Model/JumpText/NormalJumpText";
|
|
private const string CureTextPath = "Model/JumpText/CureJumpText";
|
|
private const string HurtMissImagePath = "Assets/RawResources/UI/CoreGame/Hurt/hurt_miss.png";
|
|
|
|
public static bool s_ShowJumpText = true;
|
|
private static float s_HalfRandomAngle = BattleConst.JumpTextAngle / 2;
|
|
private static readonly StringBuilder s_StringBuilder = new StringBuilder();
|
|
private static readonly int[] s_Nums = new int[4];
|
|
|
|
private const int s_CharDictWidth_CN = 13;
|
|
|
|
private static char[] s_CharDict_CN =
|
|
{
|
|
//1,2,3,4,5,6,7,8,9,0,.,万,亿
|
|
'\"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', //普通
|
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '<', ':', ';', //暴击
|
|
'>', '?', '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'J', 'H', 'I', //火元素
|
|
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'X', 'V', 'W', //雷元素
|
|
'Y', 'Z', '[', '\\', ']', '^', '_', '`', 'a', 'b', 'e', 'c', 'd', //毒元素
|
|
'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r' //治疗
|
|
};
|
|
|
|
private static int[] s_NumIndex = { 9, 0, 1, 2, 3, 4, 5, 6, 7, 8 };
|
|
|
|
private static string ConvertValueToStr_CN(long value, int typeIndex)
|
|
{
|
|
s_StringBuilder.Clear();
|
|
Array.Fill(s_Nums, 0);
|
|
|
|
if (value < 10000)
|
|
{
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
var num = (int)(value / Math.Pow(10, 3 - i)) % 10;
|
|
s_Nums[i] = num;
|
|
}
|
|
|
|
int startIndex = 0;
|
|
while (s_Nums[startIndex] == 0)
|
|
{
|
|
startIndex++;
|
|
}
|
|
|
|
for (int i = startIndex; i < 4; i++)
|
|
{
|
|
s_StringBuilder.Append(s_CharDict_CN[typeIndex * s_CharDictWidth_CN + s_NumIndex[s_Nums[i]]]);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 10000亿
|
|
if (value >= 1000000000000)
|
|
{
|
|
value = 999999999999;
|
|
}
|
|
//1亿
|
|
var biggerThanOneHundredMillion = value >= 100000000;
|
|
double temp = biggerThanOneHundredMillion ? value * 0.00000001 : value * 0.0001;
|
|
|
|
// temp 肯定大于1, 若小于1,算法不成立
|
|
double tempScale = 1;
|
|
int count = 0;
|
|
while (temp * tempScale < 1000)
|
|
{
|
|
tempScale *= 10;
|
|
count++;
|
|
}
|
|
temp *= tempScale;
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
s_Nums[i] = (int)(temp / Math.Pow(10, 3 - i)) % 10;
|
|
}
|
|
var pointIndex = 3 - count;
|
|
|
|
for (int i = 0; i < 4; i++)
|
|
{
|
|
s_StringBuilder.Append(s_CharDict_CN[typeIndex * s_CharDictWidth_CN + s_NumIndex[s_Nums[i]]]);
|
|
if (pointIndex == i && pointIndex != 3)
|
|
{
|
|
s_StringBuilder.Append(s_CharDict_CN[typeIndex * s_CharDictWidth_CN + 10]);
|
|
}
|
|
}
|
|
|
|
s_StringBuilder.Append(biggerThanOneHundredMillion
|
|
? s_CharDict_CN[typeIndex * s_CharDictWidth_CN + 12]
|
|
: s_CharDict_CN[typeIndex * s_CharDictWidth_CN + 11]);
|
|
}
|
|
return s_StringBuilder.ToString();
|
|
}
|
|
|
|
|
|
private string ConvertValueToStr_Temp(long value, int typeIndex)
|
|
{
|
|
s_StringBuilder.Clear();
|
|
long temp = value;
|
|
int length = 0;
|
|
|
|
// 计算数字的位数
|
|
while (temp != 0)
|
|
{
|
|
temp /= 10;
|
|
length++;
|
|
}
|
|
|
|
// 存储每一位数字
|
|
int[] digits = new int[length];
|
|
|
|
// 填充数组
|
|
temp = value;
|
|
for (int i = length - 1; i >= 0; i--)
|
|
{
|
|
digits[i] = (int)(temp % 10);
|
|
temp /= 10;
|
|
}
|
|
|
|
// 输出每一位数字
|
|
foreach (var digit in digits)
|
|
{
|
|
s_StringBuilder.Append(s_CharDict_CN[typeIndex * s_CharDictWidth_CN + s_NumIndex[digit]]);
|
|
}
|
|
return s_StringBuilder.ToString();
|
|
}
|
|
|
|
private string GetJumpTextContent(long value, int typeIndex)
|
|
{
|
|
return ConvertValueToStr_CN(value, typeIndex);
|
|
// return ConvertValueToStr_Temp(value, typeIndex);
|
|
}
|
|
|
|
|
|
public void Reset()
|
|
{
|
|
hurtDatas.Clear();
|
|
foreach (var param in m_JumpTextListDict)
|
|
{
|
|
var paramValue = param.Value;
|
|
GoPoolDic.GetPool(paramValue.reuseGoData.path).ReleaseGo(paramValue.reuseGoData);
|
|
SptPool<JumpTextParam>.Free(ref paramValue);
|
|
}
|
|
m_JumpTextListDict.Clear();
|
|
}
|
|
|
|
public void PushHurtData(HurtData hurtData)
|
|
{
|
|
if (!s_ShowJumpText)
|
|
return;
|
|
|
|
if (hurtDatas.Count == 0)
|
|
{
|
|
Contexts.Combat.jumpTextEntity.ReplaceComponent(CombatComponentsLookup.JumpText, this);
|
|
}
|
|
|
|
var malloc = SptPool<HurtData>.Malloc();
|
|
malloc.CopyFrom(hurtData);
|
|
hurtDatas.Enqueue(malloc);
|
|
}
|
|
|
|
private class JumpTextParam : ISptPool
|
|
{
|
|
public Vector2 pos;
|
|
public string content;
|
|
public bool isCritical;
|
|
public bool isHeadShot;
|
|
public ReuseGoData reuseGoData;
|
|
|
|
public void Reset()
|
|
{
|
|
pos = Vector2.zero;
|
|
content = null;
|
|
isCritical = false;
|
|
isHeadShot = false;
|
|
reuseGoData = null;
|
|
}
|
|
}
|
|
|
|
public void ShowChangeHpJumpText(HurtData hurtData)
|
|
{
|
|
var dst = hurtData.dst;
|
|
var pos = dst.transformProxy.position;
|
|
if (dst.bindPointProxy?.TryGetBindPointOrDefault(BindPointType.JumpText, out var trans) == true)
|
|
{
|
|
pos = trans.position;
|
|
}
|
|
|
|
if ((hurtData.hurtRet & HurtRet.Miss) == HurtRet.Miss)
|
|
{
|
|
CreateJumpText(SpriteTextPath, pos, HurtMissImagePath);
|
|
return;
|
|
}
|
|
|
|
if ((hurtData.hurtRet & HurtRet.Cure) == HurtRet.Cure)
|
|
{
|
|
var value = hurtData.calculateDeltaHp;
|
|
if (value == 0)
|
|
return;
|
|
var content = GetJumpTextContent(value, 5);
|
|
CreateJumpText(CureTextPath, pos, content);
|
|
return;
|
|
}
|
|
|
|
bool isHeadShot = (hurtData.hurtRet & HurtRet.HeadShot) == HurtRet.HeadShot;
|
|
|
|
if ((hurtData.hurtRet & HurtRet.Critical) == HurtRet.Critical)
|
|
{
|
|
var value = -hurtData.calculateDeltaHp - hurtData.hpShieldDelta;
|
|
if (value == 0)
|
|
return;
|
|
var content = GetJumpTextContent(value, 1);
|
|
CreateJumpText(CriticalTextPath, pos, content, isHeadShot, true);
|
|
return;
|
|
}
|
|
|
|
if ((hurtData.hurtRet & HurtRet.Normal) == HurtRet.Normal)
|
|
{
|
|
int typeIndex = 0;
|
|
switch (hurtData.elementType)
|
|
{
|
|
case ElementType.None:
|
|
typeIndex = 0;
|
|
break;
|
|
case ElementType.Fire:
|
|
typeIndex = 2;
|
|
break;
|
|
case ElementType.Thunder:
|
|
typeIndex = 3;
|
|
break;
|
|
case ElementType.Toxic:
|
|
typeIndex = 4;
|
|
break;
|
|
}
|
|
var value = -hurtData.calculateDeltaHp - hurtData.hpShieldDelta;
|
|
if (value == 0)
|
|
return;
|
|
var content = GetJumpTextContent(value, typeIndex);
|
|
CreateJumpText(NormalTextPath, pos, content, isHeadShot);
|
|
return;
|
|
}
|
|
}
|
|
|
|
private void CreateJumpText(string prefabPath, Vector2 pos, string content, bool isHeadShot = false,
|
|
bool isCritical = false)
|
|
{
|
|
var param = SptPool<JumpTextParam>.Malloc();
|
|
param.pos = pos;
|
|
param.content = content;
|
|
param.isHeadShot = isHeadShot;
|
|
param.isCritical = isCritical;
|
|
var reuseGoData = GoPoolDic.GetPool(prefabPath).GetNewGo(CreateJumpTextAction, param);
|
|
param.reuseGoData = reuseGoData;
|
|
m_JumpTextListDict.Add(reuseGoData.GetSeq(), param);
|
|
}
|
|
|
|
private void DestroyJumpText(object seqObj)
|
|
{
|
|
var seq = (int)seqObj;
|
|
if (!m_JumpTextListDict.TryGetValue(seq, out var param)) return;
|
|
GoPoolDic.GetPool(param.reuseGoData.path).ReleaseGo(param.reuseGoData);
|
|
SptPool<JumpTextParam>.Free(ref param);
|
|
m_JumpTextListDict.Remove(seq);
|
|
}
|
|
|
|
private void CreateJumpTextAction(ReuseGoData reuseGoData)
|
|
{
|
|
var go = reuseGoData.go;
|
|
var param = (JumpTextParam)reuseGoData.param;
|
|
var distance = RandomSrv.Range(0, BattleConst.JumpTextRadius);
|
|
var angle = RandomSrv.Range(-s_HalfRandomAngle, s_HalfRandomAngle);
|
|
var radians = angle * Mathf.Deg2Rad;
|
|
var dir = new Vector2(Mathf.Sin(radians), Mathf.Cos(radians));
|
|
go.transform.position = param.pos + dir * distance;
|
|
go.TryGetComponent<JumpText>(out var jumpText);
|
|
switch (jumpText.rendererType)
|
|
{
|
|
case JumpText.RendererType.TextMeshPro:
|
|
jumpText.textMeshPro.text = param.content;
|
|
jumpText.textMeshPro.sortingOrder = param.isCritical ? 1003 : 1001;
|
|
break;
|
|
case JumpText.RendererType.Sprite:
|
|
GameObjectUtil.LoadAssetAsync<Sprite>(param.content, go, (_, obj) =>
|
|
{
|
|
jumpText.spriteRenderer.sprite = obj as Sprite;
|
|
jumpText.spriteRenderer.sortingOrder = 1000;
|
|
});
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException();
|
|
}
|
|
if (jumpText.iconRenderers.Length > 0)
|
|
{
|
|
jumpText.iconRenderers[0].gameObject.SetActiveWrap(param.isHeadShot);
|
|
}
|
|
foreach (var icon in jumpText.iconRenderers)
|
|
{
|
|
icon.sortingOrder = param.isCritical ? 1002 : 1000;
|
|
}
|
|
go.SetActiveWrap(true);
|
|
|
|
Contexts.Combat.renderTimerEntity?.renderTimer.AddTimer(1f, reuseGoData.GetSeq(), DestroyJumpText);
|
|
}
|
|
}
|
|
}
|