1
This commit is contained in:
@@ -2234,6 +2234,22 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
/// <summary>召唤鱼 guid(= 服务端 fishId.ToString()):Notice 比 OnFishSpawn 先到时记录,等鱼建出来再检索</summary>
|
||||
private string _summonFishGuid;
|
||||
|
||||
[Header("召唤卡漩涡特效")]
|
||||
[Tooltip("召唤鱼漩涡特效预制体(鱼本体先隐藏,特效旋转到指定位置后鱼才激活出现在屏幕中央)")]
|
||||
public GameObject summonVortexFXPrefab;
|
||||
[Tooltip("漩涡特效时长(秒):特效转完这一刻激活鱼开始移动(需与特效动画时长一致)")]
|
||||
public float summonVortexDuration = 1.5f;
|
||||
|
||||
[Header("召唤卡出场(旋转放大)")]
|
||||
[Tooltip("出场时长(秒):原地旋转 + 放大到正常大小的时间")]
|
||||
public float summonEntranceDuration = 0.5f;
|
||||
[Tooltip("出场自转圈数(正数=顺时针,负数=逆时针)。以 0.5 位置的正确朝向为终点倒推,转完正好落在正确朝向")]
|
||||
public float summonSelfSpinTurns = 2f;
|
||||
[Tooltip("出场自转轴:默认 Z 轴(屏幕平面内自转)")]
|
||||
public Vector3 summonSelfSpinAxis = new Vector3(0f, 0f, 1f);
|
||||
[Tooltip("出场位置偏移(世界坐标):微调漩涡/出场落点")]
|
||||
public Vector3 summonEntranceTargetOffset = Vector3.zero;
|
||||
|
||||
/// <summary>
|
||||
/// 服务端 SummonCardFishNotice 房间广播回调:某玩家使用召唤卡,服务端已创建召唤鱼。
|
||||
/// 仅播放召唤提示(飞机场召唤Boss鱼,其他场次召唤黄金鱼),
|
||||
@@ -2292,19 +2308,120 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 召唤鱼特殊处理:保存引用 + 开始时间加整体时间的一半。
|
||||
/// moveTime 初始 = moveLine.moveTime * 0.5 → 鱼直接出现在路线 0.5 位置(屏幕中央),
|
||||
/// 之后从中间继续向终点游(moveTime 继续累计,走满总时长离场)。
|
||||
/// isMove=false 的鱼不走路线(固定位置播动画),跳过偏移。
|
||||
/// 召唤鱼特殊处理:保存引用 + 漩涡出场流程。
|
||||
/// 流程:① 鱼本体先未激活(隐藏)→ ② 漩涡特效在指定位置(路线 0.5 = 屏幕中央)播放旋转
|
||||
/// → ③ 特效时长到了再激活鱼(OnEnable 复位后 ChangeState(move) 自动开始移动)
|
||||
/// → ④ 激活后重设 moveTime = 总时长*0.5(OnEnable 会把 moveTime 复位成 0,必须在激活后设置)。
|
||||
/// 未拖 summonVortexFXPrefab 时跳过特效,直接放中间(兜底)。
|
||||
/// </summary>
|
||||
private void ApplySummonFishCenterSpawn(MonsterContral monster)
|
||||
{
|
||||
_summonFish = monster;
|
||||
if (monster == null || !monster.isMove) return;
|
||||
if (monster == null) return;
|
||||
StartCoroutine(SummonVortexRoutine(monster));
|
||||
}
|
||||
|
||||
/// <summary>漩涡出场协程:鱼先隐藏 → 漩涡在路线 0.5 位置播放 → 激活鱼但先禁用 MonsterContral → 原地旋转+放大出场(终点朝向=0.5 位置的正确朝向)→ 再启用 MonsterContral 继续游动</summary>
|
||||
private IEnumerator SummonVortexRoutine(MonsterContral monster)
|
||||
{
|
||||
var moveLine = monster.monsterData?.moveLine;
|
||||
if (moveLine == null || moveLine.moveTime <= 0f) return;
|
||||
// ⭐ 开始时间 = 0 + 整体时间的一半 → 直接放在路线 0.5(屏幕中央)
|
||||
monster.moveTime = moveLine.moveTime * 0.5f;
|
||||
|
||||
// 出场位置 = 路线 0.5 位置(屏幕中央);无路线的 Boss 兜底用屏幕正中
|
||||
Vector3 spawnPos = GetSummonCenterWorld(monster);
|
||||
if (moveLine != null && moveLine.moveTime > 0f)
|
||||
{
|
||||
// 中点世界坐标:路径上 moveTime = 总时长一半的位置(GetBezierPointJob 按秒取点)
|
||||
Vector2 center2D = moveLine.GetBezierPointJob(moveLine.moveTime * 0.5f);
|
||||
spawnPos = new Vector3(center2D.x, center2D.y, spawnPos.z);
|
||||
}
|
||||
spawnPos += summonEntranceTargetOffset;
|
||||
|
||||
// ① 鱼本体先未激活(漩涡期间不显示、不移动、打不到)
|
||||
if (monster.gameObject.activeSelf)
|
||||
monster.gameObject.SetActive(false);
|
||||
|
||||
// ② 漩涡特效:在路线 0.5 位置播放,旋转期间鱼保持隐藏
|
||||
if (summonVortexFXPrefab != null)
|
||||
{
|
||||
EffectPool.Instance.Get(summonVortexFXPrefab, spawnPos, Quaternion.identity,
|
||||
CreateFishManager.Instance.transform.parent); // autoReturn=true:粒子播完自动回池
|
||||
yield return new WaitForSeconds(summonVortexDuration);
|
||||
}
|
||||
|
||||
// ⭐ 漩涡期间这条鱼被击杀/回收(guid 已被复用成别的鱼)→ 中止出场,避免把回池的鱼又拉出来
|
||||
if (monster == null || monster.isDead || monster.guid != _summonFishGuid) yield break;
|
||||
|
||||
// ③ 出场期间先禁用 MonsterContral 再激活预制体(这些预制体默认是未激活状态):
|
||||
// 组件禁用时 OnEnable 不会跑 → 不会在出场瞬间按路线瞬移/开始游动,
|
||||
// 也避免了"激活后再禁用"导致 Boss 的 OnEnable 跑两遍(重复进场音效/随机泳姿)
|
||||
monster.enabled = false;
|
||||
monster.gameObject.SetActive(true);
|
||||
monster.transform.position = spawnPos;
|
||||
|
||||
// ④ 用鱼自身的朝向逻辑算出"0.5 位置的正确朝向"(含侧倾/镜像补偿),取出被改写的节点;
|
||||
// 朝向逻辑用的 uirootRect/mainCamera/_cachedChild 是出生时 OnEnable 缓存的(禁用时不会被清)
|
||||
MonsterContral.RouteFacingResult facing = monster.GetRouteFacingAt(0.5f);
|
||||
Vector3 scaleTarget = monster.transform.localScale; // 此刻的缩放就是最终缩放(None 分支的左右镜像也在里面)
|
||||
monster.transform.localScale = Vector3.zero; // 从 0 放大出来
|
||||
|
||||
// ⑤ 旋转 + 放大出场:以"正确朝向"为基准倒退若干圈开始转,转到最后一帧正好落在正确朝向
|
||||
yield return SummonScaleSpinEntrance(monster, facing, scaleTarget);
|
||||
|
||||
// ⑥ 精确归位:朝向/缩放/位置写死成目标值,再启用 MonsterContral 从路线 50% 继续游动
|
||||
// (OnEnable 会把 moveTime 清零,所以 moveTime 必须在启用之后设置 → OnSummonEntranceEnd 内部处理)
|
||||
if (monster == null || monster.isDead || !monster.gameObject.activeInHierarchy) yield break;
|
||||
if (facing.valid && facing.node != null) facing.node.rotation = facing.rotation;
|
||||
monster.transform.localScale = scaleTarget;
|
||||
monster.transform.position = spawnPos;
|
||||
monster.enabled = true;
|
||||
monster.OnSummonEntranceEnd(0.5f);
|
||||
}
|
||||
|
||||
/// <summary>屏幕正中(画布中心)的世界坐标,z 沿用鱼自身深度</summary>
|
||||
private Vector3 GetSummonCenterWorld(MonsterContral monster)
|
||||
{
|
||||
var uiRootRect = UIManager.Instance.uiRoot.GetComponent<RectTransform>();
|
||||
Vector3 world = CoordinateTransformation.CanvasToWorld(Vector2.zero, uiRootRect, Camera.main);
|
||||
world.z = monster.transform.position.z;
|
||||
return world;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 召唤出场:原地旋转 + 放大出来。
|
||||
/// ⭐ 旋转以"0.5 位置的正确朝向"为基准倒退 summonSelfSpinTurns 圈开始,
|
||||
/// 转到最后一帧正好落在正确朝向(不会有收尾的朝向跳变)。
|
||||
/// ⭐ 只转朝向逻辑决定的那一个节点(根节点 或 child0):另一个节点保持预制体姿态。
|
||||
/// </summary>
|
||||
private IEnumerator SummonScaleSpinEntrance(MonsterContral monster, MonsterContral.RouteFacingResult facing, Vector3 scaleTarget)
|
||||
{
|
||||
float duration = Mathf.Max(0.01f, summonEntranceDuration);
|
||||
float spinTotal = summonSelfSpinTurns * 360f;
|
||||
float elapsed = 0f;
|
||||
while (elapsed < duration)
|
||||
{
|
||||
// 出场途中被击杀/回收(回池会 SetActive(false))→ 立即中止,交由死亡流程处理
|
||||
if (monster == null || monster.isDead || !monster.gameObject.activeInHierarchy) yield break;
|
||||
|
||||
elapsed += Time.deltaTime;
|
||||
float t = Mathf.Clamp01(elapsed / duration);
|
||||
float ease = 1f - Mathf.Pow(1f - t, 3f); // OutCubic:先快后慢,收尾自然
|
||||
|
||||
// 放大出来:0 → 最终缩放(含左右镜像的 x 符号)
|
||||
monster.transform.localScale = Vector3.Lerp(Vector3.zero, scaleTarget, ease);
|
||||
|
||||
// 旋转出来:从"正确朝向倒退 spinTotal 度"转到"正确朝向"
|
||||
if (facing.valid && facing.node != null)
|
||||
{
|
||||
float deg = spinTotal * (1f - ease); // ease=0 → 倒退 spinTotal;ease=1 → 0(正确朝向)
|
||||
facing.node.rotation = facing.rotation * Quaternion.AngleAxis(deg, summonSelfSpinAxis);
|
||||
}
|
||||
yield return null;
|
||||
}
|
||||
|
||||
// 收尾精确落在正确朝向 + 最终缩放
|
||||
if (facing.valid && facing.node != null)
|
||||
facing.node.rotation = facing.rotation;
|
||||
monster.transform.localScale = scaleTarget;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Reference in New Issue
Block a user