611 lines
23 KiB
C#
611 lines
23 KiB
C#
using Spine.Unity;
|
||
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;
|
||
|
||
/// <summary>出现动画保护截止时间:这段时间内 Idle(动画名为空)不 ClearTrack,避免出现动画刚播就被抹掉</summary>
|
||
private float _appearAnimHoldUntil;
|
||
|
||
/// <summary>
|
||
/// 从资源表查询 TurretResourcesData。表里没有则返回 null,调用方应使用 TurretData 自身的 Inspector 默认值。
|
||
/// </summary>
|
||
public TurretResourcesData GetResourcesData()
|
||
{
|
||
return TurretResourcesData.GetTurretData(turretNumber);
|
||
}
|
||
|
||
/// <summary>安全获取攻击音效 ID:表里有就用,没有则返回 0(静音)。</summary>
|
||
public int GetAttackAudioID()
|
||
{
|
||
var res = GetResourcesData();
|
||
return res != null ? res.attackAudioID : 0;
|
||
}
|
||
|
||
/// <summary>安全获取子弹 ID 列表:表里有就用,没有则返回空列表。</summary>
|
||
public List<int> GetBulletIDs()
|
||
{
|
||
var res = GetResourcesData();
|
||
return res?.bulletID ?? new List<int>();
|
||
}
|
||
|
||
/// <summary>安全获取动画类型:表里有就用,没有则用 Inspector 配置的 currTurretType。</summary>
|
||
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()
|
||
{
|
||
PlayState(TurretState.Idle);
|
||
BindAddDownButtons(); // ⭐ XJMH 加减炮倍:炮台上的 +/- 绑定点击(每次激活重绑,幂等)
|
||
}
|
||
|
||
// ==================== XJMH 加减炮倍按钮绑定 ====================
|
||
// 炮台上的 obj_Add / obj_Down(物体名 Up / Down)在预制体里没有 Button 组件、也没有任何代码绑定
|
||
// → 点击无反应。这里在炮台激活时统一补 Button + 绑定:
|
||
// + → 座位 ChangeTurretAddConsumeNum(发 ChangeGunMultiple,等服务端确认后应用新炮倍)
|
||
// - → 座位 ChangeTurretMinusConsumeNum
|
||
// 未拖引用跳过(可要可不要);非本地座位由 SitPosData.HideTurretAddMinusUI 隐藏。
|
||
private SitPosData ResolveSit()
|
||
{
|
||
return setPosData != null ? setPosData : GetComponentInParent<SitPosData>();
|
||
}
|
||
|
||
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<Button>();
|
||
if (btn == null) btn = go.GetComponentInChildren<Button>(true);
|
||
if (btn == null) btn = go.AddComponent<Button>(); // 没有 Button 就程序补一个(物体自带的 Image 提供射线检测)
|
||
btn.onClick.RemoveAllListeners(); // 重绑前清掉,避免重复触发
|
||
btn.onClick.AddListener(action);
|
||
}
|
||
//public Vector2 GetBulletStartWorldPos()
|
||
//{
|
||
// if (tra_BulletStartPosition == null)
|
||
// return Vector2.zero;
|
||
|
||
// // 如果是 UI RectTransform(UGUI)
|
||
// RectTransform rect = tra_BulletStartPosition.GetComponent<RectTransform>();
|
||
// if (rect != null)
|
||
// {
|
||
// // 1. UI 本地坐标 → Canvas 坐标
|
||
// Vector2 canvasPos = CoordinateTransformation.AnchoredPos_ToCanvas(
|
||
// rect,
|
||
// UIManager.Instance.uiRoot.GetComponent<Canvas>()
|
||
// );
|
||
|
||
// // 2. Canvas 坐标 → 世界坐标
|
||
// return CoordinateTransformation.CanvasToWorld(
|
||
// canvasPos,
|
||
// UIManager.Instance.uiRoot.GetComponent<RectTransform>(),
|
||
// Camera.main
|
||
// );
|
||
// }
|
||
|
||
// // 如果不是 UI(比如 3D Transform)
|
||
// return tra_BulletStartPosition.position;
|
||
//}
|
||
public Vector2 GetBulletStartWorldPos()
|
||
{
|
||
if (tra_BulletStartPosition == null)
|
||
return Vector2.zero;
|
||
|
||
// 如果是 UI(UGUI)
|
||
RectTransform rect = tra_BulletStartPosition.GetComponent<RectTransform>();
|
||
if (rect != null)
|
||
{
|
||
Canvas canvas = UIManager.Instance.uiRoot.GetComponent<Canvas>();
|
||
Camera cam = Camera.main;
|
||
|
||
// 方式1:通过屏幕坐标直接转世界坐标(推荐)
|
||
Vector3 screenPos = RectTransformUtility.WorldToScreenPoint(
|
||
canvas.renderMode == RenderMode.ScreenSpaceOverlay ? null : canvas.worldCamera,
|
||
rect.position
|
||
);
|
||
// 需要计算 Z 轴距离(物体到相机的距离),这里假设子弹打在 Z=0 平面
|
||
float distance = Mathf.Abs(cam.transform.position.z - 0f);
|
||
Vector3 worldPos = cam.ScreenToWorldPoint(new Vector3(screenPos.x, screenPos.y, distance));
|
||
worldPos.z = 0f;
|
||
return worldPos;
|
||
}
|
||
|
||
// 非 UI(3D 物体)
|
||
return tra_BulletStartPosition.position;
|
||
}
|
||
public void SetFrenzy(bool value)
|
||
{
|
||
isFrenzy = value;
|
||
|
||
if (!useFrenzyAnim) // 没有狂暴动画 → 用速度加倍
|
||
{
|
||
float speed = isFrenzy ? 2f : 1f;
|
||
|
||
if (skeletonAnimation != null)
|
||
skeletonAnimation.timeScale = speed;
|
||
|
||
if (new_CurrAnimation != null)
|
||
new_CurrAnimation.speed = speed;
|
||
|
||
if (old_CurrAnimation != null)
|
||
{
|
||
foreach (AnimationState state in old_CurrAnimation)
|
||
state.speed = speed;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// 有狂暴动画 → 不做速度调整,保持 1 倍速
|
||
if (skeletonAnimation != null)
|
||
skeletonAnimation.timeScale = 1f;
|
||
|
||
if (new_CurrAnimation != null)
|
||
new_CurrAnimation.speed = 1f;
|
||
|
||
if (old_CurrAnimation != null)
|
||
{
|
||
foreach (AnimationState state in old_CurrAnimation)
|
||
state.speed = 1f;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
public virtual void ChangeState(TurretState newState)
|
||
{
|
||
if (currState == newState) return;
|
||
|
||
currState = newState;
|
||
PlayState(newState);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 播放"出现动画":各 SkeletonGraphic 上配置的 Spine startingAnimation(炮台容器/炮体上配的是 out、trans 等)。
|
||
/// ⭐ Spine 只在 Awake(第一次激活)应用一次 startingAnimation,而 OnEnable 的 PlayState(Idle)
|
||
/// 在动画名为空时会 ClearTrack 把它抹掉,所以切换炮台时补播一次,
|
||
/// 并在播放期间保护它不被 Idle 清掉(见 PlaySkeleton 的空动画名分支)。
|
||
/// </summary>
|
||
public void PlayAppearAnim()
|
||
{
|
||
float hold = 0f;
|
||
foreach (var g in GetComponentsInChildren<SkeletonGraphic>(true))
|
||
{
|
||
if (g == null || string.IsNullOrEmpty(g.startingAnimation) || g.AnimationState == null) continue;
|
||
|
||
var track = g.AnimationState.SetAnimation(0, g.startingAnimation, g.startingLoop);
|
||
if (!g.startingLoop && track != null)
|
||
hold = Mathf.Max(hold, track.Animation.Duration);
|
||
}
|
||
_appearAnimHoldUntil = Time.time + hold;
|
||
}
|
||
|
||
private void PlayState(TurretState state)
|
||
{
|
||
switch (currTurretType)
|
||
{
|
||
case TurretAnimType.skeletonAnimation:
|
||
PlaySkeleton(state);
|
||
break;
|
||
|
||
case TurretAnimType.animation:
|
||
PlayLegacy(state);
|
||
break;
|
||
|
||
case TurretAnimType.animator:
|
||
PlayAnimator(state);
|
||
break;
|
||
}
|
||
}
|
||
|
||
//private void PlaySkeleton(TurretState state)
|
||
//{
|
||
// if (skeletonAnimation == null) return;
|
||
|
||
// string anim = state switch
|
||
// {
|
||
// TurretState.Idle => idleAnim,
|
||
// TurretState.Attack => (isFrenzy && useFrenzyAnim) ? frenzyAttackAnim : attackAnim,
|
||
// TurretState.LaserStart => laserStartAnim,
|
||
// TurretState.LaserLoop => laserLoopAnim,
|
||
// TurretState.LaserEnd => laserEndAnim,
|
||
// _ => idleAnim
|
||
// };
|
||
|
||
// bool loop = state == TurretState.Attack || state == TurretState.LaserLoop;
|
||
// skeletonAnimation.AnimationState.SetAnimation(0, anim, loop);
|
||
|
||
// if (state == TurretState.LaserStart)
|
||
// {
|
||
// skeletonAnimation.AnimationState.AddAnimation(0, laserLoopAnim, true, 0f);
|
||
// }
|
||
//}
|
||
|
||
|
||
|
||
//private void PlayLegacy(TurretState state)
|
||
//{
|
||
// if (old_CurrAnimation == null) return;
|
||
|
||
// string anim = state switch
|
||
// {
|
||
// TurretState.Idle => idleAnim,
|
||
// TurretState.Attack => (isFrenzy && useFrenzyAnim) ? frenzyAttackAnim : attackAnim,
|
||
// TurretState.LaserStart => laserStartAnim,
|
||
// TurretState.LaserLoop => laserLoopAnim,
|
||
// TurretState.LaserEnd => laserEndAnim,
|
||
// _ => idleAnim
|
||
// };
|
||
|
||
// old_CurrAnimation.Play(anim);
|
||
//}
|
||
|
||
|
||
//private void PlayAnimator(TurretState state)
|
||
//{
|
||
// if (new_CurrAnimation == null) return;
|
||
|
||
// if (state == TurretState.Attack && isFrenzy && useFrenzyAnim)
|
||
// {
|
||
// new_CurrAnimation.SetTrigger("FrenzyAttack");
|
||
// }
|
||
// else
|
||
// {
|
||
// new_CurrAnimation.SetInteger("State", (int)state);
|
||
// }
|
||
//}
|
||
private void PlaySkeleton(TurretState state)
|
||
{
|
||
if (skeletonAnimation == null) return;
|
||
|
||
string anim = state switch
|
||
{
|
||
TurretState.Idle => idleAnim,
|
||
TurretState.Attack => (isFrenzy && useFrenzyAnim) ? frenzyAttackAnim : attackAnim,
|
||
TurretState.LaserStart => laserStartAnim,
|
||
TurretState.LaserLoop => laserLoopAnim,
|
||
TurretState.LaserEnd => laserEndAnim,
|
||
_ => idleAnim
|
||
};
|
||
|
||
// 如果动画名为空 → 停止当前动画(暂停),不再播放任何动画
|
||
if (string.IsNullOrEmpty(anim))
|
||
{
|
||
// ⭐ 出现动画播放期间不覆盖:ClearTrack 会把刚播的出现动画抹掉。
|
||
// 典型场景:切炮台后松手,HandleInput 会发一次 ChangeState(Idle),
|
||
// 而 idleAnim 为空正好走这个分支,出现动画一帧就被清掉。
|
||
if (Time.time < _appearAnimHoldUntil) return;
|
||
|
||
skeletonAnimation.AnimationState.ClearTrack(0);
|
||
skeletonAnimation.AnimationState.SetEmptyAnimation(0, 0f);
|
||
return;
|
||
}
|
||
|
||
bool loop = state == TurretState.Attack || state == TurretState.LaserLoop;
|
||
skeletonAnimation.AnimationState.SetAnimation(0, anim, loop);
|
||
|
||
if (state == TurretState.LaserStart && !string.IsNullOrEmpty(laserLoopAnim))
|
||
{
|
||
skeletonAnimation.AnimationState.AddAnimation(0, laserLoopAnim, true, 0f);
|
||
}
|
||
}
|
||
|
||
private void PlayLegacy(TurretState state)
|
||
{
|
||
if (old_CurrAnimation == null) return;
|
||
|
||
string anim = state switch
|
||
{
|
||
TurretState.Idle => idleAnim,
|
||
TurretState.Attack => (isFrenzy && useFrenzyAnim) ? frenzyAttackAnim : attackAnim,
|
||
TurretState.LaserStart => laserStartAnim,
|
||
TurretState.LaserLoop => laserLoopAnim,
|
||
TurretState.LaserEnd => laserEndAnim,
|
||
_ => idleAnim
|
||
};
|
||
|
||
if (string.IsNullOrEmpty(anim))
|
||
{
|
||
old_CurrAnimation.Stop();
|
||
return;
|
||
}
|
||
|
||
old_CurrAnimation.Play(anim);
|
||
}
|
||
|
||
private void PlayAnimator(TurretState state)
|
||
{
|
||
if (new_CurrAnimation == null) return;
|
||
|
||
// 战神约定(PlayFire/FireIndex/IdleIndex):控制器带 PlayFire 参数时自动启用
|
||
if (!_warGodAnimChecked) DetectWarGodAnimator();
|
||
if (_warGodAnimMode)
|
||
{
|
||
PlayWarGodAnimator(state);
|
||
return;
|
||
}
|
||
|
||
// ---- 旧约定(State 整数 / FrenzyAttack 触发器),保持不变 ----
|
||
// 如果缺少对应动画,暂停 animator(速度为0)或者设置一个空状态
|
||
if (state == TurretState.Attack && isFrenzy && useFrenzyAnim && !string.IsNullOrEmpty(frenzyAttackAnim))
|
||
{
|
||
new_CurrAnimation.SetTrigger("FrenzyAttack");
|
||
}
|
||
else if (!string.IsNullOrEmpty(attackAnim) || state == TurretState.Idle && !string.IsNullOrEmpty(idleAnim))
|
||
{
|
||
new_CurrAnimation.SetInteger("State", (int)state);
|
||
}
|
||
else
|
||
{
|
||
// 没有可用动画时暂停 animator,避免残留动作
|
||
new_CurrAnimation.speed = 0f;
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 战神 Animator 约定检测:控制器带 PlayFire 参数(14082/14053 等战神状态机)即启用战神模式。
|
||
/// 参数实际类型以运行时 Animator.parameters 为准,不写死(个别控制器 PlayFire 可能是 Trigger)。
|
||
/// 变体索引(fireIndex/idleIndex)检测完一次性写入。
|
||
/// </summary>
|
||
private void DetectWarGodAnimator()
|
||
{
|
||
// 控制器未就绪时不标记,下次 PlayAnimator 再检测
|
||
if (new_CurrAnimation.runtimeAnimatorController == null) return;
|
||
_warGodAnimChecked = true;
|
||
_warGodAnimMode = false;
|
||
|
||
foreach (var p in new_CurrAnimation.parameters)
|
||
{
|
||
if (p.name == playFireParam)
|
||
{
|
||
_warGodAnimMode = true;
|
||
_playFireIsTrigger = p.type == AnimatorControllerParameterType.Trigger;
|
||
}
|
||
else if (p.name == fireIndexParam)
|
||
{
|
||
_hasFireIndex = true;
|
||
_fireIndexType = p.type;
|
||
}
|
||
else if (p.name == idleIndexParam)
|
||
{
|
||
_hasIdleIndex = true;
|
||
_idleIndexType = p.type;
|
||
}
|
||
}
|
||
|
||
if (!_warGodAnimMode) return;
|
||
|
||
// 变体索引一次性写入(Inspector 配置,运行中不变)
|
||
if (_hasFireIndex) SetNumericParam(fireIndexParam, _fireIndexType, fireIndex);
|
||
if (_hasIdleIndex) SetNumericParam(idleIndexParam, _idleIndexType, idleIndex);
|
||
|
||
Debug.Log($"[TurretData] 战神Animator模式 #{turretNumber}: PlayFire={(_playFireIsTrigger ? "Trigger" : "Bool")}, " +
|
||
$"FireIndex={(_hasFireIndex ? fireIndex.ToString() : "无")}, IdleIndex={(_hasIdleIndex ? idleIndex.ToString() : "无")}");
|
||
}
|
||
|
||
/// <summary>
|
||
/// 战神状态切换(14082 等状态机结构):
|
||
/// Idle0 --PlayFire=true--> Fire状态机;Fire0/Fire1 --PlayFire=false--> Exit 回 Idle。
|
||
/// - Bool 型(标准):Attack 置 true 持续开火,Idle 置 false 停火退出;
|
||
/// - Trigger 型(兜底):Attack 设触发器,Idle 复位。
|
||
/// LaserStart/LaserLoop 视为开火中,None/LaserEnd 视为待机。
|
||
/// ⭐ FireIndex 动态切换:锁定中(激光开启)=1 走 Fire1(激光动画);非锁定=0 走 Fire0(正常子弹动画)。
|
||
/// </summary>
|
||
private void PlayWarGodAnimator(TurretState state)
|
||
{
|
||
bool attacking = state == TurretState.Attack
|
||
|| state == TurretState.LaserStart
|
||
|| state == TurretState.LaserLoop;
|
||
|
||
// ⭐ 开火变体:0=正常子弹 1=激光(锁定中)。进 Fire 状态机前先设好值
|
||
if (attacking && _hasFireIndex)
|
||
SetNumericParam(fireIndexParam, _fireIndexType, IsLaserActive() ? 1 : 0);
|
||
|
||
if (_playFireIsTrigger)
|
||
{
|
||
if (attacking) new_CurrAnimation.SetTrigger(playFireParam);
|
||
else new_CurrAnimation.ResetTrigger(playFireParam);
|
||
}
|
||
else
|
||
{
|
||
new_CurrAnimation.SetBool(playFireParam, attacking);
|
||
}
|
||
}
|
||
|
||
/// <summary>
|
||
/// 激光是否开启:战神锁定中即激光开启(与 SitPosData.UpdateZhanShenLaser 的显示条件一致)。
|
||
/// setPosData 由 SitPosData.LoadZhanShen 注入;远程座位的锁定经 SetLockTarget 同步,同样生效。
|
||
/// </summary>
|
||
private bool IsLaserActive()
|
||
{
|
||
var sit = setPosData;
|
||
return sit != null
|
||
&& sit.isLock
|
||
&& sit.monCotl_Lock_Position != null
|
||
&& sit.monCotl_Lock_Position.gameObject.activeInHierarchy;
|
||
}
|
||
|
||
/// <summary>
|
||
/// 锁定状态变化瞬间刷新 FireIndex(0=子弹 Fire0 / 1=激光 Fire1):
|
||
/// ChangeState 同状态早退不会重跑 PlayWarGodAnimator,边开火边锁定时 FireIndex 会停在旧值,
|
||
/// 动画不切 Fire1、SMB 事件永不触发,特效只能等 laserFXDelay 兜底定时器“直接激活”。
|
||
/// 锁定建立/丢失时调用本方法刷新参数 → Fire0↔Fire1 过渡(FireIndex 条件)立即生效,
|
||
/// 特效显示由此完全交给 Fire1 上的 ZhanShenLaserLoopSMB 动画事件开门。
|
||
/// </summary>
|
||
public void RefreshWarGodFireMode()
|
||
{
|
||
if (!_warGodAnimMode || !_hasFireIndex) return;
|
||
if (currState != TurretState.Attack
|
||
&& currState != TurretState.LaserStart
|
||
&& currState != TurretState.LaserLoop) return;
|
||
SetNumericParam(fireIndexParam, _fireIndexType, IsLaserActive() ? 1 : 0);
|
||
}
|
||
|
||
/// <summary>
|
||
/// 战神激光 loop 动画开始通知(ZhanShenLaserLoopSMB 状态机行为 / 剪辑动画事件殊途同归):
|
||
/// 通知座位立即显示激光及全部特效(提前结束 laserFXDelay 等待)。
|
||
/// </summary>
|
||
public void NotifyZhanShenLaserLoopAnim()
|
||
{
|
||
setPosData?.NotifyZhanShenLaserLoopAnim();
|
||
}
|
||
|
||
/// <summary>
|
||
/// AnimationEvent 接收器:在激光 loop 动画剪辑的第 0 帧配动画事件、函数名填 ZhanShenLaserLoopBegin。
|
||
/// ⭐ 前提:Animator 挂在和本组件同一个物体上(动画事件只发给 Animator 所在物体的脚本);
|
||
/// Animator 在子物体上时改用 ZhanShenLaserLoopSMB(Add Behaviour 到 Animator 的 loop 状态)。
|
||
/// </summary>
|
||
public void ZhanShenLaserLoopBegin()
|
||
{
|
||
NotifyZhanShenLaserLoopAnim();
|
||
}
|
||
|
||
/// <summary>按参数实际类型写数值(Int/Bool/Float 通吃)</summary>
|
||
private void SetNumericParam(string paramName, AnimatorControllerParameterType type, int value)
|
||
{
|
||
switch (type)
|
||
{
|
||
case AnimatorControllerParameterType.Int:
|
||
new_CurrAnimation.SetInteger(paramName, value);
|
||
break;
|
||
case AnimatorControllerParameterType.Bool:
|
||
new_CurrAnimation.SetBool(paramName, value != 0);
|
||
break;
|
||
case AnimatorControllerParameterType.Float:
|
||
new_CurrAnimation.SetFloat(paramName, value);
|
||
break;
|
||
}
|
||
}
|
||
|
||
} |