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

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);
}
}
}