using System;
using System.Collections.Generic;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class SitPosData : MonoBehaviour
{
/// 本地玩家的座位引用(由游戏面板初始化时设置)
public static SitPosData localPlayerSit;
/// 当前房间房主座位(人机请求由房主发送,房主退出后自动继承)
public static SitPosData roomOwnerSit;
// -------------------------
// 玩家基础信息
// -------------------------
[Header("玩家信息")]
public string user;
[Tooltip("座位编号 0~3。0,1=下方 2,3=上方")]
public int posID;
[Tooltip("是否为人机")]
public bool isBot = false;
/// posID>=2 = 上方,需要翻转(0,1=下方;2,3=上方)
public bool IsFlipped => posID >= 2;
[Header("金币")]
public long goldNum;
public long consumeGoldNum;
public TextMeshProUGUI tMP_GoldNum;
public TextMeshProUGUI tMP_DiamondNum;
public TextMeshProUGUI tMP_TurretConsumeNum;
[Header("翅膀")]
[Tooltip("翅膀实例化的父节点")]
public Transform wingParent;
// -------------------------
// 炮台管理(动态克隆)
// -------------------------
[Header("炮台")]
[Tooltip("炮台实例化的父节点")]
public Transform turretParent;
[Tooltip("炮台锚点位置(相对 turretParent)")]
public Vector2 turretAnchoredPos = Vector2.zero;
[Tooltip("当前装备的炮台编号")]
public int currentTurretNumber;
/// 当前运行中的炮台实例
public TurretData currentTurret;
// 状态机入口(GameMainPanel 调用)
public Action OnStateChange;
// -------------------------
// 炮台旋转
// -------------------------
[Header("炮台旋转")]
public Transform tra_CurrTurret;
public float currentAngle;
///
/// 炮台在世界坐标(Z=0平面)的位置缓存。
/// 因为炮台是 UGUI 元素,tra_CurrTurret.position 是 Canvas 坐标,不能直接和鱼的世界坐标比较距离。
/// 这里用和子弹起点(GetBulletStartWorldPos)相同的转换方式,把 UI 坐标转成世界坐标。
/// 由 LoadTurret 加载完炮台后计算并缓存,bot AI/锁定检测距离时用此字段。
///
[System.NonSerialized]
public Vector3 turretWorldPos;
// -------------------------
// 锁定系统
// -------------------------
[Header("锁定系统")]
public MonsterContral monCotl_Lock;
public Transform monCotl_Lock_Position;
public bool isLock = false;
public GameObject lockFX; // 主锁定图标(单发/双倍用)
public List lockFX_Triple = new List(); // 三发锁定额外2个图标
public List tripleLockTargets = new List();
public List tripleLockPositions = new List();
// -------------------------
// UI
// -------------------------
[Header("UI")]
public Button btn_TurretAdd;
public Button btn_TurretMinus;
private void Awake()
{
btn_TurretAdd.onClick.AddListener(() => ChangeTurretAddConsumeNum());
btn_TurretMinus.onClick.AddListener(() => ChangeTurretMinusConsumeNum());
}
private void OnEnable()
{
// 默认显示等待界面
ShowWaiting();
}
private void OnDisable()
{
if (localPlayerSit == this)
localPlayerSit = null;
// 房主退出 → 自动继承给第一个非人机玩家
if (roomOwnerSit == this)
{
roomOwnerSit = null;
TransferRoomOwner();
}
}
///
/// 玩家加入 → 显示玩家 UI(child0),隐藏等待界面(child1)。
///
public void ShowPlayer()
{
if (transform.childCount > 0)
transform.GetChild(0).gameObject.SetActive(true);
if (transform.childCount > 1)
transform.GetChild(1).gameObject.SetActive(false);
// 如果是本地玩家的座位,自动注册并加载装备
if (user == GameManager.Instance?.user?.id)
{
localPlayerSit = this;
var cannonUsing = GameManager.Instance.user.cannonUsing;
if (cannonUsing != null && int.TryParse(cannonUsing.number, out int num))
LoadTurret(num);
var wingUsing = GameManager.Instance.user.wingUsing;
if (wingUsing != null && int.TryParse(wingUsing.number, out int wingNum))
LoadWing(wingNum);
}
// 非人机玩家加入时,自动分配为首个房主
if (!isBot)
AssignRoomOwner(this);
}
///
/// 玩家退出/等待 → 显示等待界面(child1),隐藏玩家 UI(child0)。
///
public void ShowWaiting()
{
if (transform.childCount > 0)
transform.GetChild(0).gameObject.SetActive(false);
if (transform.childCount > 1)
transform.GetChild(1).gameObject.SetActive(true);
}
/// 房主退出后,将房主身份转移给第一个活跃的非人机玩家
/// 鱼创建已由服务端 OnFishSpawn 统一下发,此处仅维护 roomOwnerSit 标识(用于 bot 控制/AFK 等场景)。
public static void TransferRoomOwner()
{
var list = FindObjectsOfType();
foreach (var sit in list)
{
if (!sit.isBot && sit.gameObject.activeInHierarchy && sit != roomOwnerSit)
{
roomOwnerSit = sit;
break;
}
}
}
/// 分配房主(首个非人机玩家)
/// 鱼创建已由服务端 OnFishSpawn 统一下发,此处仅维护 roomOwnerSit 标识(用于 bot 控制/AFK 等场景)。
public static void AssignRoomOwner(SitPosData sit)
{
if (roomOwnerSit == null && !sit.isBot)
{
roomOwnerSit = sit;
}
}
// ==================== 炮台加载(动态克隆) ====================
///
/// 根据炮台编号,从 Addressables 加载预制体并克隆到 turretParent。
/// 位置/旋转/缩放保持预制体原始值,不动。
///
public void LoadTurret(int turretNumber)
{
// ⭐ 换炮台时只清活跃子弹(清屏),保留池缓存(同 prefab 能复用)
// 用 ClearActive 而非 ClearAll:ClearAll 会清池导致永远不复用
BulletPool.Instance.ClearActive();
if (currentTurret != null)
{
Destroy(currentTurret.gameObject);
currentTurret = null;
}
currentTurretNumber = turretNumber;
// 从 TurretResourcesData 拿预制体
GameObject prefab = TurretResourcesData.GetTurretPrefab(turretNumber);
if (prefab == null)
{
Debug.LogWarning($"[SitPosData] 炮台预制体未加载: #{turretNumber}");
return;
}
// 克隆到父节点
GameObject instance = Instantiate(prefab, turretParent, false);
instance.SetActive(true);
// 固定位置归零,由外部父节点定位
var rt = instance.GetComponent();
if (rt != null)
rt.anchoredPosition = turretAnchoredPos;
currentTurret = instance.GetComponent();
if (currentTurret == null)
{
Debug.LogError($"[SitPosData] 预制体上未找到 TurretData 组件: #{turretNumber}");
Destroy(instance);
return;
}
currentTurret.turretNumber = turretNumber;
// 缓存旋转节点
//tra_CurrTurret = currentTurret.transform.GetChild(0);
tra_CurrTurret = currentTurret.transform.parent;
// 绑定状态机入口
OnStateChange = currentTurret.ChangeState;
// ⭐ 缓存炮台在世界坐标(Z=0平面)的位置,bot AI/锁定检测距离时用
// 和子弹起点(GetBulletStartWorldPos)用相同的 UI→世界 转换方式
UpdateTurretWorldPos();
Debug.Log($"[SitPosData] 炮台已加载: #{turretNumber}");
}
///
/// 把炮台 UI 坐标转换成世界坐标(Z=0平面)并缓存到 turretWorldPos。
/// 转换方式和 TurretData.GetBulletStartWorldPos 一致。
///
public void UpdateTurretWorldPos()
{
if (tra_CurrTurret == null)
{
turretWorldPos = Vector3.zero;
return;
}
RectTransform rect = tra_CurrTurret.GetComponent();
if (rect != null && UIManager.Instance != null && UIManager.Instance.uiRoot != null)
{
Canvas canvas = UIManager.Instance.uiRoot.GetComponent