using System;
|
using System.Collections;
|
using System.Collections.Generic;
|
using UnityEngine;
|
using DG.Tweening;
|
using DG.Tweening.Core;
|
using DG.Tweening.Plugins.Options;
|
using Spine.Unity;
|
using UnityEngine.UI;
|
using System.Linq;
|
|
public enum BattleCamp
|
{
|
Red,
|
Blue
|
}
|
|
public enum BattleState
|
{
|
None = 0,
|
Stunned = 1 << 0,
|
Poisoned = 1 << 1,
|
Bleeding = 1 << 2,
|
Silenced = 1 << 3,
|
Frozen = 1 << 4,
|
Burned = 1 << 5
|
}
|
|
public abstract class BattleObject
|
{
|
public BattleField battleField;
|
|
public BattleObjectLayerMgr layerMgr;
|
|
public int ObjID { get; set; }
|
|
public BattleCamp Camp { get; protected set; }
|
|
public BattleObject(BattleField _battleField)
|
{
|
battleField = _battleField;
|
}
|
|
// ============ 抽象访问方法(子类返回各自的Team类型信息) ============
|
|
public abstract int GetPositionNum();
|
public abstract float GetModelScale();
|
public abstract string GetName();
|
|
// Buff 管理器访问方法(Hero 有 buff,Mingge 返回 null)
|
public abstract BattleObjectBuffMgr GetBuffMgr();
|
|
// 状态查询抽象方法
|
protected abstract bool GetIsStunned();
|
protected abstract bool GetIsFrozen();
|
protected abstract bool GetIsStoned();
|
protected abstract bool GetIsSlient();
|
protected abstract bool GetIsDisarmed();
|
protected abstract bool GetIsInvincible();
|
protected abstract bool GetIsDead();
|
public abstract int GetRage();
|
|
// 血量相关抽象方法(Hero 特有,Mingge 返回默认值)
|
public abstract long GetCurHp();
|
public abstract long GetMaxHp();
|
public abstract void SetCurHp(long value);
|
public abstract void SetIsDead(bool value);
|
|
// 其他属性访问方法
|
public abstract int GetNPCID();
|
public abstract long GetFightPower();
|
|
public abstract void Run();
|
|
public abstract void Pause();
|
|
public abstract void Resume();
|
|
public abstract void Destroy();
|
|
// ============ 动画相关抽象方法(替代 motionBase 直接调用) ============
|
|
/// <summary>
|
/// 播放动画
|
/// </summary>
|
public abstract void PlayAnimation(MotionName motionName, bool loop);
|
|
/// <summary>
|
/// 显示幻影残影
|
/// </summary>
|
public abstract void ShowIllusionShadow(bool show, Color? color = null);
|
|
/// <summary>
|
/// 播放技能动画
|
/// </summary>
|
public abstract Spine.TrackEntry PlaySkillAnimation(SkillConfig skillConfig, SkillSkinConfig skillSkinConfig, SkillBase skillBase, bool isCounter, Action onComplete);
|
|
/// <summary>
|
/// 检查是否可以开始死亡
|
/// </summary>
|
public abstract bool CanStartDeath();
|
|
/// <summary>
|
/// 检查是否可以释放技能
|
/// </summary>
|
public abstract bool CanCastSkillAnimation(SkillSkinConfig skillSkinConfig);
|
|
/// <summary>
|
/// 获取骨骼动画组件(用于特效挂载等)
|
/// </summary>
|
public abstract SkeletonAnimation GetSkeletonAnimation();
|
|
/// <summary>
|
/// 设置骨骼动画透明度
|
/// </summary>
|
public abstract void SetSkeletonAlpha(float alpha);
|
|
/// <summary>
|
/// 获取 RectTransform(用于移动等操作)
|
/// </summary>
|
public virtual RectTransform GetRectTransform() => null;
|
|
/// <summary>
|
/// 获取 GameObject
|
/// </summary>
|
public virtual GameObject GetGameObject() => null;
|
|
/// <summary>
|
/// 获取 Transform(用于特效挂载等)
|
/// </summary>
|
public virtual Transform GetTransform() => null;
|
|
/// <summary>
|
/// 获取世界坐标位置
|
/// </summary>
|
public virtual Vector3 GetPosition() => Vector3.zero;
|
|
/// <summary>
|
/// 获取血条信息栏
|
/// </summary>
|
public virtual BattleHeroInfoBar GetHeroInfoBar() => null;
|
|
/// <summary>
|
/// 刷新Buff显示
|
/// </summary>
|
public virtual void RefreshBuff(List<HB428_tagSCBuffRefresh> buffList) { }
|
|
/// <summary>
|
/// 更新血量显示
|
/// </summary>
|
public virtual void UpdateHP(float percentage) { }
|
|
/// <summary>
|
/// 是否正在复活中
|
/// </summary>
|
public virtual bool IsReborning() => false;
|
|
/// <summary>
|
/// 设置复活状态
|
/// </summary>
|
public virtual void SetReborning(bool value) { }
|
|
/// <summary>
|
/// 设置 GameObject 激活状态
|
/// </summary>
|
public virtual void SetActive(bool active) { }
|
|
/// <summary>
|
/// 重置位置到原点
|
/// </summary>
|
public virtual void ResetPosition() { }
|
|
/// <summary>
|
/// 设置朝向(通过缩放)
|
/// </summary>
|
public virtual void SetFacing(float direction) { }
|
|
/// <summary>
|
/// 重置朝向(朝向右边)
|
/// </summary>
|
public virtual void ResetFacing() { }
|
|
/// <summary>
|
/// 停止所有移动动画
|
/// </summary>
|
public virtual void StopMoveAnimation() { }
|
|
/// <summary>
|
/// 显示提示信息(简单版本)
|
/// </summary>
|
public virtual void ShowTips(string message, bool useArtText = false, bool followCharacter = true, float scaleRatio = 1f) { }
|
|
/// <summary>
|
/// 显示提示信息(完整版本)
|
/// </summary>
|
public virtual void ShowTips(BattleHeroInfoBar.TipsInfo tipsInfo) { }
|
|
/// <summary>
|
/// 设置死亡状态(Hero 特定)
|
/// </summary>
|
public virtual void SetDeath() { }
|
|
/// <summary>
|
/// 复活后处理(Hero 特定)
|
/// </summary>
|
public virtual void AfterReborn() { }
|
|
/// <summary>
|
/// 复活前准备(Hero 特定)
|
/// </summary>
|
public virtual void PreReborn(bool reviveSelf = false) { }
|
|
/// <summary>
|
/// 复活动作(Hero 特定)
|
/// </summary>
|
public virtual void OnReborn(HB427_tagSCUseSkill.tagSCUseSkillHurt vNetData, bool reviveSelf = false, RecordAction parentAction = null) { }
|
|
public virtual void OnObjInfoRefresh(H0418_tagObjInfoRefresh _refreshInfo)
|
{
|
// 子类实现
|
}
|
|
// 眩晕
|
public bool IsStunned()
|
{
|
return GetIsStunned();
|
}
|
|
// 冰冻
|
public bool IsFrozen()
|
{
|
return GetIsFrozen();
|
}
|
|
// 石化
|
public bool IsStoned()
|
{
|
return GetIsStoned();
|
}
|
|
// 被沉默
|
public bool IsSlient()
|
{
|
return GetIsSlient();
|
}
|
|
// 被缴械
|
public bool IsDisarmed()
|
{
|
return GetIsDisarmed();
|
}
|
|
// 是否无敌
|
public bool IsInvincable()
|
{
|
return GetIsInvincible();
|
}
|
|
// 是否死亡
|
public bool IsDead()
|
{
|
return GetIsDead();
|
}
|
|
// 是否被控住了
|
public bool IsCrowdControlled()
|
{
|
return IsStunned() || IsStoned() || IsFrozen();
|
}
|
|
public virtual bool IsCanCastSkill()
|
{
|
// 被控住
|
if (IsCrowdControlled())
|
{
|
return false;
|
}
|
|
// 被沉默
|
if (IsSlient())
|
{
|
return false;
|
}
|
|
// 看看怒气是否达到释放要求
|
return GetRage() >= 100;
|
}
|
|
public virtual bool IsCanNormalAttack()
|
{
|
// 被控住
|
if (IsCrowdControlled())
|
{
|
return false;
|
}
|
|
// 缴械
|
if (IsDisarmed())
|
{
|
return false;
|
}
|
|
return true;
|
}
|
|
public abstract DeathRecordAction Hurt(BattleHurtParam battleHurtParam, SkillRecordAction _parentSkillAction = null);
|
|
public abstract void OnDodgeBegin(DamageType damageType);
|
|
public abstract void OnDodgeEnd(Action _complete = null);
|
|
public abstract void OnDeath(Action _onDeathAnimationComplete, bool withoutAnime = false);
|
|
protected abstract BattleDmgInfo PopDamage(BattleHurtParam battleHurtParam);
|
|
protected abstract BattleDmgInfo PopDamageForCaster(BattleHurtParam battleHurtParam);
|
|
public RectTransform GetAliasTeamNode()
|
{
|
return battleField.GetTeamNode(Camp);
|
}
|
|
public RectTransform GetEnemyTeamNode()
|
{
|
return battleField.GetTeamNode(Camp == BattleCamp.Red ? BattleCamp.Blue : BattleCamp.Red);
|
}
|
|
public BattleCamp GetEnemyCamp()
|
{
|
return Camp == BattleCamp.Red ? BattleCamp.Blue : BattleCamp.Red;
|
}
|
|
public abstract void HaveRest();
|
|
protected BattleDrops m_battleDrops;
|
|
public virtual void PushDropItems(BattleDrops _battleDrops)
|
{
|
m_battleDrops = _battleDrops;
|
}
|
|
public virtual void PerformDrop()
|
{
|
if (null == m_battleDrops)
|
return;
|
|
EventBroadcast.Instance.Broadcast<string, BattleDrops, Action>(
|
EventName.BATTLE_DROP_ITEMS, battleField.guid, m_battleDrops, OnPerformDropFinish);
|
}
|
|
protected virtual void OnPerformDropFinish()
|
{
|
m_battleDrops = null;
|
}
|
|
public void SetBack()
|
{
|
layerMgr.SetBack();
|
}
|
|
public void SetFront()
|
{
|
layerMgr.SetFront();
|
}
|
|
public abstract void SetSpeedRatio(float ratio);
|
|
public abstract void OnObjPropertyRefreshView(HB418_tagSCObjPropertyRefreshView vNetData);
|
|
|
#if UNITY_EDITOR_STOP_USING
|
public abstract void EditorRevive();
|
|
public List<int> TryAttack(BattleObject obj, SkillConfig skillConfig)
|
{
|
List<int> damageList = new List<int>();
|
|
int totalDamage = 100;
|
|
int damage1 = (int)((float)totalDamage * 0.3f);
|
|
int damage2 = (int)((float)totalDamage * 0.25f);
|
|
int damage3 = totalDamage - damage1 - damage2;
|
|
damageList.Add(damage1);
|
damageList.Add(damage2);
|
damageList.Add(damage3);
|
|
return damageList;
|
}
|
#endif
|
|
// BattleObject.cs
|
|
public virtual void OnHurtTarget(BattleHurtParam battleHurtParam)
|
{
|
// 检查是否有吸血或反伤
|
bool hasSuckHp = battleHurtParam.caster.suckHpList != null && battleHurtParam.caster.suckHpList.Count > 0;
|
bool hasReflectHp = battleHurtParam.caster.reflectHpList != null && battleHurtParam.caster.reflectHpList.Count > 0;
|
|
if (!hasSuckHp && !hasReflectHp)
|
{
|
return;
|
}
|
|
// ============ 应用施法者的血量和护盾变化 ============
|
bool isLastHit = battleHurtParam.hitIndex >= battleHurtParam.skillSkinConfig.DamageDivide.Length - 1;
|
ApplyHurtToCaster(battleHurtParam, isLastHit);
|
|
// 和Hurt一样,调用PopDamage处理吸血/反伤的显示
|
BattleDmgInfo casterDmgInfo = PopDamageForCaster(battleHurtParam);
|
|
// 如果有反伤,施法者播放受击动画
|
if (hasReflectHp && casterDmgInfo.casterDamageList != null && casterDmgInfo.casterDamageList.Count > 0)
|
{
|
long totalReflect = casterDmgInfo.casterDamageList.Sum(d => d.damage);
|
var buffMgr = GetBuffMgr();
|
if (totalReflect > 0 && buffMgr != null && !buffMgr.isControled[BattleConst.HardControlGroup])
|
{
|
OnPlayHitAnimation();
|
}
|
}
|
}
|
|
/// <summary>
|
/// 应用施法者的血量和护盾变化(吸血和反伤)
|
/// </summary>
|
private void ApplyHurtToCaster(BattleHurtParam battleHurtParam, bool isLastHit)
|
{
|
BattleCastObj caster = battleHurtParam.caster;
|
|
// 应用血量变化(由子类实现)
|
ApplyCasterHpChange(caster.toHp);
|
|
// 打印所有角色的名字和当前血量跟总血量
|
// foreach (var obj in battleField.battleObjMgr.allBattleObjDict.Values)
|
// {
|
// Debug.LogError($"[ApplyHurtToCaster] ObjID: {obj.ObjID}, Name: {obj.teamHero.heroConfig.Name}, CurHp: {obj.teamHero.curHp}, MaxHp: {obj.teamHero.maxHp} Skill {battleHurtParam.hB427_TagSCUseSkill.packUID} " );
|
// }
|
|
// 护盾值由buff系统自动管理,不需要手动设置
|
|
#if UNITY_EDITOR
|
// 最后一击时验证血量是否与服务器一致
|
if (isLastHit)
|
{
|
BattleUtility.ValidateHpConsistencyForCaster(battleHurtParam, "施法者吸血/反伤");
|
}
|
#endif
|
}
|
|
public bool IsTianziBoss()
|
{
|
return battleField.MapID == 30020 && battleField.FindBoss() == this;
|
}
|
|
/// <summary>
|
/// 播放受击动画(只有 Hero 有实现,Mingge 留空)
|
/// </summary>
|
protected abstract void OnPlayHitAnimation();
|
|
/// <summary>
|
/// 应用施法者血量变化(吸血/反伤)
|
/// </summary>
|
protected abstract void ApplyCasterHpChange(long newHp);
|
}
|