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 {/// /// 玩家 /// Player, /// /// 怪物 /// Enemy, /// /// 中立 /// 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, } /// /// 角色基类,玩家处理事件 /// [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().direction = HurtDirectin; if (isGoodDamege) { go.GetComponent().CreateText(true); isGoodDamege = false; } else { go.GetComponent().CreateText(); } if (temp - hp>0) { if (isMoFa) { go.GetComponent().text = "" + (temp - hp).ToString("F0") + ""; // 显示伤害值 isMoFa = false; } else { go.GetComponent().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 value; // 字典的值 [Header("角色动画帧数间隔(毫秒)")] public int CharacterAnimationFrameInterval = 50; } [Header("角色动画")] public List AnimationTree = new List(); [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 buffList = new List(); public CharacterFlags myTags = 0; public bool hasfalg(CharacterFlags flag) { return (myTags & flag) == flag; } public SkillUp mySkillUp; /// /// 储存buff /// public List> storageBuff = new List>(); /// /// 使用buff /// public List> PlayerBuff=new List>(); public bool IsDead = false; public int HaveDieTime = 0; public virtual async void Start() { if (mySkillUp == null) { mySkillUp = this.transform.GetComponent(); } 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(); } /// /// 添加Buff /// /// public void AddBuff(List> buffs, Action buffAction) { buffs.Add(buffAction); UnityEngine.Debug.LogError(this.name + "添加buff到"+ buffs); } public void RemoveBuff(List> buffs, Action buffAction) { buffs.Remove(buffAction); UnityEngine.Debug.LogError(this.name + "移除" + buffs); } /// /// 执行所有当前 Buff /// public void ApplyBuffs() { foreach (var buff in PlayerBuff) { UnityEngine.Debug.LogError(this.name + "进入执行buff判断"); buff.Invoke(this); // 将自己作为目标传递 } // 清空 Buff 列表,假设 Buff 是一次性的 PlayerBuff.Clear(); } /// /// 角色动画更新 /// 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 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; } } } /// /// 角色死亡 /// public virtual void die() { if (Application.isPlaying) { GetComponent().HideInfoPanel(); animationHighlight = dieIndex; Navigation.PauseAnimation(); if (!IsDead) { UIContorl.instance.Killnumber++; SkillBox.instance.AddExperience(gold, this.gameObject.transform); IsDead = true; } HaveDieTime++; } } /// /// 角色受到攻击 /// public virtual void hit() { if (Application.isPlaying) { animationHighlight = hitIndex; } } /// /// 角色减速 /// public void SlowDown(float num) { Navigation.speedFactor *= num; } /// /// 单位更新buff /// async void UpdateBuff()//单位buff更新 { while (true) { List deleteArr = new List(); 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秒执行一次 } } /// /// 重置角色所有状态 /// 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("攻击力赋值++++++++++++++++++++++++++++++"); } } } } /// /// 计算伤害 /// /// 造成者 /// 目标 /// /// 萌妖每次攻击对敌人造成伤害=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().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().isSlowed) // 如果敌人减速 { hurt *= (1 + mySkillUp.DamageOfSlow); UnityEngine.Debug.Log("减速敌人加成"); } hurt *= (1 + WuxingDamage(Target.gameObject.GetComponent()));//计算五行属性伤害 hurt *= HujiaDamage(Target.gameObject.GetComponent());//计算破甲伤害 if (hurt * (1 - TargetDefense / 100) < 1) { hurt = 1; } else { hurt *= (1 - TargetDefense / 100); } if (GetComponent()) { GetComponent().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().elementType,(int)Target.elementType]; // 如果是正数,表示加成,增加伤害 // 如果是负数,表示减成,减少伤害 // UnityEngine.Debug.Log("属性关系:"+"萌妖"+ GetComponent().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() != null) { var material = transform.GetComponent().material; if (material != null) Destroy(material); var texture = material.mainTexture; if (texture != null) Destroy(texture); } // 停止协程 StopAllCoroutines(); // 清理未使用的资源 Resources.UnloadUnusedAssets(); } }