UnityCommon/Role/Role.cs
2025-01-09 13:30:13 +08:00

763 lines
24 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Threading.Tasks;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
using TMPro;
using Debug = UnityEngine.Debug;
using UnityEngine.EventSystems;
public enum Camp
{/// <summary>
/// 玩家
/// </summary>
Player,
/// <summary>
/// 怪物
/// </summary>
Enemy,
/// <summary>
/// 中立
/// </summary>
Neutral
}
public enum CharacterFlags
{
no=0<<0,
fly = 1 << 0,
land = 1 << 1,
big = 1 << 2,
min = 1 << 3,
FlyBig =fly|big,
FlyMin=fly|min,
LandBig = land | big,
LandMin = land | min,
}
/// <summary>
/// 角色基类,玩家处理事件
/// </summary>
[ExecuteInEditMode]
public class Role : Fun
{
[Header("Id")] public string id;
[Header("名称")] public string Name;
[Header("阵营")] public Camp camp ;
[Header("血量")] public float hp = 100f;//血量
public float maxHp;
[Header(("死亡动画编号"))] public int dieIndex=-1;
[Header("hp填充直接扣")] public Image Hpfiil;
[Header("hp填充慢慢扣")] public Image HpfiilYello;
[Header("扣血填充")] public GameObject HpTextPrefab;
[Header("自己的画布")]public Canvas _Canvas;
[Header("自己的图片")] public SpriteRenderer spriteRenderers; // 存储所有的SpriteRenderer组件
[Header("被打的方向")] public int HurtDirectin;
public string Quality;//品质
public string Elements;//属性
public string Info;//详情
public string SkillId;//技能
public string AttackType;//攻击类型
public string AttackActionType;//攻击作用类型
public float AttackRange;//攻击范围
public float AttackCD;//攻击CD
public float CritRate;//暴击率
public float CriticalHitRateBonus;//暴击加成
[Header("击杀数量")] public int killNum;
[Header("是不是魔法伤害")] public bool isMoFa=false;
public float Hp
{
get => hp;
set
{
float temp = hp;
hp = value;
// 更新血条显示
if (Hpfiil != null)
{
Hpfiil.fillAmount = hp / maxHp;
// 使用 DOTween 动画平滑过渡血条填充
DOTween.To(() => HpfiilYello.fillAmount, x => HpfiilYello.fillAmount = x, hp / maxHp, 0.8f) // 0.5f 为过渡时间
.SetEase(Ease.InOutQuad); // 使用缓动效果,使血条变化更加平滑
if (UIContorl.instance.NowShowInfo != null && UIContorl.instance.NowShowInfo.Id == 1 && this == UIContorl.instance.NowShowInfo.role)
{
UIContorl.instance.NowShowInfo.UpDateShow("1", "Enemy_001", "0", "3", "1", "测试文档一", hp, maxHp);
}
}
// 更新血量文本效果
if (HpTextPrefab != null && hp < maxHp)
{
hit();
Navigation.StopPathDoTween(0.2f); // 停止任何进行中的 DoTween 动画0.2s为示例值
GameObject go = GameObject.Instantiate(HpTextPrefab, _Canvas.transform);
go.GetComponent<SnowHpControl>().direction = HurtDirectin;
if (isGoodDamege)
{
go.GetComponent<SnowHpControl>().CreateText(true);
isGoodDamege = false;
}
else
{
go.GetComponent<SnowHpControl>().CreateText();
}
if (temp - hp>0)
{
if (isMoFa)
{
go.GetComponent<Text>().text = "<color=blue>" + (temp - hp).ToString("F0") + "</color>"; // 显示伤害值
isMoFa = false;
}
else
{
go.GetComponent<Text>().text = (temp - hp).ToString("F0"); // 显示伤害值
}
}
}
// 判断角色是否死亡
if (hp <= 0)
{
die(); // 执行死亡处理
}
}
}
[Header("掉落")] public int gold = 6;
public int Gold
{
[DebuggerStepThrough]
get => gold;
[DebuggerStepThrough]
set => gold = value;
}
[Header("攻击力")] private float attack = 10f;
[Header("攻击力上限")] public float MaxAttack = 10f;
[Header("攻击力下限")] public float MinAttack = 10f;
public bool isGoodDamege=false;//是否暴击
public float Attack
{
get => attack;
set => attack = value;
}
[Header("等级")] private int level = 1;
public int Level
{
[DebuggerStepThrough] get => level;
[DebuggerStepThrough] set => level = value;
}
[Header("物理护甲")] public int physicalArmor = 10;//物理护甲
[Header("魔法护甲")] public int magicArmor = 5;//魔法护甲
[Header("导航组件")] public SimplePathfindingDoTween Navigation;
[System.Serializable ]
public class AnimationList//动画list
{
//[Header("动画是否循环")] public bool isloop = false;
[Header("动画图片")] public List<Sprite> value; // 字典的值
[Header("角色动画帧数间隔(毫秒)")] public int CharacterAnimationFrameInterval = 50;
}
[Header("角色动画")] public List<AnimationList> AnimationTree = new List<AnimationList>();
[Header("角色动画播放")] public int animationHighlight = 0;
[Header("角色精灵位置")] public SpriteRenderer spriteRenderer;
[Header("角色Image位置")] public Image image;
public delegate void AnimationItem(int AnimationItem);
public event AnimationItem OnAnimationStart;
public event AnimationItem OnAnimationIng;
public event AnimationItem OnAnimationEnd;
[Header("动画是否正常播放")] public bool isAnimationPlay = false;//动画是否正常播放
[Header("碰撞体")]public Collider2D mycollider;
[Header("攻击脚本")] public Attack attackClass;
[Header("当前播放图片序列")] public int CurrentIndex;
public int hitIndex = 2;//受击动画索引
public int normalIndex = 0;//移动动画索引
public bool isHit=false;//
public List<BUff> buffList = new List<BUff>();
public CharacterFlags myTags = 0;
public bool hasfalg(CharacterFlags flag)
{
return (myTags & flag) == flag;
}
public SkillUp mySkillUp;
/// <summary>
/// 储存buff
/// </summary>
public List<Action<Role>> storageBuff = new List<Action<Role>>();
/// <summary>
/// 使用buff
/// </summary>
public List<Action<Role>> PlayerBuff=new List<Action<Role>>();
public bool IsDead = false;
public int HaveDieTime = 0;
public virtual async void Start()
{
if (mySkillUp == null)
{
mySkillUp = this.transform.GetComponent<SkillUp>();
}
if (mySkillUp == null)
{
UnityEngine.Debug.LogError(this.name+"mySkillUp is no");
}
maxHp = hp;
SetSelfInfo();
//SetAttackRange();//设置攻击范围
if (Application.isPlaying)
{
if (attackClass)
{
attackClass.role = this;
}
UpdateBuff();
}
tag = Enum.GetName(typeof(Camp), camp);
updateAnimation();
}
/// <summary>
/// 添加Buff
/// </summary>
/// <param name="buffAction"></param>
public void AddBuff(List<Action<Role>> buffs, Action<Role> buffAction)
{
buffs.Add(buffAction);
UnityEngine.Debug.LogError(this.name + "添加buff到"+ buffs);
}
public void RemoveBuff(List<Action<Role>> buffs, Action<Role> buffAction)
{
buffs.Remove(buffAction);
UnityEngine.Debug.LogError(this.name + "移除" + buffs);
}
/// <summary>
/// 执行所有当前 Buff
/// </summary>
public void ApplyBuffs()
{
foreach (var buff in PlayerBuff)
{
UnityEngine.Debug.LogError(this.name + "进入执行buff判断");
buff.Invoke(this); // 将自己作为目标传递
}
// 清空 Buff 列表,假设 Buff 是一次性的
PlayerBuff.Clear();
}
/// <summary>
/// 角色动画更新
/// </summary>
public async void updateAnimation()
{
while (true)
{
if (hp < 0)
{
Debug.LogError("!!!!!!!!!!!跳过while");
return;
}
if (AnimationTree.Count == 0)
{
isAnimationPlay = false;
return;
}
isAnimationPlay = true;
if (animationHighlight >= AnimationTree.Count)
{
animationHighlight = AnimationTree.Count - 1;
}
else if (animationHighlight < 0)
{
animationHighlight = 0;
}
List<Sprite> LightSprite = AnimationTree[animationHighlight].value;
if (LightSprite == null)
{
isAnimationPlay = false;
return;
};
OnAnimationStart?.Invoke(animationHighlight);
var lsanimationHighlight = animationHighlight;
foreach (Sprite sprite in LightSprite)
{
if (lsanimationHighlight == animationHighlight)
{
if (image != null)
{
image.sprite = sprite;
}
else if (spriteRenderer != null)
{
spriteRenderer.sprite = sprite;
}
if (animationHighlight >= 0 && animationHighlight < AnimationTree.Count)
{
if (hp < 0)
{
Debug.LogError("@@@@@@@@@@@@跳过while");
return;
}
OnAnimationIng?.Invoke(animationHighlight);
await Task.Delay(AnimationTree[animationHighlight].CharacterAnimationFrameInterval);
}
}
else
{
break;
}
}
OnAnimationEnd?.Invoke(lsanimationHighlight);
if (lsanimationHighlight == dieIndex)
{
//SpawnPool.intance.DeadNumber += 1;
SpawnMonster.intance.enemysList.Remove(this.gameObject);
if (SpawnMonster.intance.enemysList.Count<=0)
{
SpawnMonster.intance.Index += 1;
}
Destroy(this.gameObject);
//Destroy(this);
}
if (lsanimationHighlight == hitIndex)
{
animationHighlight = normalIndex;
}
}
}
/// <summary>
/// 角色死亡
/// </summary>
public virtual void die()
{
if (Application.isPlaying)
{
GetComponent<CharacterClick>().HideInfoPanel();
animationHighlight = dieIndex;
Navigation.PauseAnimation();
if (!IsDead)
{
UIContorl.instance.Killnumber++;
SkillBox.instance.AddExperience(gold, this.gameObject.transform);
IsDead = true;
}
HaveDieTime++;
}
}
/// <summary>
/// 角色受到攻击
/// </summary>
public virtual void hit()
{
if (Application.isPlaying)
{
animationHighlight = hitIndex;
}
}
/// <summary>
/// 角色减速
/// </summary>
public void SlowDown(float num)
{
Navigation.speedFactor *= num;
}
/// <summary>
/// 单位更新buff
/// </summary>
async void UpdateBuff()//单位buff更新
{
while (true)
{
List<BUff> deleteArr = new List<BUff>();
foreach (BUff buffItem in buffList)
{
if (buffItem.executionInterval <= 0)
{
buffItem.executionInterval = buffItem.executionInterval_max;
buffItem.Funaction.Invoke(buffItem.value);
}
buffItem.executionInterval -= 0.1f;
buffItem.timeLeft -= 0.1f;
if (buffItem.timeLeft <= 0)
{
deleteArr.Add(buffItem);
}
}
foreach (BUff item in deleteArr)
{
buffList.Remove(item);
}
await Task.Delay(100);//buff检测最小时间0.1秒执行一次
}
}
/// <summary>
/// 重置角色所有状态
/// </summary>
public void ResetAllStatus()
{
IsDead = false;
// 重置血量
Hp = 100f;
// 重置攻击力
Attack = 10f;
// 重置护甲
physicalArmor = 10;
magicArmor = 5;
// 重置等级
Level = 1;
// 重置金币
Gold = 10;
// 清空 Buff 列表
buffList.Clear();
// 如果有导航组件,停止当前的导航行为
if (Navigation != null)
{
//Navigation.Stop(); // 假设你有 Stop 方法来停止导航
}
// 重置角色动画
animationHighlight = 0;
isAnimationPlay = false;
// 重置碰撞体(根据需求是否需要调整)
if (mycollider != null)
{
mycollider.enabled = true; // 启用碰撞体
}
// 如果有其他需要重置的状态,可以在这里添加
}
public void FlashRedEffect(int color = 0, float time = 0.2f)//0、1、2 红、蓝、紫
{
// 如果spriteRenderer存在
if (spriteRenderer != null)
{
// 创建一个Sequence来确保动画按顺序执行
Sequence sequence = DOTween.Sequence();
// 颜色变化
if (color == 0)
{
// 变为红色并恢复白色
sequence.Append(spriteRenderer.DOColor(UnityEngine.Color.red, 0.2f))
.Append(spriteRenderer.DOColor(UnityEngine.Color.white, time));
}
else if (color == 1)
{
// 更冷的深蓝色
UnityEngine.Color frostBlueWithAlpha = new UnityEngine.Color(0.2f, 0.5f, 1f); ; // 冰冻蓝色
// 变为蓝色并恢复白色
sequence.Append(spriteRenderer.DOColor(frostBlueWithAlpha, 0.2f))
.Append(spriteRenderer.DOColor(UnityEngine.Color.white, time));
}
else if (color == 2)
{
// 中毒的紫色
UnityEngine.Color poisonPurpleWithAlpha = new UnityEngine.Color(0.6f, 0.2f, 0.8f); // 紫色调,带有绿色的感觉
// 变为紫色并恢复白色
sequence.Append(spriteRenderer.DOColor(poisonPurpleWithAlpha, 0.2f))
.Append(spriteRenderer.DOColor(UnityEngine.Color.white, time));
}
// 开始执行Sequence
sequence.Play();
}
}
public void StopDoTween(float stopTime)
{
// 暂停当前的动画
transform.DOPause();
// 插入一个自定义的延迟(僵直时间)
DOTween.To(() => 0f, x => { }, 0f, stopTime).OnKill(() =>
{
// 在延迟结束后恢复动画
transform.DOPlay();
});
}
public void SetSelfInfo()
{
if (camp==Camp.Player)
{
// Debug.Log("攻击力赋值==============================" + MengyaoInfo.Instance.m_Mengyao.Count);
foreach (Character character in MengyaoInfo.Instance.m_Mengyao)
{
if (id ==character.Id)
{
Name = character.Name;
MinAttack = int.Parse(character.MinAttack);
MaxAttack = int.Parse(character.MaxAttack);
AttackCD = float.Parse(character.AttackCD);
CritRate = float.Parse(character.CritRate);
Quality=character.Quality;//品质
Elements=character.Elements;//属性
Info=character.Info;//详情
SkillId=character.SkillId;//技能
AttackType=character.AttackType;//攻击类型
AttackActionType=character.AttackActionType;//攻击作用类型
CriticalHitRateBonus = float.Parse(character.CriticalHitRateBonus);
AttackRange = float.Parse(character.AttackRange);
//Debug.Log("攻击力赋值++++++++++++++++++++++++++++++");
}
}
}
}
/// <summary>
/// 计算伤害
/// </summary>
/// <param name="self">造成者</param>
/// <param name="Target">目标</param>
/// <returns></returns>
/// 萌妖每次攻击对敌人造成伤害=a*(1+g+d+e)*(1-b/100)*c*(1+h)
//暴击情况下萌妖每次攻击对敌人造成伤害=a* (1+g+d+e)*(1-b/100)*c* (1+h)*(2+f)
public float DamageCreate(Role Target)//伤害生成
{
// 生成普通伤害
float hurt = UnityEngine.Random.Range(MinAttack, MaxAttack);
// 判断是否暴击
float critChance = UnityEngine.Random.Range(0f, 1f); // 生成一个0到1之间的随机数
//敌人防御力
float TargetDefense = Target.gameObject.GetComponent<enemy>().Defense;
if (critChance < CritRate*(1+mySkillUp.CriticalRate)) // 如果暴击发生
{
// 计算暴击伤害(普通伤害乘以暴击加成)
hurt *= (2 + CriticalHitRateBonus*(1+ mySkillUp.CriticalDamage));
isGoodDamege = true;
UnityEngine.Debug.Log("暴击发生!伤害增加");
}
hurt *= (1 + mySkillUp.DamageUp);
// Debug.LogError("伤害加成:"+ mySkillUp.DamageUp);
if (Target.hasfalg(CharacterFlags.big)) // 如果是大型敌人
{
hurt*=(1+mySkillUp.DamageOfBig);
//Debug.LogError("大型敌人加成");
}
if (Target.hasfalg(CharacterFlags.min)) // 如果是小型敌人
{
hurt *= (1 + mySkillUp.DamageOfMin);
//Debug.LogError("小型敌人加成");
}
if (Target.hasfalg(CharacterFlags.fly)) // 如果是飞行敌人
{
hurt *= (1 + mySkillUp.DamageOfSky);
//Debug.LogError("飞行敌人加成");
}
if (Target.hasfalg(CharacterFlags.land)) // 如果是地面敌人
{
hurt *= (1 + mySkillUp.DamageOfland);
//Debug.LogError("地面敌人加成");
}
if (Target.GetComponent<enemy>().isSlowed) // 如果敌人减速
{
hurt *= (1 + mySkillUp.DamageOfSlow);
UnityEngine.Debug.Log("减速敌人加成");
}
hurt *= (1 + WuxingDamage(Target.gameObject.GetComponent<enemy>()));//计算五行属性伤害
hurt *= HujiaDamage(Target.gameObject.GetComponent<enemy>());//计算破甲伤害
if (hurt * (1 - TargetDefense / 100) < 1)
{
hurt = 1;
}
else
{
hurt *= (1 - TargetDefense / 100);
}
if (GetComponent<enemy>())
{
GetComponent<enemy>().HarmNumber += Mathf.Round(hurt);
}
return Mathf.Round(hurt);
}
public virtual void SlowDown(float slowFactor, float duration)
{
}
public void ApplyPoisonDamage(float poisonDuration, float poisonInterval, float poisonDamage, Role AttackRole)
{
// 使用异步方法时要确保调用时使用 await或者启动异步任务
ApplyPoisonCoroutine(poisonDuration, poisonInterval, poisonDamage, AttackRole);
}
private async Task ApplyPoisonCoroutine(float poisonDuration, float poisonInterval, float poisonDamage, Role AttackRole)
{
float elapsedTime = 0f;
FlashRedEffect(2, poisonDuration);
// 通过一个时间间隔来每隔一段时间触发伤害
while (elapsedTime < poisonDuration)
{
// 等待下一个伤害时间点
await Task.Delay((int)(poisonInterval * 1000)); // 乘以1000转换为毫秒
// 每隔 poisonInterval 执行一次伤害
this.bloodLoss(new object[] { this, poisonDamage, DamageType.magicDamage, AttackRole });
//Hp -= poisonDamage;
UnityEngine.Debug.Log($"中毒伤害: {poisonDamage}, 当前血量: {hp}/{maxHp}");
elapsedTime += poisonInterval;
}
UnityEngine.Debug.Log("中毒效果结束");
}
public float WuxingDamage(enemy Target)//五行属性伤害计算 返回倍率减伤或增加伤害
{
// 克制关系表(使用二维数组或字典表示)
// 行:敌人属性,列:萌妖属性
// 正数表示加成负数表示减成0表示无影响
float[,] attributeRelations = new float[5, 5]
{
// 金 木 水 火 土
{ 0f, 0.5f, 0f, -0.25f, 0f }, // 金
{ -0.25f, 0f, 0f, 0f, 0.5f }, // 木
{ 0f, 0f, 0f, 0.5f, -0.25f }, // 水
{ 0.5f, 0f, -0.25f, 0f, 0f }, // 火
{ 0f, -0.25f, 0.5f, 0f, 0f } // 土
};
// 获取克制关系
float relation = attributeRelations[ (int)GetComponent<enemy>().elementType,(int)Target.elementType];
// 如果是正数,表示加成,增加伤害
// 如果是负数,表示减成,减少伤害
// UnityEngine.Debug.Log("属性关系:"+"萌妖"+ GetComponent<enemy>().elementType+"::"+"敌人"+ Target.elementType+"伤害加成"+relation);
return relation;
}
public float HujiaDamage(enemy Target)//护甲伤害计算 返回倍率减伤或增加伤害
{
// 克制关系表(使用二维数组表示,行表示攻击类型,列表示防御类型)
float[,] attackDefenseRelations = new float[5, 4]
{
// 轻甲 重甲 魔盾 灵体
{ 1f, 0.5f, 1f, 0.35f }, // 普通攻击
{ 0.6f, 1.5f, 1f, 0.35f }, // 破甲攻击
{ 1.5f, 0.75f, 1f, 0.35f }, // 刺穿攻击
{ 1.25f, 1.5f, 0.5f, 2f }, // 魔法攻击
{ 1f, 1f, 1f, 1f } // 真实攻击
};
// 获取克制关系
float relation = attackDefenseRelations[int.Parse(AttackType), (int)Target.defenseType];
// 如果是正数,表示加成,增加伤害
// 如果是负数,表示减成,减少伤害
//UnityEngine.Debug.Log("破甲关系:" + "萌妖" + AttackType + "::" + "敌人" + Target.defenseType + "伤害加成" + relation);
return relation;
}
void OnDestroy()
{
this.AnimationTree = null;
// 清理动态加载资源
if (transform.GetComponent<Renderer>() != null)
{
var material = transform.GetComponent<Renderer>().material;
if (material != null) Destroy(material);
var texture = material.mainTexture;
if (texture != null) Destroy(texture);
}
// 停止协程
StopAllCoroutines();
// 清理未使用的资源
Resources.UnloadUnusedAssets();
}
}