using Spine.Unity;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public enum TurretAnimType
{
None = 0,
skeletonAnimation = 1,
animation = 2,
animator = 3
}
public enum TurretState
{
None = 0,
Idle = 1,
Attack = 2,
LaserStart = 3,
LaserLoop = 4,
LaserEnd = 5
}
public class TurretData : MonoBehaviour
{
[Header("基础")]
public string turretID;
public SitPosData setPosData;
public Transform tra_BulletStartPosition;
[Tooltip("炮台旋转节点。拖入后 SitPosData.tra_CurrTurret 用此节点旋转;不拖则用炮台自身的父节点(兼容旧逻辑)")]
public Transform tra_RotationPivot;
public GameObject bulletPrefab_Two;
public GameObject bulletPrefab;
[Header("战神激光(锁定时显示,普通炮台不配置即无此效果)")]
[Tooltip("激光预制体。非空=预制体形态(JiGuangControl 工具类驱动);为空=LineRenderer 兜底形态(自动创建)")]
public GameObject laserPrefab;
[Tooltip("LineRenderer 兜底形态的线宽")]
public float laserWidth = 0.3f;
[Tooltip("LineRenderer 兜底形态的颜色")]
public Color laserColor = new Color(1f, 0.3f, 0.3f, 0.9f);
[Tooltip("预制体形态激光的长度校正值(不同激光预制体设置不同值)")]
public float laserLengthCorrect = 1f;
[Header("UI面板属性")]
[Tooltip("炮台编号,对应 TurretResourcesData.turretNumber")]
public int turretNumber;
[Tooltip("1=普通炮台 2=战神 3=翅膀")]
public int turretType = 1;
[Tooltip("UI 展示名称")]
public string displayName;
[Tooltip("品质 1=普通 2=稀有 3=史诗 4=传说")]
[Range(1, 5)]
public int quality = 1;
[Tooltip("解锁所需等级(0=默认拥有)")]
public int unlockLevel;
[Tooltip("UI 列表/详情用的缩略图")]
public Sprite uiIconSprite;
[TextArea(2, 4)]
[Tooltip("描述文字")]
public string description;
// ---- 运行时状态(由服务器/UI面板读写) ----
[System.NonSerialized] public bool isUnlocked;
[System.NonSerialized] public bool isEquipped;
[System.NonSerialized] public int ownStarLevel;
[Header("动画组件")]
public SkeletonGraphic skeletonAnimation;
public Animation old_CurrAnimation;
public Animator new_CurrAnimation;
public TurretAnimType currTurretType;
public bool isFrenzy=false;
[Header("动画名")]
public string idleAnim;
public string attackAnim;
// 新增:狂暴专用攻击动画(已经是二倍速帧动画)
public string frenzyAttackAnim;
private bool useFrenzyAnim = false;
public string laserStartAnim;
public string laserLoopAnim;
public string laserEndAnim;
[Header("战神 Animator 参数")]
[Tooltip("战神状态机开火参数名(Bool:Idle0 --PlayFire--> Fire状态机,Fire --PlayFire=false--> Exit回Idle)。" +
"检测到此参数自动启用战神模式,无需手动配置")]
public string playFireParam = "PlayFire";
[Tooltip("开火动画变体参数名(Int):0=Fire0(正常子弹) 1=Fire1(激光)。锁定时自动切1,非锁定开火用0")]
public string fireIndexParam = "FireIndex";
[Tooltip("待机动画变体参数名(Int:IdleIndex=0选Idle0...)")]
public string idleIndexParam = "IdleIndex";
[Tooltip("开火动画变体索引默认值:0=Fire0(正常子弹) 1=Fire1(激光)。运行时按锁定状态自动切换,此值仅为无锁定信息时的兜底")]
public int fireIndex = 0;
[Tooltip("待机动画变体索引:0=Idle0 1=Idle1...")]
public int idleIndex = 0;
[Header("XJMH加减炮倍")]
public GameObject obj_Add;
public GameObject obj_Down;
// ---- 战神模式运行时缓存(首次 PlayAnimator 时检测)----
private bool _warGodAnimChecked; // 是否已检测过参数
private bool _warGodAnimMode; // true=战神 PlayFire 约定
private bool _playFireIsTrigger; // PlayFire 实际类型是否 Trigger(个别控制器用触发器)
private bool _hasFireIndex;
private bool _hasIdleIndex;
private AnimatorControllerParameterType _fireIndexType = AnimatorControllerParameterType.Int;
private AnimatorControllerParameterType _idleIndexType = AnimatorControllerParameterType.Int;
private TurretState currState;
/// 出现动画保护截止时间:这段时间内 Idle(动画名为空)不 ClearTrack,避免出现动画刚播就被抹掉
private float _appearAnimHoldUntil;
///
/// 从资源表查询 TurretResourcesData。表里没有则返回 null,调用方应使用 TurretData 自身的 Inspector 默认值。
///
public TurretResourcesData GetResourcesData()
{
return TurretResourcesData.GetTurretData(turretNumber);
}
/// 安全获取攻击音效 ID:表里有就用,没有则返回 0(静音)。
public int GetAttackAudioID()
{
var res = GetResourcesData();
return res != null ? res.attackAudioID : 0;
}
/// 安全获取子弹 ID 列表:表里有就用,没有则返回空列表。
public List GetBulletIDs()
{
var res = GetResourcesData();
return res?.bulletID ?? new List();
}
/// 安全获取动画类型:表里有就用,没有则用 Inspector 配置的 currTurretType。
public TurretAnimType GetAnimationType()
{
var res = GetResourcesData();
return res != null ? (TurretAnimType)res.animationType : currTurretType;
}
private void Awake()
{
//if (setPosData != null)
// setPosData.OnStateChange = ChangeState;
// 自动判断:如果狂暴攻击动画名不为空,就启用切换动画模式
useFrenzyAnim = !string.IsNullOrEmpty(frenzyAttackAnim);
}
private void OnEnable()
{
// ⭐ 状态缓存必须跟着 OnEnable 实际播的动画走:这里直接播 Idle(不走 ChangeState),
// 所以必须手动把 currState 一起重置。否则反复激活(切炮台/座位隐藏恢复/对象池复用)后
// currState 会停在 Attack,之后真正的 ChangeState(Attack) 被"同状态早退"吃掉 →
// 炮台停在错误状态(表现为该攻击时不出手 / 不该攻击时一直在攻击状态)。
currState = TurretState.Idle;
PlayState(TurretState.Idle);
BindAddDownButtons(); // ⭐ XJMH 加减炮倍:炮台上的 +/- 绑定点击(每次激活重绑,幂等)
}
///
/// 当前动画状态(只读)。调用方(GameMainPanel)用它在"这一帧没开火"时判断要不要补发 Idle,
/// 避免每帧重复广播状态。注意:状态由 OnStateChange 指向的那个 TurretData 接收
/// (战神装备中指向战神,见 SitPosData.LoadZhanShen)。
///
public TurretState CurrState => currState;
// ==================== XJMH 加减炮倍按钮绑定 ====================
// 炮台上的 obj_Add / obj_Down(物体名 Up / Down)在预制体里没有 Button 组件、也没有任何代码绑定
// → 点击无反应。这里在炮台激活时统一补 Button + 绑定:
// + → 座位 ChangeTurretAddConsumeNum(发 ChangeGunMultiple,等服务端确认后应用新炮倍)
// - → 座位 ChangeTurretMinusConsumeNum
// 未拖引用跳过(可要可不要);非本地座位由 SitPosData.HideTurretAddMinusUI 隐藏。
private SitPosData ResolveSit()
{
return setPosData != null ? setPosData : GetComponentInParent();
}
private void OnClickTurretAdd() { ResolveSit()?.ChangeTurretAddConsumeNum(); }
private void OnClickTurretMinus() { ResolveSit()?.ChangeTurretMinusConsumeNum(); }
private void BindAddDownButtons()
{
BindAddDownButton(obj_Add, OnClickTurretAdd);
BindAddDownButton(obj_Down, OnClickTurretMinus);
}
private static void BindAddDownButton(GameObject go, UnityEngine.Events.UnityAction action)
{
if (go == null) return; // 未拖引用:跳过,不报错
var btn = go.GetComponent