Files
5.24BuYu/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs
T
2026-05-27 19:47:06 +08:00

1278 lines
39 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/*
======================== GameMainPanel_FishBase ========================
【主控制层职责】
负责:输入 → 旋转 → 攻击 → 子弹 → 锁定 → 网络同步 → 广播处理
不负责:动画(TurretData)、发射点(TurretData)、金币(SitPosData)
=======================================================================
① InputModule(输入系统)
├── HandleInput() 主入口
├── 按下(PressDown)
├── 长按(PressHold)
├── 松开(PressUp)
├── CheckTouchIsChangeTurret() 判断是否点到“换炮台按钮”
└── HandleChangeTurretHold() 长按换炮台按钮 → 打开换炮台面板
-----------------------------------------------------------------------
② RotateModule(旋转系统)
├── HandleRotate() 手动旋转入口
├── RotateToTouch() 朝触摸点旋转
├── RotateToLockTarget() 朝锁定目标旋转
├── HandleAutoRotate() 自动开火时的自动旋转
└── AutoSweepRotate() 自动扫射(左右摆动)
-----------------------------------------------------------------------
③ FireModule(攻击系统)
├── TryFire() 长按触发攻击(冷却计时)
├── FireBullet() 发射子弹(普通/三射/双倍/锁定)
├── StartLaser() 激光开始(LaserStart)
├── LoopLaser() 激光持续(LaserLoop)
└── StopLaser() 激光结束(LaserEnd)
-----------------------------------------------------------------------
④ BulletModule(子弹系统)
├── CreateBullet() 创建子弹实例
-----------------------------------------------------------------------
⑤ LockModule(锁定系统)
├── HandleLock() 点击锁定
├── 自动锁定(AutoLock) 可选扩展
├── CancelLock() 取消锁定
├── UpdateLockFX() 锁定特效跟随目标
└── SyncLock() 网络同步锁定状态
-----------------------------------------------------------------------
⑥ NetSyncModule(网络同步)
├── SyncRotate() 同步旋转
├── SyncFire() 同步发射
├── SyncLock() 同步锁定
├── SyncLaserState() 同步激光状态
└── SyncChangeTurret() 同步炮台切换(可选)
-----------------------------------------------------------------------
⑦ NetReceiveModule(服务器广播处理)
├── SyncGameData_Rotate() 广播旋转
├── SyncGameData_FireBullet() 广播发射
├── SyncGameData_ChangeTarget() 广播锁定
├── SyncGameData_ChangeTurret() 广播炮台切换(可选)
└── SyncGameData_LaserState() 广播激光状态(可选)
-----------------------------------------------------------------------
⑧ ResourceModule(资源加载)
├── LoadResources() 加载音频/鱼资源/路线
└── UnLoadResources() 卸载资源
-----------------------------------------------------------------------
⑨ PlayerJoinModule(玩家加入/退出)
├── JoinGame() 玩家加入房间
└── ExitGame() 玩家退出房间
=======================================================================
*/
using Assets.MyGame.Scripts.Net;
using Assets.MyGame.Scripts.Net.API;
using Assets.MyGame.Scripts.Net.APIResponses.Enum;
using Assets.MyGame.Scripts.Net.WebResponses;
using DG.Tweening;
using Newtonsoft.Json;
using Spine.Unity;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using TMPro;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
public class GameMainPanel_FishBase : GameMainPanel_Base
{
[Header("游戏场景")]
public string sceneName;
public GameTypeEnum gameType;
[Header("设置")]
protected bool isOpenSetting;
public Button btn_SettingList;
public Transform SittingListParent;
public Button btn_TuiChu;
[Header("我在这")]
public GameObject mySitAnim;
[Header("Skill")]
public Dictionary<string, Toggle> dic_Skill_Toggle = new Dictionary<string, Toggle>();//开关型技能
public Toggle toggle_SkillAuto;
public Toggle toggle_Lock;
public Toggle toggle_Three;
public Toggle toggle_Shuang;
public Toggle toggle_BaoZou;
public Image img_BaoZou;
public float frenzyDuration = 5f; // 疯狂状态持续时间
public float currFrenzyTime = 0f;
public Toggle toggle_BingFeng;
public Image img_BingFeng;
public float bingFengDuration = 5f; // 冰封状态持续时间
public float currBingFengTime = 0f;
public List<SitPosData> list_Sits = new List<SitPosData>();
public SitPosData currSitData;
[Header("攻击参数")]
public float attackTime = 0.5f;
float clickTime = 0;
public GameObject bullet_Test;
public GameObject bulletParent;
float changeTurretTime = 0f;
bool isChangingTurret = false;
int bulletCount = 0;
public GameObject boardCast_Boss;
AudioClip bulletClip;
public List<int> paoBeiList=new List<int>();
public ProgressBar JinDuTiao;
#region UI
bool isfirstShow = true;
protected override void OnShow(object args = null)
{
base.OnShow(args);
LoadResources();
//UIManager.Instance.ShowBoard("太好看了");
var v = JsonConvert.DeserializeObject<WebSocketResponseBase<RoomJoinNotice>>(args.ToString());
if (v.arguments.Count > 0)
{
RoomJoinNotice roomJoinNotice = v.arguments[0];
if (isfirstShow)
{
int t = GameManager.Instance.gameData.currRoomData.gameType;
int l = GameManager.Instance.gameData.currRoomData.roomLevel;
foreach (var item in GameManager.Instance.gameConfig.roomConfigs)
{
if (item.gameType== t && l == GameManager.Instance.gameData.currRoomData.roomLevel)
{
paoBeiList= item.cannonMultipleList;
}
}
string roomId = GameManager.Instance.gameData.currRoomData.roomId;
//string roomId = GameManager.Instance.gameData.currRoomData;
foreach (var item in GameManager.Instance.gameData.currRoomData.players)
{
JoinGame(item.position, item.gold, item.cannonMultiple, 0, item.userId);
}
GameManager.Instance.gameData.roomJoinNotice = v.arguments[0];
isfirstShow = false;
currSitData = list_Sits[roomJoinNotice.position];
//currSitData.ChangeTurret(1);
currSitData.lockFX.transform.GetChild(0).gameObject.SetActive(false);
currSitData.lockFX.transform.GetChild(1).gameObject.SetActive(true);
mySitAnim.GetComponent<RectTransform>().anchoredPosition = currSitData.currentTurret.GetComponent<RectTransform>().anchoredPosition;
}
else
{
JoinGame(roomJoinNotice.position, roomJoinNotice.gold, roomJoinNotice.cannonMultiple, 0, roomJoinNotice.userId);
}
}
else
{
UIManager.Instance.ShowBoardError("获取信息失败");
}
}
protected override void OnHide()
{
base.OnHide();
UnLoadResources();
SceneManager.UnloadSceneAsync(sceneName);
WebSocketManager.Instance.Close(SocketType.game);
}
#endregion
#region 生命周期
private float baseAttackTime;
public override void Awake()
{
base.Awake();
baseAttackTime = attackTime;
btn_TuiChu.onClick.AddListener(() =>
{
WebSocketSendList.LeaveRoom(GameManager.Instance.gameData.currRoomData.roomId, currSitData.user);
CreateFishManager.Instance.fangzhu = false;
});
// 服务器广播监听
EventCenter.Instance.AddEventListener<SyncGameData>(ConstEventString.SyncGameData_Rotate, SyncGameData_Rotate);
EventCenter.Instance.AddEventListener<FireCannonSendData>(ConstEventString.SyncGameData_FireBullet, SyncGameData_FireBullit);
EventCenter.Instance.AddEventListener<SyncGameData>(ConstEventString.SyncGameData_ChangeTargetMonster, SyncGameData_ChangeTargetMonster);
EventCenter.Instance.AddEventListener<SyncGameData>(ConstEventString.SyncGameData_RendromDieFish, SyncGameData_RendromDieFish);
EventCenter.Instance.AddEventListener<SyncGameData>(ConstEventString.SyncGameData_TurretState, SyncGameData_TurretState);
EventCenter.Instance.AddEventListener<SyncGameData>(ConstEventString.SyncGameData_ChangeTurret, SyncGameData_ChangeTurret);
}
public virtual void OnDestroy()
{
EventCenter.Instance.RemoveEventListener<SyncGameData>(ConstEventString.SyncGameData_Rotate, SyncGameData_Rotate);
EventCenter.Instance.RemoveEventListener<FireCannonSendData>(ConstEventString.SyncGameData_FireBullet, SyncGameData_FireBullit);
EventCenter.Instance.RemoveEventListener<SyncGameData>(ConstEventString.SyncGameData_ChangeTargetMonster, SyncGameData_ChangeTargetMonster);
EventCenter.Instance.RemoveEventListener<SyncGameData>(ConstEventString.SyncGameData_RendromDieFish, SyncGameData_RendromDieFish);
EventCenter.Instance.RemoveEventListener<SyncGameData>(ConstEventString.SyncGameData_TurretState, SyncGameData_TurretState);
EventCenter.Instance.RemoveEventListener<SyncGameData>(ConstEventString.SyncGameData_ChangeTurret, SyncGameData_ChangeTurret);
}
public virtual void Start()
{
btn_SettingList.onClick.AddListener(() =>
{
if (isOpenSetting) StartCoroutine(CloseSettingList());
else StartCoroutine(OpenSettingList());
});
if (toggle_Lock != null)
{
toggle_Lock.onValueChanged.AddListener(on =>
{
if (!on)
{
// 本地清理锁定
if (currSitData != null)
currSitData.ClearLock();
// 同步给服务器:取消锁定
SyncGameData sgd = new SyncGameData
{
sitPos = currSitData.posID,
frameType = FrameDataType.changeAutoTarget,
time = BeijingTimeManager.Instance.CurrentTimestampMs,
frameData = new FrameData_ChangeAutoTarget { targetGuid = null }
};
WebSocketSendList.SyncGameData(sgd);
}
});
}
toggle_BaoZou.onValueChanged.AddListener(on =>
{
// UI 开关只是触发,但最终状态以 currGameType 为准
CreateFishManager.Instance.currGameType.isFrenzy = on;
SetFrenzy(on);
});
toggle_SkillAuto.onValueChanged.AddListener(on =>
{
if (!on)
{
// 自动开火关闭 → 立即切回 Idle
currSitData.ChangeState(TurretState.Idle);
}
});
toggle_BingFeng.onValueChanged.AddListener(on => {
});
}
public bool isFrenzy;
public void SetFrenzy(bool on)
{
bool frenzy = CreateFishManager.Instance.currGameType.isFrenzy;
// 攻击速度翻倍
attackTime = frenzy ? baseAttackTime * 0.5f : baseAttackTime;
// 动画倍速
if (currSitData != null && currSitData.currentTurret != null)
currSitData.currentTurret.SetFrenzy(frenzy);
}
public void OnEnable()
{
}
int ina = 0;
private void Update()
{
if (Keyboard.current.oKey.wasPressedThisFrame)
{
ina++;
currSitData.ChangeTurret(ina);
}
if (Keyboard.current.pKey.wasPressedThisFrame)
{
ina--;
currSitData.ChangeTurret(ina);
}
HandleInput();
HandleAutoRotate();
CheckLockTargetValid();//锁定目标失效自动清除
HandleAutoFire(); // 自动开火真正发射
HandleLock();
UpdateLockFX();
HandleAutoLock();
LoopLaser();
SettingClose();
}
float sittingTime = 10;
float currSittingTime;
/// <summary>
/// 等待10秒未操作关闭设置面板
/// </summary>
public void SettingClose()
{
//if (isOpenSetting) StartCoroutine(CloseSettingList());
//else StartCoroutine(OpenSettingList());
if (isOpenSetting)
{
currSittingTime -= Time.deltaTime;
if (currSittingTime <= 0)
{
StartCoroutine(CloseSettingList());
}
}
else
{
currSittingTime = 10;
}
}
#endregion
#region 资源加载模块
public async void LoadResources()
{
CreateFishManager.Instance.isResources = false;
await AudioResourcesData.LoadAudioGame();
JinDuTiao.SetProgress(0.2f);
await MonsterMoveLine.LoadBezier();
JinDuTiao.SetProgress(0.4f);
await FishResourcesData.LoadFishAssetsData();
JinDuTiao.SetProgress(0.6f);
await Addressables.LoadAssetsAsync<AudioClip>("Audio", clip =>
{
if (clip.name == "PW_Shoot")
bulletClip = clip;
}).Task;
JinDuTiao.SetProgress(0.8f);
await Task.Delay(100);
CreateFishManager.Instance.EnterRoom(gameType);
CreateFishManager.Instance.isResources = true;
JinDuTiao.SetProgress(0.9f);
await Task.Delay(2000);
JinDuTiao.SetProgress(1);
await Task.Delay(300);
JinDuTiao.Hide();
}
public async void UnLoadResources()
{
CreateFishManager.Instance.ExitRoom();
CreateFishManager.Instance.isResources = false;
await FishResourcesData.UnLoadFishAssetsData();
await AudioResourcesData.UnLoadAudioGame();
await MonsterMoveLine.UnLoadBezier();
}
#endregion
#region 输入系统(InputModule)
private bool IsPointerOverUI(Vector2 pos)
{
PointerEventData eventData = new PointerEventData(EventSystem.current);
eventData.position = pos;
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(eventData, results);
return results.Count > 0;
}
public struct CrossPlatformInput
{
public bool isPressed;
public bool wasPressedThisFrame;
public bool wasReleasedThisFrame;
public Vector2 position;
}
private CrossPlatformInput GetInput()
{
CrossPlatformInput input = new CrossPlatformInput();
// ============================
// PC / Editor → 鼠标输入
// ============================
#if UNITY_STANDALONE || UNITY_EDITOR
if (Mouse.current != null)
{
input.isPressed = Mouse.current.leftButton.isPressed;
input.wasPressedThisFrame = Mouse.current.leftButton.wasPressedThisFrame;
input.wasReleasedThisFrame = Mouse.current.leftButton.wasReleasedThisFrame;
input.position = Mouse.current.position.ReadValue();
}
#else
// ============================
// 移动平台 → 触摸输入
// ============================
var touch = Touchscreen.current?.primaryTouch;
if (touch != null)
{
input.isPressed = touch.press.isPressed;
input.wasPressedThisFrame = touch.press.wasPressedThisFrame;
input.wasReleasedThisFrame = touch.press.wasReleasedThisFrame;
input.position = touch.position.ReadValue();
}
#endif
return input;
}
private void HandleInput()
{
CrossPlatformInput input = GetInput();
if (!input.isPressed && !input.wasPressedThisFrame && !input.wasReleasedThisFrame)
return;
// ⭐ UI 点击过滤
if (IsPointerOverUI(input.position))
return;
// 按下
if (input.wasPressedThisFrame)
{
isChangingTurret = CheckTouchIsChangeTurret(input.position);
clickTime = attackTime;
if (mySitAnim != null && mySitAnim.gameObject.activeSelf)
mySitAnim.gameObject.SetActive(false);
if (!isChangingTurret)
currSitData.ChangeState(TurretState.Attack);
}
// 长按
if (input.isPressed)
{
if (isChangingTurret)
{
HandleChangeTurretHold();
return;
}
HandleRotate(input.position);
TryFire();
}
// 松开
if (input.wasReleasedThisFrame)
{
if (isChangingTurret)
{
isChangingTurret = false;
changeTurretTime = 0;
CloseChangeTurretUI();
return;
}
currSitData.ChangeState(TurretState.Idle);
}
}
private void HandleChangeTurretHold()
{
changeTurretTime += Time.deltaTime;
if (changeTurretTime > 1f)
{
if (!currSitData.changeTurretList.activeSelf)
currSitData.changeTurretList.SetActive(true);
}
}
private bool CheckTouchIsChangeTurret(Vector2 pos)
{
PointerEventData pointerData = new PointerEventData(EventSystem.current);
pointerData.position = pos;
List<RaycastResult> results = new List<RaycastResult>();
EventSystem.current.RaycastAll(pointerData, results);
foreach (var result in results)
{
if (result.gameObject.CompareTag("ChangeTurret"))
{
SitPosData sit = result.gameObject.GetComponentInParent<SitPosData>();
if (sit == currSitData)
return true;
}
}
return false;
}
private void CloseChangeTurretUI()
{
currSitData.changeTurretList.SetActive(false);
changeTurretTime = 0;
isChangingTurret = false;
}
#endregion
#region 打开关闭右上角设置选项
public virtual IEnumerator OpenSettingList()
{
RectTransform tran = SittingListParent.GetComponent<RectTransform>();
tran.gameObject.SetActive(true);
tran.DOSizeDelta(new Vector2(466, 143), 0.2f);
isOpenSetting = true;
Vector3 v3 = btn_SettingList.transform.localScale;
v3.x = Mathf.Abs(v3.x) * -1;
btn_SettingList.transform.localScale = v3;
yield break;
}
public virtual IEnumerator CloseSettingList()
{
RectTransform tran = SittingListParent.GetComponent<RectTransform>();
Vector3 v3 = btn_SettingList.transform.localScale;
v3.x = Mathf.Abs(v3.x);
btn_SettingList.transform.localScale = v3;
tran.DOSizeDelta(new Vector2(0, 143), 0.2f).OnComplete(() =>
{
tran.gameObject.SetActive(false);
});
isOpenSetting = false;
yield break;
}
#endregion
#region ② 炮台旋转系统(RotateModule)
//private void HandleRotate(Vector2 pos)
//{
// if (toggle_Lock.isOn && currSitData.monCotl_Lock != null)
// {
// RotateToLockTarget(currSitData);
// }
// else
// {
// RotateToTouch(currSitData, pos);
// }
//}
private void HandleRotate(Vector2 pos)
{
// ⭐ 只有真正锁定目标时才自动旋转
if (toggle_Lock.isOn && currSitData.isLock && currSitData.monCotl_Lock != null)
{
RotateToLockTarget(currSitData);
}
else
{
// 锁定开关开着但没有锁定目标 → 允许手动旋转
RotateToTouch(currSitData, pos);
}
}
private void RotateToTouch(SitPosData sit, Vector2 pos)
{
RectTransformUtility.ScreenPointToLocalPointInRectangle(
sit.tra_CurrTurret.transform.parent as RectTransform,
pos, null, out Vector2 localPos);
Vector2 dir = localPos - sit.tra_CurrTurret.GetComponent<RectTransform>().anchoredPosition;
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 90f;
sit.SetRotation(angle);
SyncRotate(angle);
}
private void RotateToLockTarget(SitPosData sit)
{
Vector2 screenPos = Camera.main.WorldToScreenPoint(sit.monCotl_Lock_Position.position);
RectTransformUtility.ScreenPointToLocalPointInRectangle(
sit.tra_CurrTurret.transform.parent as RectTransform,
screenPos, null, out Vector2 localPos);
Vector2 dir = localPos - sit.tra_CurrTurret.GetComponent<RectTransform>().anchoredPosition;
float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 90f;
sit.SetRotation(angle);
}
private void HandleAutoRotate()
{
// 锁定模式优先
if (toggle_Lock.isOn && currSitData.isLock)
{
RotateToLockTarget(currSitData);
return;
}
// 自动开火关闭 → 不自动旋转
if (!toggle_SkillAuto.isOn) return;
// 自动扫射(左右摆动)
AutoSweepRotate();
}
private float autoRotateAngle = 0;
private float autoRotateSpeed = 40f;
private float autoRotateMin = -60f;
private float autoRotateMax = 60f;
private int autoRotateDir = 1;
private void AutoSweepRotate()
{
autoRotateAngle += autoRotateSpeed * autoRotateDir * Time.deltaTime;
if (autoRotateAngle > autoRotateMax)
{
autoRotateAngle = autoRotateMax;
autoRotateDir = -1;
}
else if (autoRotateAngle < autoRotateMin)
{
autoRotateAngle = autoRotateMin;
autoRotateDir = 1;
}
currSitData.SetRotation(autoRotateAngle);
}
private Coroutine rotateCoroutine;
private void SmoothRotate(SitPosData sit, float angle)
{
sit.SetRotation(angle); // 先立即更新角度(逻辑角度)
if (rotateCoroutine != null)
StopCoroutine(rotateCoroutine);
rotateCoroutine = StartCoroutine(RotateIE_Angle(sit, Quaternion.Euler(0, 0, angle)));
}
private IEnumerator RotateIE_Angle(SitPosData sit, Quaternion target)
{
float angleThreshold = 0.1f;
while (true)
{
float angleDiff = Quaternion.Angle(sit.tra_CurrTurret.rotation, target);
if (angleDiff <= angleThreshold)
{
sit.tra_CurrTurret.rotation = target;
yield break;
}
sit.tra_CurrTurret.rotation = Quaternion.Lerp(
sit.tra_CurrTurret.rotation,
target,
0.6f
);
yield return null;
}
}
#endregion
#region Skill系统(SkillModule)
public void DaoJiShi()
{
if (toggle_BaoZou.isOn)
{
img_BaoZou.fillAmount = currFrenzyTime / frenzyDuration;
currFrenzyTime -= Time.deltaTime;
if (currFrenzyTime <= 0)
{
toggle_BaoZou.isOn = false;
img_BaoZou.fillAmount = 1;
}
}
if (toggle_BingFeng.isOn)
{
img_BingFeng.fillAmount = currBingFengTime / bingFengDuration;
currBingFengTime -= Time.deltaTime;
if (currBingFengTime <= 0)
{
toggle_BingFeng.isOn = false;
img_BingFeng.fillAmount = 1;
}
}
}
#endregion
#region ③ 攻击系统(FireModule)
private void TryFire()
{
clickTime += Time.deltaTime;
if (clickTime < attackTime) return;
clickTime = 0;
float angle = currSitData.currentAngle;
bool isSanShe = toggle_Three.isOn;
bool isDouble = toggle_Shuang.isOn;
bool isLock = toggle_Lock.isOn;
//FireBullet(currSitData, angle, isSanShe, isDouble, isLock);
SyncFire(angle, isSanShe, isDouble, isLock);
}
private void FireBullet(SitPosData sit, float angle, bool isSanShe, bool isDouble, bool isLock,List<string> bullitIDs)
{
Vector2 startPos = sit.GetBulletStartPos();
if (isSanShe)
{
CreateBullet(sit, startPos, angle - 20, isDouble, isLock, bullitIDs[0]);
CreateBullet(sit, startPos, angle, isDouble, isLock, bullitIDs[1]);
CreateBullet(sit, startPos, angle + 20, isDouble, isLock, bullitIDs[2]);
}
else
{
CreateBullet(sit, startPos, angle, isDouble, isLock, bullitIDs[0]);
}
AudioManager.Instance.PlayFX(bulletClip);
}
private bool isLaser = false;
private void StartLaser()
{
isLaser = true;
currSitData.ChangeState(TurretState.LaserStart);
SyncLaserState(TurretState.LaserStart);
}
private void LoopLaser()
{
if (!isLaser) return;
// TODO: 激光持续伤害 / 特效
}
private void StopLaser()
{
isLaser = false;
currSitData.ChangeState(TurretState.LaserEnd);
SyncLaserState(TurretState.LaserEnd);
}
private float autoFireTimer = 0f;
//private void HandleAutoFire()
//{
// if (!toggle_SkillAuto.isOn) return;
// if (currSitData == null) return;
// autoFireTimer += Time.deltaTime;
// if (autoFireTimer < attackTime) return;
// autoFireTimer = 0f;
// float angle = currSitData.currentAngle;
// bool isSanShe = toggle_Three.isOn;
// bool isDouble = toggle_Shuang.isOn;
// bool isLock = toggle_Lock.isOn;
// FireBullet(currSitData, angle, isSanShe, isDouble, isLock);
// SyncFire(angle, isSanShe, isDouble, isLock);
//}
private void HandleAutoFire()
{
if (currSitData == null) return;
bool needAutoFire = toggle_SkillAuto.isOn || (toggle_Lock.isOn && currSitData.isLock && currSitData.lockFX.gameObject.activeSelf);
if (!needAutoFire)
{
autoFireTimer = 0f;
return;
}
autoFireTimer += Time.deltaTime;
if (autoFireTimer < attackTime) return;
autoFireTimer = 0f;
float angle = currSitData.currentAngle;
bool isSanShe = toggle_Three.isOn;
bool isDouble = toggle_Shuang.isOn;
bool isLock = toggle_Lock.isOn;
// ⭐ 自动攻击也要播放攻击动画
currSitData.ChangeState(TurretState.Attack);
//FireBullet(currSitData, angle, isSanShe, isDouble, isLock);
SyncFire(angle, isSanShe, isDouble, isLock);
}
#endregion
#region 锁定系统(LockModule)
private void HandleLock()
{
CrossPlatformInput input = GetInput();
if (!toggle_Lock.isOn) return;
// 只有按下那一帧才触发锁定
if (!input.wasReleasedThisFrame&&!input.wasPressedThisFrame) return;
// ⭐ UI 点击过滤
if (IsPointerOverUI(input.position))
return;
Vector2 worldPos = Camera.main.ScreenToWorldPoint(input.position);
RaycastHit2D hit = Physics2D.Raycast(worldPos, Vector2.zero, 50, LayerMask.GetMask("Fish"));
if (hit.collider != null)
{
MonsterContral monster = hit.collider.GetComponentInParent<MonsterContral>();
currSitData.SetLockTarget(monster, hit.collider.transform);
SyncLock(new List<string> { monster?.guid }, monster.colliderList.IndexOf(hit.collider.transform));
}
else
{
currSitData.ClearLock();
SyncLock(null);
}
}
private void UpdateLockFX()
{
foreach (var sit in list_Sits)
{
if (!sit.isLock || sit.monCotl_Lock == null) continue;
Vector3 pos = Vector3.zero;
if (!sit.monCotl_Lock_Position.gameObject.activeInHierarchy)
{
foreach (Transform t in sit.monCotl_Lock.colliderList)
{
if (t.gameObject.activeInHierarchy)
{
sit.monCotl_Lock_Position = t;
pos = sit.monCotl_Lock_Position.position;
break;
}
}
if (!sit.monCotl_Lock_Position.gameObject.activeInHierarchy)
{
if (sit.lockFX.activeSelf)
sit.lockFX.SetActive(false);
}
}
else
{
pos = sit.monCotl_Lock_Position.position;
if (!sit.lockFX.activeSelf)
sit.lockFX.SetActive(true);
}
pos.z = Camera.main.transform.position.z + 1;
sit.lockFX.transform.position = pos;
}
}
private void CheckLockTargetValid()
{
if (!currSitData.isLock) return;
var monster = currSitData.monCotl_Lock;
// 目标无效:被对象池回收 / 不激活 / 被销毁
if (monster == null || !monster.gameObject.activeInHierarchy)
{
currSitData.ClearLock(); // 清除锁定
SyncLock(null); // 同步服务器
// ⭐⭐⭐ 关键:怪死了 → 动画回到 Idle ⭐⭐⭐
currSitData.ChangeState(TurretState.Idle);
}
}
private void HandleAutoLock()
{
// 自动锁定必须满足:自动开火 + 锁定开关开启
if (!toggle_SkillAuto.isOn) return;
if (!toggle_Lock.isOn) return; // ✔ 自动锁定必须在锁定开关开启时才工作
// 已经有锁定目标并且还活着,就不重复找
if (currSitData.isLock &&
currSitData.monCotl_Lock != null &&
currSitData.monCotl_Lock.gameObject.activeInHierarchy)
{
return;
}
MonsterContral target = FindAutoLockTarget();
if (target != null)
{
currSitData.SetLockTarget(target, target.transform);
if (target.colliderList.Count>0)
{
for (int i = 0; i < target.colliderList.Count; i++)
{
if (target.colliderList[i].gameObject.activeInHierarchy)
{
SyncLock(new List<string> { target?.guid }, i);
}
}
}
else
{
SyncLock(new List<string> { target?.guid }, -1);
}
}
else
{
currSitData.ClearLock();
SyncLock(null);
}
}
private MonsterContral FindAutoLockTarget()
{
if (CreateFishManager.Instance == null ||
CreateFishManager.Instance.fishDatas_hashCodekey == null ||
CreateFishManager.Instance.fishDatas_hashCodekey.Count == 0)
return null;
MonsterContral best = null;
float bestSqr = float.MaxValue;
Vector3 origin = currSitData.tra_CurrTurret.position;
foreach (var kv in CreateFishManager.Instance.fishDatas_hashCodekey)
{
MonsterContral m = kv.Value;
if (m == null || !m.gameObject.activeInHierarchy) continue;
float sqr = (m.transform.position - origin).sqrMagnitude;
if (sqr < bestSqr)
{
bestSqr = sqr;
best = m;
}
}
return best;
}
//private void HandleAutoLock()
//{
// if (!toggle_SkillAuto.isOn) return;
// if (toggle_Lock.isOn) return;
// if (currSitData.isLock) return;
// MonsterContral nearest = CreateFishManager.Instance;
// if (nearest != null)
// {
// currSitData.SetLockTarget(nearest, nearest.transform);
// SyncLock(nearest);
// }
//}
#endregion
#region BulletModule(子弹系统)
private BullitMove CreateBullet(SitPosData sit, Vector2 pos, float angle, bool isDouble, bool isLock,string id)
{
GameObject prefab = isDouble ? sit.currentTurret.bulletPrefab_Two : sit.currentTurret.bulletPrefab;
if (!sit.ConsumeGold(isDouble ? 2 : 1))
return null;
var bullet = Instantiate(prefab, pos, Quaternion.Euler(0, 0, angle), bulletParent.transform)
.GetComponent<BullitMove>();
bullet.userid = sit.user;
bullet.playerID = sit.user;
bullet.bulletID = id;
if (isLock)
bullet.Lock(sit.monCotl_Lock, currSitData.monCotl_Lock_Position);
return bullet;
}
#endregion
#region ⑥ 网络同步(NetSyncModule)
private void SyncRotate(float angle)
{
SyncGameData sgd = new SyncGameData
{
sitPos = currSitData.posID,
frameType = FrameDataType.rotateTurrect,
time = BeijingTimeManager.Instance.CurrentTimestampMs,
frameData = new FrameData_Rotate { angle = angle }
};
WebSocketSendList.SyncGameData(sgd);
}
private void SyncFire(float angle, bool isSanShe, bool isDouble, bool isLock)
{
SyncGameData sgd = new SyncGameData
{
sitPos = currSitData.posID,
frameType = FrameDataType.fireBullet,
time = BeijingTimeManager.Instance.CurrentTimestampMs,
frameData = new FrameData_FireBullit
{
angle = angle,
gold = currSitData.goldNum,
isSanShe = isSanShe,
twoRTruuect = isDouble,
isSuoDing = isLock,
auto = toggle_SkillAuto.isOn
}
};
//WebSocketSendList.SyncGameData(sgd);
var roomdata = GameManager.Instance.gameData.currRoomData;
var user = GameManager.Instance.user;
// 三射 = 3 发,否则 = 1 发
int count = isSanShe ? 3 : 1;
// 新版 FireCannon 不需要 timestamp 和 sign
WebSocketSendList.FireCannon(
roomdata.roomId,
user.id,
currSitData.consumeGoldNum,
count,
sgd,
"63215f0afa3f5b25"
);
// WebSocketSendList.FireCannon(roomdata.roomId, user.id,currSitData.consumeGoldNum,1,BeijingTimeManager.Instance.CurrentTimestamp, "63215f0afa3f5b25", sgd);
}
private void SyncLock(List<string> monsterguid,int index=-1)
{
SyncGameData sgd = new SyncGameData
{
sitPos = currSitData.posID,
frameType = FrameDataType.changeAutoTarget,
time = BeijingTimeManager.Instance.CurrentTimestampMs,
frameData = new FrameData_ChangeAutoTarget
{
targetGuid = monsterguid,
colliderIndex=index,
}
};
WebSocketSendList.SyncGameData(sgd);
}
private void SyncLaserState(TurretState state)
{
SyncGameData sgd = new SyncGameData
{
sitPos = currSitData.posID,
frameType = FrameDataType.changeTurretState,
time = BeijingTimeManager.Instance.CurrentTimestampMs,
frameData = new FrameData_TurretState { state = state }
};
WebSocketSendList.SyncGameData(sgd);
}
private void SyncChangeTurret(int index)
{
SyncGameData sgd = new SyncGameData
{
sitPos = currSitData.posID,
frameType = FrameDataType.changeTurret,
time = BeijingTimeManager.Instance.CurrentTimestampMs,
frameData = new FrameData_ChangeTurret { turretIndex = index }
};
WebSocketSendList.SyncGameData(sgd);
}
#endregion
#region ⑦ 服务器广播处理(NetReceiveModule)
public void SyncGameData_Rotate(SyncGameData sync)
{
if (sync.sitPos == currSitData.posID) return;
var data = FrameDataParser.Parse<FrameData_Rotate>(sync.frameData);
SmoothRotate(list_Sits[sync.sitPos], data.angle);
}
public void SyncGameData_FireBullit(FireCannonSendData sync)
{
//if (sync.sitPos == currSitData.posID) return;
var data = FrameDataParser.Parse<FrameData_FireBullit>(sync.extra.frameData);
FireBullet(list_Sits[sync.extra.sitPos], data.angle, data.isSanShe, data.twoRTruuect, data.isSuoDing,sync.bulletIds);
}
public void SyncGameData_ChangeTargetMonster(SyncGameData sync)
{
if (sync.sitPos == currSitData.posID) return;
var data = FrameDataParser.Parse<FrameData_ChangeAutoTarget>(sync.frameData);
if (data.targetGuid == null)
{
list_Sits[sync.sitPos].ClearLock();
return;
}
MonsterContral monster = CreateFishManager.Instance.fishDatas_hashCodekey[data.targetGuid[0]];
Transform hitPos = data.colliderIndex != -1?monster.colliderList[ data.colliderIndex]: monster.transform;
list_Sits[sync.sitPos].SetLockTarget(monster, hitPos);
}
public void SyncGameData_RendromDieFish(SyncGameData sync)
{
var data = JsonConvert.DeserializeObject<FrameData_RandomDieFish>(sync.frameData.ToString());
CreateFishManager.Instance.Id_DieListFish_FX(
data.guids,
data.coinNum,
new Vector3(data.x, data.y, data.z),
data.count
);
}
public void SyncGameData_TurretState(SyncGameData sync)
{
if (sync.sitPos == currSitData.posID) return;
var data = FrameDataParser.Parse<FrameData_TurretState>(sync.frameData);
var sit = list_Sits[sync.sitPos];
sit.ChangeState(data.state);
}
public void SyncGameData_ChangeTurret(SyncGameData sync)
{
if (sync.sitPos == currSitData.posID) return;
var data = FrameDataParser.Parse<FrameData_ChangeTurret>(sync.frameData);
list_Sits[sync.sitPos].ChangeTurret(data.turretIndex);
}
#endregion
#region 玩家加入/退出(PlayerJoinModule)
public void JoinGame(int sitNum, long goldNum, long consumeGold, int currentTurretIndex, string user = null)
{
foreach (var sit in list_Sits)
{
if (sit.posID != sitNum) continue;
sit.gameObject.SetActive(true);
sit.user = user ?? GameManager.Instance.user.id;
sit.goldNum = goldNum;
sit.consumeGoldNum = consumeGold;
sit.tMP_GoldNum.text = goldNum.ToString();
sit.tMP_TurretConsumeNum.text = consumeGold.ToString();
sit.ChangeTurret(currentTurretIndex);
}
}
public void TuiChuHHWK()
{
WebSocketSendList.LeaveRoom(GameManager.Instance.gameData.currRoomData.roomId, currSitData.user);
CreateFishManager.Instance.fangzhu = false;
}
#endregion
}