This commit is contained in:
2026-05-28 18:16:45 +08:00
parent ecff13130f
commit 4a6677b252
7 changed files with 269 additions and 22 deletions
@@ -8,5 +8,6 @@ public class ConstEventString
public const string SyncGameData_RendromDieFish = "SyncGameData_RenderDieFish";
public const string SyncGameData_TurretState = "SyncGameData_TurretState";
public const string SyncGameData_ChangeTurret = "SyncGameData_ChangeTurret";
public const string SyncGameData_FreezeFish = "SyncGameData_FreezeFish";
}
@@ -96,6 +96,8 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
public Dictionary<string, RoomFishDetailConfig> spawnDic;
public bool isCreateFish; //是否可以创建鱼
public bool isFrozen = false; //是否冰冻中(冻结出鱼+所有鱼定格)
private Dictionary<string, CharacterStateType> frozenFishStates = new Dictionary<string, CharacterStateType>();
/// <summary>按鱼类型分类的生成配置(Boss / 普通 / 黄金…)</summary>
private Dictionary<FishTypeEnum, List<RoomFishDetailConfig>> fishTypeConfig;
@@ -240,7 +242,8 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
private void Update()
{
isCreateFish = BroadCastCreateFish();
if (!isFrozen)
isCreateFish = BroadCastCreateFish();
}
@@ -902,6 +905,7 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
/// <param name="syncGameData"></param>
public void CreateFish(SyncGameData syncGameData)
{
if (isFrozen) return; // 冰冻中不创建鱼
var rotateData = FrameDataParser.Parse<FrameData_CreateFish>(syncGameData.frameData);
if (rotateData != null)
SpawnFishMainThread(rotateData, syncGameData.time);
@@ -1487,7 +1491,9 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
{
if (item.user == killFish.userId)
{
item.monCotl_Lock = null;
// 只有死的鱼正好是当前锁定目标时才清除
if (item.monCotl_Lock != null && item.monCotl_Lock.guid == killFish.fishId)
item.monCotl_Lock = null;
//item.lockFX.gameObject.SetActive(false);
sitData = item;
}
@@ -1681,4 +1687,54 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
return null;
}
}
#region 冰冻技能
/// <summary>
/// 冰冻:记录所有鱼当前状态并强制切到 Idle(暂停移动+动画)
/// </summary>
public void FreezeAllFish()
{
isFrozen = true;
frozenFishStates.Clear();
// 只遍历全量字典 fishDatas_hashCodekey(已包含所有鱼),不重复遍历子字典
if (fishDatas_hashCodekey != null)
{
foreach (var kv in fishDatas_hashCodekey)
{
MonsterContral m = kv.Value;
if (m == null || !m.gameObject.activeInHierarchy) continue;
// 记录原状态
frozenFishStates[m.guid] = m.currState;
// 定格
m.isMove = false;
m.ChangeState(CharacterStateType.idle);
}
}
}
/// <summary>
/// 解冻:恢复鱼到冰冻前状态
/// </summary>
public void UnfreezeAllFish()
{
isFrozen = false;
if (fishDatas_hashCodekey != null)
{
foreach (var kv in fishDatas_hashCodekey)
{
MonsterContral m = kv.Value;
if (m == null || !m.gameObject.activeInHierarchy) continue;
m.isMove = true;
if (frozenFishStates.TryGetValue(m.guid, out var prevState))
m.ChangeState(prevState);
}
}
frozenFishStates.Clear();
}
#endregion
}
@@ -48,7 +48,8 @@ namespace Assets.MyGame.Scripts.Net.WebResponses
changeAutoTarget=4,
randomDieFish=5,
changeTurretState=6,
changeTurret=7
changeTurret=7,
freezeFish=8
}
[Serializable]
@@ -93,6 +94,8 @@ namespace Assets.MyGame.Scripts.Net.WebResponses
public bool twoRTruuect;
public string monsterID;
public bool isZuanTou;
/// <summary>三发锁定时每个子弹对应的鱼 GUID(3个),按优先级排序</summary>
public List<string> monsterIDs;
}
[Serializable]
public class FrameData_CreateFish : FrameData
@@ -127,4 +130,9 @@ namespace Assets.MyGame.Scripts.Net.WebResponses
{
public int turretIndex;
}
[Serializable]
public class FrameData_FreezeFish : FrameData
{
public bool isFreeze; // true=冰冻开始, false=解冻结束
}
}
@@ -202,6 +202,9 @@ namespace Assets.MyGame.Scripts.Net
case FrameDataType.randomDieFish:
EventCenter.Instance.EventTrigger<SyncGameData>(ConstEventString.SyncGameData_RendromDieFish, syncGameData);
break;
case FrameDataType.freezeFish:
EventCenter.Instance.EventTrigger<SyncGameData>(ConstEventString.SyncGameData_FreezeFish, syncGameData);
break;
default:
break;
}
@@ -91,6 +91,7 @@ using Spine.Unity;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
@@ -240,6 +241,7 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
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);
EventCenter.Instance.AddEventListener<SyncGameData>(ConstEventString.SyncGameData_FreezeFish, SyncGameData_FreezeFish);
}
@@ -251,6 +253,7 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
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);
EventCenter.Instance.RemoveEventListener<SyncGameData>(ConstEventString.SyncGameData_FreezeFish, SyncGameData_FreezeFish);
@@ -290,6 +293,7 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
// UI 开关只是触发,但最终状态以 currGameType 为准
CreateFishManager.Instance.currGameType.isFrenzy = on;
SetFrenzy(on);
if (on) currFrenzyTime = frenzyDuration;
});
toggle_SkillAuto.onValueChanged.AddListener(on =>
{
@@ -299,10 +303,23 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
currSitData.ChangeState(TurretState.Idle);
}
});
toggle_BingFeng.onValueChanged.AddListener(on => {
toggle_BingFeng.onValueChanged.AddListener(on => {
if (on)
{
// 开始冰冻
currBingFengTime = bingFengDuration;
CreateFishManager.Instance.FreezeAllFish();
SyncFreeze(true);
}
else
{
// 手动关闭 → 解冻
if (CreateFishManager.Instance.isFrozen)
{
CreateFishManager.Instance.UnfreezeAllFish();
SyncFreeze(false);
}
}
});
@@ -357,6 +374,7 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
HandleAutoLock();
LoopLaser();
SettingClose();
DaoJiShi();
}
float sittingTime = 10;
@@ -768,6 +786,7 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
{
toggle_BingFeng.isOn = false;
img_BingFeng.fillAmount = 1;
// 解冻由 toggle.onValueChanged(false) 触发,不在此重复
}
}
}
@@ -789,10 +808,47 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
//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)
private void FireBullet(SitPosData sit, float angle, bool isSanShe, bool isDouble, bool isLock, List<string> bullitIDs,
List<string> fireTargetMonsterIDs = null)
{
Vector2 startPos = sit.GetBulletStartPos();
if (isSanShe)
// ⭐ 三发 + 锁定 + 有多目标:每发子弹瞄准不同的目标
if (isSanShe && isLock && fireTargetMonsterIDs != null && fireTargetMonsterIDs.Count > 0)
{
for (int i = 0; i < 3 && i < fireTargetMonsterIDs.Count; i++)
{
// 按 GUID 查找目标
MonsterContral targetMonster = null;
Transform targetHitPos = null;
if (CreateFishManager.Instance.fishDatas_hashCodekey.TryGetValue(fireTargetMonsterIDs[i], out var m)
&& m != null && m.gameObject.activeInHierarchy)
{
targetMonster = m;
targetHitPos = m.transform;
// 优先用活跃 collider
if (m.colliderList != null)
{
foreach (var col in m.colliderList)
{
if (col.gameObject.activeInHierarchy) { targetHitPos = col; break; }
}
}
}
if (targetMonster != null)
{
// 计算朝目标的角度
Vector3 targetWorldPos = targetHitPos.position;
Vector2 dir = ((Vector2)targetWorldPos - startPos).normalized;
float targetAngle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 90f;
string bulletId = i < bullitIDs.Count ? bullitIDs[i] : bullitIDs[0];
CreateBullet(sit, startPos, targetAngle, isDouble, true, bulletId, targetMonster, targetHitPos);
}
}
}
else if (isSanShe)
{
CreateBullet(sit, startPos, angle - 20, isDouble, isLock, bullitIDs[0]);
CreateBullet(sit, startPos, angle, isDouble, isLock, bullitIDs[1]);
@@ -881,6 +937,83 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
#endregion
#region 多目标查找(TripleLock)
/// <summary>鱼锁定优先级:特殊Boss(5) > Boss鱼(4) > 特殊鱼(3) > 黄金鱼(2) > 普通鱼(1)</summary>
private int GetFishLockPriority(MonsterContral monster)
{
switch (monster.fishenum)
{
case FishTypeEnum.特殊Boss: return 5;
case FishTypeEnum.Boss鱼: return 4;
case FishTypeEnum.特殊鱼: return 3;
case FishTypeEnum.黄金鱼: return 2;
case FishTypeEnum.普通鱼: return 1;
default: return 0;
}
}
/// <summary>
/// 查找 fire 时的多目标(三发锁定用)。
/// 第一个目标 = 主锁 monCotl_Lock(打哪锁哪),剩余从 Boss/特殊Boss/特殊鱼/黄金鱼 按优先级补满
/// </summary>
private List<(MonsterContral monster, Transform hitPos)> FindFireTargets(int maxCount)
{
var result = new List<(MonsterContral monster, Transform hitPos)>();
var selected = new HashSet<string>();
if (CreateFishManager.Instance == null) return result;
// ① 主锁目标排第一(打哪锁哪)
if (currSitData.isLock && currSitData.monCotl_Lock != null &&
currSitData.monCotl_Lock.gameObject.activeInHierarchy)
{
Transform pos = currSitData.monCotl_Lock_Position != null && currSitData.monCotl_Lock_Position.gameObject.activeInHierarchy
? currSitData.monCotl_Lock_Position
: currSitData.monCotl_Lock.transform;
result.Add((currSitData.monCotl_Lock, pos));
selected.Add(currSitData.monCotl_Lock.guid);
if (result.Count >= maxCount) return result;
}
// ② 按优先级从分类字典补满剩余位置
var dicts = new Dictionary<string, MonsterContral>[]
{
CreateFishManager.Instance.fishDatas_hashCodekey_TS_Boss,
CreateFishManager.Instance.fishDatas_hashCodekey_Boss,
CreateFishManager.Instance.fishDatas_hashCodekey_TS,
CreateFishManager.Instance.fishDatas_hashCodekey_HJ,
};
foreach (var dict in dicts)
{
if (dict == null) continue;
foreach (var kv in dict)
{
MonsterContral m = kv.Value;
if (m == null || !m.gameObject.activeInHierarchy) continue;
if (selected.Contains(m.guid)) continue; // 跳过已选中的
Transform pos = m.transform;
if (m.colliderList != null)
{
foreach (var col in m.colliderList)
{
if (col.gameObject.activeInHierarchy) { pos = col; break; }
}
}
result.Add((m, pos));
selected.Add(m.guid);
if (result.Count >= maxCount) return result;
}
}
return result;
}
#endregion
#region 锁定系统(LockModule)
@@ -1056,7 +1189,8 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
#endregion
#region BulletModule(子弹系统)
private BullitMove CreateBullet(SitPosData sit, Vector2 pos, float angle, bool isDouble, bool isLock,string id)
private BullitMove CreateBullet(SitPosData sit, Vector2 pos, float angle, bool isDouble, bool isLock, string id,
MonsterContral lockTarget = null, Transform lockHitPos = null)
{
GameObject prefab = isDouble ? sit.currentTurret.bulletPrefab_Two : sit.currentTurret.bulletPrefab;
@@ -1071,7 +1205,12 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
bullet.bulletID = id;
if (isLock)
bullet.Lock(sit.monCotl_Lock, currSitData.monCotl_Lock_Position);
{
if (lockTarget != null)
bullet.Lock(lockTarget, lockHitPos);
else
bullet.Lock(sit.monCotl_Lock, currSitData.monCotl_Lock_Position);
}
return bullet;
}
@@ -1093,20 +1232,30 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
private void SyncFire(float angle, bool isSanShe, bool isDouble, bool isLock)
{
var fireData = new FrameData_FireBullit
{
angle = angle,
gold = currSitData.goldNum,
isSanShe = isSanShe,
twoRTruuect = isDouble,
isSuoDing = isLock,
auto = toggle_SkillAuto.isOn
};
// ⭐ 三发 + 锁定:查找 3 个优先级目标,写入 monsterIDs
if (isSanShe && isLock)
{
var targets = FindFireTargets(3);
if (targets.Count > 0)
fireData.monsterIDs = targets.Select(t => t.monster.guid).ToList();
}
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
}
frameData = fireData
};
//WebSocketSendList.SyncGameData(sgd);
var roomdata = GameManager.Instance.gameData.currRoomData;
@@ -1173,6 +1322,18 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
WebSocketSendList.SyncGameData(sgd);
}
private void SyncFreeze(bool isFreeze)
{
SyncGameData sgd = new SyncGameData
{
sitPos = currSitData.posID,
frameType = FrameDataType.freezeFish,
time = BeijingTimeManager.Instance.CurrentTimestampMs,
frameData = new FrameData_FreezeFish { isFreeze = isFreeze }
};
WebSocketSendList.SyncGameData(sgd);
}
#endregion
@@ -1190,7 +1351,7 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
//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);
FireBullet(list_Sits[sync.extra.sitPos], data.angle, data.isSanShe, data.twoRTruuect, data.isSuoDing, sync.bulletIds, data.monsterIDs);
}
public void SyncGameData_ChangeTargetMonster(SyncGameData sync)
@@ -1242,6 +1403,17 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
list_Sits[sync.sitPos].ChangeTurret(data.turretIndex);
}
public void SyncGameData_FreezeFish(SyncGameData sync)
{
if (sync.sitPos == currSitData.posID) return; // 自己发的不管
var data = FrameDataParser.Parse<FrameData_FreezeFish>(sync.frameData);
if (data.isFreeze)
CreateFishManager.Instance.FreezeAllFish();
else
CreateFishManager.Instance.UnfreezeAllFish();
}
#endregion
@@ -3521,6 +3521,13 @@ MonoBehaviour:
toggle_Three: {fileID: 748668496574007314}
toggle_Shuang: {fileID: 870607161084201748}
toggle_BaoZou: {fileID: 6820470193323630788}
img_BaoZou: {fileID: 4519855428832475769}
frenzyDuration: 5
currFrenzyTime: 0
toggle_BingFeng: {fileID: 7126682788597616111}
img_BingFeng: {fileID: 734296607713292731}
bingFengDuration: 5
currBingFengTime: 0
list_Sits:
- {fileID: 1736561711096904313}
- {fileID: 9022000259197046427}
@@ -4483,7 +4490,7 @@ MonoBehaviour:
m_PersistentCalls:
m_Calls: []
m_Sprite: {fileID: 21300000, guid: 698df028996d4c14dace6f08d1aa8452, type: 3}
m_Type: 0
m_Type: 3
m_PreserveAspect: 0
m_FillCenter: 1
m_FillMethod: 4