This commit is contained in:
2026-05-18 18:39:11 +08:00
parent 198149c3bc
commit 9b832ca7ad
130 changed files with 29989 additions and 29671 deletions
+347 -278
View File
@@ -107,6 +107,8 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
/// <summary>当前房间 fishNumber → RoomFishDetailConfig</summary>
public Dictionary<string, RoomFishDetailConfig> spawnDic;
public bool isCreateFish; //是否可以创建鱼
/// <summary>按鱼类型分类的生成配置(Boss / 普通 / 黄金…)</summary>
private Dictionary<FishTypeEnum, List<RoomFishDetailConfig>> fishTypeConfig;
@@ -126,17 +128,26 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
private NativeArray<int> shouldSpawn; // 1=本帧应尝试生成,0=冷却中
// ------ 各类计时器 ------
private RoomFishProbabilityConfig tsbossCreateData; // 特殊Boss 创建数据
private float tsbossTimer = 999f; // 特殊Boss 刷新倒计时(秒)
private RoomFishProbabilityConfig tsCreateData; // 特殊鱼 创建数据
private float tsTimer = 999f; // 特殊鱼 刷新倒计时(秒)
private RoomFishProbabilityConfig bossCreateData; // Boss 创建数据
private float bossTimer = 999f; // Boss 刷新倒计时(秒)
private RoomFishProbabilityConfig yzCreateData; // 鱼阵创建数据
private float yzTimer = 999f; // 鱼阵刷新倒计时(秒)
private RoomFishProbabilityConfig ptCreateData; // 普通鱼创建数据
private float ptTimer = 999f; // 普通鱼批量启用倒计时(秒)
private RoomFishProbabilityConfig hjCreateData; // 普通鱼创建数据
private float hjTimer = 999f; // 黄金鱼批量启用倒计时(秒)
private int yzCount; // 本轮同时激活阵型数量
private int ptCount; // 本轮同时启用普通鱼数量
private int bossCount; // 本轮同时启用Boss鱼数量
private int hjCount; // 本轮同时启用黄金鱼数量
private int tsCount; // 本轮同时启用特殊鱼数量
private int bossCount; // 本轮同时启用特殊Boss鱼数量
private int tsbossCount; // 本轮同时启用Boss鱼数量
private int yz_LineCount = 0; // 场景内鱼阵路线总数
/// <summary>是否开启放鱼(false 时 Update 不执行生成逻辑)</summary>
public bool fangzhu;
public bool isResources = false;
@@ -176,7 +187,7 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
{
get { EnsureInit(); return createDic; }
}
#region 生命周期
// ================================================================
// Unity 生命周期
// ================================================================
@@ -206,19 +217,18 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
}
public void InitChuYu()
// ================================================================
// Update:定时调度 + Job 驱动生成
// ================================================================
private void Update()
{
// 随机初始化计时器,避免所有类型同帧触发
yzCount = Random.Range(yzCreateData.countRange[0], yzCreateData.countRange[1]);
ptCount = Random.Range(ptCreateData.countRange[0], ptCreateData.countRange[1]);
bossCount = Random.Range(ptCreateData.countRange[0], ptCreateData.countRange[1]);
yzTimer = 0.5f;
ptTimer = 0.5f;
bossTimer = 5f;
//yzTimer = Random.Range(yzCreateData.timeRange[0], yzCreateData.timeRange[1]);
//ptTimer = Random.Range(ptCreateData.timeRange[0], ptCreateData.timeRange[1]);
//bossTimer = Random.Range(bossCreateData.timeRange[0], bossCreateData.timeRange[1]);
isCreateFish = BroadCastCreateFish();
}
private void OnDestroy()
{
EventCenter.Instance.RemoveEventListener<SyncGameData>(
@@ -227,228 +237,24 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
// 释放 NativeArray,避免内存泄漏
DisposeNativeArrays();
}
#endregion
// ================================================================
// Update:定时调度 + Job 驱动生成
// ================================================================
private void Update()
#region 初始化
public void InitChuYu()
{
if (!isResources)
{
return;
}
// 未初始化 或 未开启放鱼 → 跳过
if (spawnList == null || !fangzhu) return;
float dt = Time.deltaTime;
// ---- 1. 用 Job System 并行更新所有鱼的计时器 ----
var job = new FishSpawnTimerJob
{
deltaTime = dt,
timers = timers,
frequencies = frequencies,
shouldSpawn = shouldSpawn,
};
job.Schedule().Complete();
// ---- 2. Boss 定时激活 ----
TickBossSpawn(dt);
// ---- 3. 鱼阵定时激活 ----
TickFishArraySpawn(dt);
TickFishArraySpawn(dt);
// ---- 4. 普通鱼定时批量激活 ----
TickNormalFishSpawn(dt);
// ---- 5. 遍历 shouldSpawn,向服务器发送生成请求 ----
ProcessSpawnRequests();
}
// ================================================================
// 定时 Tick 方法(由 Update 调用)
// ================================================================
/// <summary>每 25 秒随机激活一条 Boss 鱼。</summary>
private void TickBossSpawn(float dt)
{
bossTimer -= dt;
if (bossTimer > 0f) return;
bossCount = Random.Range(ptCreateData.countRange[0], ptCreateData.countRange[1]);
bossTimer = Random.Range(bossCreateData.timeRange[0], bossCreateData.timeRange[1]);
if (!fishTypeConfig.TryGetValue(FishTypeEnum.Boss鱼, out var bossList) || bossList.Count == 0)
return;
StartCoroutine(buchongfu(bossList, bossCount));
foreach (var item in bossList)
{
if (item.fishNumber == 11026.ToString())
{
item.isCreate = 2;
}
}
}
IEnumerator buchongfu(List<RoomFishDetailConfig> bossList,int count)
{
for (int j = 0; j < count; j++)
{
while (true)
{
int i = Random.Range(0, bossList.Count);
if (fishDatas_hashCodekey_Boss.Count > 0)
{
foreach (var item in fishDatas_hashCodekey_Boss)
{
if (bossList[i].fishNumber != item.Value.fishTypeID.ToString())
{
bossList[i].isCreate = 2;
yield break;
}
}
}
else
{
bossList[i].isCreate = 2;
yield break;
}
yield return null;
}
}
}
/// <summary>每 1~3 秒随机激活若干组鱼阵。</summary>
private void TickFishArraySpawn(float dt)
{
yzTimer -= dt;
if (yzTimer > 0f) return;
// 随机初始化计时器,避免所有类型同帧触发
yzCount = Random.Range(yzCreateData.countRange[0], yzCreateData.countRange[1]);
yzTimer = Random.Range(yzCreateData.timeRange[0], yzCreateData.timeRange[1]);
int lineCount = yz_FishConfig_Line_List.Count;
if (lineCount == 0) return;
// 随机选 yzCount 个不重复的阵型下标
var selectedIndices = RandomUniqueNumbers(
Mathf.Min(yzCount, lineCount), 0, lineCount);
foreach (int idx in selectedIndices)
{
string arrayNumber = yz_FishConfig_Line_Dic[idx];
if (!yz_FishConfig_Line.TryGetValue(arrayNumber, out var lineList) || lineList.Count == 0)
continue;
// 随机选一条配置并标记为待生成
var chosen = lineList[Random.Range(0, lineList.Count)];
chosen.isCreate = 2;
// 同步更新 spawnDic 中的状态
if (spawnDic.TryGetValue(chosen.fishNumber, out var spawnEntry))
spawnEntry.isCreate = 2;
}
}
/// <summary>每 3 秒随机批量激活若干条普通鱼。</summary>
private void TickNormalFishSpawn(float dt)
{
ptTimer -= dt;
if (ptTimer > 0f) return;
ptCount = Random.Range(ptCreateData.countRange[0], ptCreateData.countRange[1]);
ptTimer = Random.Range(ptCreateData.timeRange[0], ptCreateData.timeRange[1]);
if (!fishTypeConfig.TryGetValue(FishTypeEnum.普通鱼, out var normalList) || normalList.Count == 0)
return;
// 随机选 ptCount 个不重复下标
var indices = RandomUniqueNumbers(
Mathf.Min(ptCount, normalList.Count), 0, normalList.Count);
foreach (int idx in indices)
normalList[idx].isCreate = 2;
hjCount = Random.Range(hjCreateData.countRange[0], hjCreateData.countRange[1]);
bossCount = Random.Range(bossCreateData.countRange[0], bossCreateData.countRange[1]);
yzTimer = 0.5f;
ptTimer = 0.5f;
hjTimer = 0.5f;
bossTimer = 5f;
//yzTimer = Random.Range(yzCreateData.timeRange[0], yzCreateData.timeRange[1]);
//ptTimer = Random.Range(ptCreateData.timeRange[0], ptCreateData.timeRange[1]);
//bossTimer = Random.Range(bossCreateData.timeRange[0], bossCreateData.timeRange[1]);
}
/// <summary>
/// 遍历 shouldSpawn 数组,对本帧到期且被标记 isCreate==2 的鱼
/// 向服务器发送 WebSocket 生成同步包。
/// </summary>
private void ProcessSpawnRequests()
{
for (int i = 0; i < spawnList.Count; i++)
{
if (shouldSpawn[i] != 1) continue;
var fish = spawnList[i];
// isCreate==0:刚到期,重置为冷却中,等待外部计时器激活
if (fish.isCreate == 0)
{
fish.isCreate = 1; // 标记为"已处理但未激活"
continue;
}
// isCreate==2:已被激活,向服务器同步一次生成请求
if (fish.isCreate == 2)
{
SendCreateFishRequest(fish);
fish.isCreate = 0;
}
}
}
/// <summary>
/// 构建并发送生成鱼的 WebSocket 同步数据包。
/// </summary>
private void SendCreateFishRequest(RoomFishDetailConfig fish)
{
int pathId = 0;
// 普通鱼(type==1)才从 pathList 随机选路径;鱼阵(type==2)由后续逻辑决定
if (fish.type == 1)
{
var pathList = FishDatas[fish.fishNumber].pathList;
if (pathList != null && pathList.Count > 0)
pathId = pathList[Random.Range(0, pathList.Count)];
}
var sgd = new SyncGameData
{
sitPos = GameManager.Instance.gameData.roomJoinNotice.position,
frameType = FrameDataType.createFish,
time = BeijingTimeManager.Instance.CurrentTimestampMs,
frameData = new FrameData_CreateFish
{
fishNumber = fish.fishNumber,
guid = Guid.NewGuid().ToString(),
moveLineId = pathId.ToString()
}
};
WebSocketSendList.SyncGameData(sgd);
}
// ================================================================
// 初始化 / 清理
// ================================================================
/// <summary>
/// 懒加载初始化:只执行一次,构建全部配置缓存字典。
/// </summary>
@@ -485,7 +291,6 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
fishDic[fish.fishNumber] = fish;
}
}
/// <summary>
/// 构建高频查询的字典缓存(fishArrayConfigs / fishTypeConfigs)。
/// </summary>
@@ -498,6 +303,44 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
.ToDictionary(f => f.fishNumber, f => f);
}
#endregion
#region 进入房间加载
/// <summary>进入房间:初始化生成系统并绑定游戏面板。</summary>
public void EnterRoom(GameTypeEnum gameType)
{
InitSpawnSystem(gameType);
BindCurrentGamePanel();
}
/// <summary>根据当前 GameType 绑定对应 UI 面板到 currGameType。</summary>
private void BindCurrentGamePanel()
{
switch (GameManager.Instance.gameData.currGameType)
{
case GameType.FLZY:
currGameType = UIManager.Instance.Get<GameMainPanel_FishBase>(UIPanel.MainGamePanelFLZY);
break;
case GameType.YYSC:
currGameType = UIManager.Instance.Get<GameMainPanel_YYSC>(UIPanel.MainGamePanelYYSC);
break;
case GameType.XJMH:
currGameType = UIManager.Instance.Get<GameMainPanel_FishBase>(UIPanel.MainGamePanelXJMH);
break;
case GameType.HHWK:
currGameType = UIManager.Instance.Get<GameMainPanel_FishBase>(UIPanel.MainGamePanelHHWK);
break;
default:
break;
}
}
/// <summary>
/// 进入房间时初始化生成系统:加载当前房间配置、分配 NativeArray。
/// </summary>
@@ -542,7 +385,7 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
}
// ---- 处理等级鱼列表(仅当前房间等级)----
int currRoomLevel = GameManager.Instance.gameData.currRoomData.roomLevel;
int currRoomLevel = GameManager.Instance.gameData.currRoomData.roomLevel;
if (config.roomFishLevelList != null)
{
foreach (var item in config.roomFishProbabilityList)
@@ -561,8 +404,10 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
break;
case FishTypeEnum.黄金鱼:
hjCreateData = item;
break;
case FishTypeEnum.特殊鱼:
tsbossCreateData = item;
break;
default:
break;
@@ -655,7 +500,252 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
yz_FishConfig_Line[yz.arrayNumber].Add(item);
yz_FishConfig_Line_List[yz_FishConfig_Line_Dic1[yz.arrayNumber]].Add(item);
}
#endregion
#region 创建鱼 广播部分
/// <summary>
/// 广播创建鱼
/// </summary>
/// <returns>此玩家是否可以创建鱼</returns>
private bool BroadCastCreateFish()
{
if (!isResources)
{
return false;
}
// 未初始化 或 未开启放鱼 → 跳过
if (spawnList == null || !fangzhu) return false;
float dt = Time.deltaTime;
// ---- 1. 用 Job System 并行更新所有鱼的计时器 ----
var job = new FishSpawnTimerJob
{
deltaTime = dt,
timers = timers,
frequencies = frequencies,
shouldSpawn = shouldSpawn,
};
job.Schedule().Complete();
// ---- 2. Boss 定时激活 ----
TickBossSpawn(dt);
// ---- 3. 鱼阵定时激活 ----
TickFishArraySpawn(dt);
TickFishArraySpawn(dt);
// ---- 4. 普通鱼定时批量激活 ----
TickNormalFishSpawn(dt);
// ---- 5. 遍历 shouldSpawn,向服务器发送生成请求 ----
ProcessSpawnRequests();
return true;
}
// ================================================================
// 定时 Tick 方法(由 Update 调用)
// ================================================================
/// <summary>每 25 秒随机激活一条 Boss 鱼。</summary>
private void TickBossSpawn(float dt)
{
bossTimer -= dt;
if (bossTimer > 0f) return;
bossCount = Random.Range(bossCreateData.countRange[0], bossCreateData.countRange[1]);
bossTimer = Random.Range(bossCreateData.timeRange[0], bossCreateData.timeRange[1]);
if (!fishTypeConfig.TryGetValue(FishTypeEnum.Boss鱼, out var bossList) || bossList.Count == 0)
return;
if (fishTypeConfig.TryGetValue(FishTypeEnum.特殊Boss, out var TSbossList) && TSbossList.Count > 0)
{
bossList.AddRange(TSbossList);
}
StartCoroutine(buchongfu(bossList, bossCount));
foreach (var item in bossList)
{
if (item.fishNumber == 11041.ToString())
{
item.isCreate = 2;
}
}
}
IEnumerator buchongfu(List<RoomFishDetailConfig> bossList, int count)
{
for (int j = 0; j < count; j++)
{
while (true)
{
int i = Random.Range(0, bossList.Count);
if (fishDatas_hashCodekey_Boss.Count > 0)
{
foreach (var item in fishDatas_hashCodekey_Boss)
{
if (bossList[i].fishNumber != item.Value.fishTypeID.ToString())
{
bossList[i].isCreate = 2;
yield break;
}
}
}
else
{
bossList[i].isCreate = 2;
yield break;
}
yield return null;
}
}
}
/// <summary>每 1~3 秒随机激活若干组鱼阵。</summary>
private void TickFishArraySpawn(float dt)
{
yzTimer -= dt;
if (yzTimer > 0f) return;
yzCount = Random.Range(yzCreateData.countRange[0], yzCreateData.countRange[1]);
yzTimer = Random.Range(yzCreateData.timeRange[0], yzCreateData.timeRange[1]);
int lineCount = yz_FishConfig_Line_List.Count;
if (lineCount == 0) return;
// 随机选 yzCount 个不重复的阵型下标
var selectedIndices = RandomUniqueNumbers(
Mathf.Min(yzCount, lineCount), 0, lineCount);
foreach (int idx in selectedIndices)
{
string arrayNumber = yz_FishConfig_Line_Dic[idx];
if (!yz_FishConfig_Line.TryGetValue(arrayNumber, out var lineList) || lineList.Count == 0)
continue;
// 随机选一条配置并标记为待生成
var chosen = lineList[Random.Range(0, lineList.Count)];
chosen.isCreate = 2;
// 同步更新 spawnDic 中的状态
if (spawnDic.TryGetValue(chosen.fishNumber, out var spawnEntry))
spawnEntry.isCreate = 2;
}
}
/// <summary>每 3 秒随机批量激活若干条普通鱼。</summary>
private void TickNormalFishSpawn(float dt)
{
ptTimer -= dt;
if (ptTimer > 0f) return;
ptCount = Random.Range(ptCreateData.countRange[0], ptCreateData.countRange[1]);
ptTimer = Random.Range(ptCreateData.timeRange[0], ptCreateData.timeRange[1]);
if (!fishTypeConfig.TryGetValue(FishTypeEnum.普通鱼, out var normalList) || normalList.Count == 0)
return;
if (fishTypeConfig.TryGetValue(FishTypeEnum.黄金鱼, out var normalList1) && normalList1.Count != 0)
{
normalList.AddRange(normalList1);
}
if (fishTypeConfig.TryGetValue(FishTypeEnum.特殊鱼, out var normalList2) && normalList2.Count != 0)
{
normalList.AddRange(normalList2);
}
// 随机选 ptCount 个不重复下标
var indices = RandomUniqueNumbers(
Mathf.Min(ptCount, normalList.Count), 0, normalList.Count);
foreach (int idx in indices)
normalList[idx].isCreate = 2;
}
/// <summary>
/// 遍历 shouldSpawn 数组,对本帧到期且被标记 isCreate==2 的鱼
/// 向服务器发送 WebSocket 生成同步包。
/// </summary>
private void ProcessSpawnRequests()
{
for (int i = 0; i < spawnList.Count; i++)
{
if (shouldSpawn[i] != 1) continue;
var fish = spawnList[i];
// isCreate==0:刚到期,重置为冷却中,等待外部计时器激活
if (fish.isCreate == 0)
{
fish.isCreate = 1; // 标记为"已处理但未激活"
continue;
}
// isCreate==2:已被激活,向服务器同步一次生成请求
if (fish.isCreate == 2)
{
SendCreateFishRequest(fish);
fish.isCreate = 0;
}
}
}
/// <summary>
/// 构建并发送生成鱼的 WebSocket 同步数据包。
/// </summary>
private void SendCreateFishRequest(RoomFishDetailConfig fish)
{
int pathId = 0;
// 普通鱼(type==1)才从 pathList 随机选路径;鱼阵(type==2)由后续逻辑决定
if (fish.type == 1)
{
var pathList = FishDatas[fish.fishNumber].pathList;
if (pathList != null && pathList.Count > 0)
pathId = pathList[Random.Range(0, pathList.Count)];
}
var sgd = new SyncGameData
{
sitPos = GameManager.Instance.gameData.roomJoinNotice.position,
frameType = FrameDataType.createFish,
time = BeijingTimeManager.Instance.CurrentTimestampMs,
frameData = new FrameData_CreateFish
{
fishNumber = fish.fishNumber,
guid = Guid.NewGuid().ToString(),
moveLineId = pathId.ToString()
}
};
WebSocketSendList.SyncGameData(sgd);
}
#endregion
#region
#endregion
#region 结束游戏退出房间
/// <summary>退出房间:关闭生成系统。</summary>
public void ExitRoom()
{
CloseSpawnSystem();
}
/// <summary>
/// 关闭生成系统:清理列表,销毁场景内所有鱼对象。
/// </summary>
@@ -696,49 +786,12 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
if (frequencies.IsCreated) frequencies.Dispose();
if (shouldSpawn.IsCreated) shouldSpawn.Dispose();
}
#endregion
// ================================================================
// 进退房间接口
// ================================================================
/// <summary>进入房间:初始化生成系统并绑定游戏面板。</summary>
public void EnterRoom(GameTypeEnum gameType)
{
InitSpawnSystem(gameType);
BindCurrentGamePanel();
}
/// <summary>退出房间:关闭生成系统。</summary>
public void ExitRoom()
{
CloseSpawnSystem();
}
/// <summary>根据当前 GameType 绑定对应 UI 面板到 currGameType。</summary>
private void BindCurrentGamePanel()
{
switch (GameManager.Instance.gameData.currGameType)
{
case GameType.FLZY:
currGameType = UIManager.Instance.Get<GameMainPanel_FishBase>(UIPanel.MainGamePanelFLZY);
break;
case GameType.YYSC:
currGameType = UIManager.Instance.Get<GameMainPanel_YYSC>(UIPanel.MainGamePanelYYSC);
break;
case GameType.XJMH:
currGameType = UIManager.Instance.Get<GameMainPanel_FishBase>(UIPanel.MainGamePanelXJMH);
break;
case GameType.HHWK:
currGameType = UIManager.Instance.Get<GameMainPanel_FishBase>(UIPanel.MainGamePanelHHWK);
break;
default:
break;
}
}
// ================================================================
// 网络回调:创建鱼
// ================================================================
///// <summary>
///// 收到服务器 SyncGameData 创鱼事件,反序列化并执行实例化。
@@ -841,6 +894,8 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
fishDatas_hashCodekey_Small[mc.guid] = mc;
break;
case 2: // Boss
case 4:
case 5:
fishDatas_hashCodekey_Boss[mc.guid] = mc;
break;
}
@@ -892,6 +947,7 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
case "702":
case "7007":
case "710": // 顺序阵:每条路径逐一延迟生成
case "704":
//int chosen710 = (prefix == "710")
// ? pathList[Random.Range(0, pathList.Count)]
// : -1;
@@ -973,8 +1029,7 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
for (int i = 0; i < count; i++)
{
float angle = (360f / count) * i;
var rotation = Quaternion.Euler(
prefab.transform.eulerAngles + Vector3.forward * angle);
var rotation = Quaternion.Euler(prefab.transform.eulerAngles + Vector3.forward * angle);
//var fish = Instantiate(prefab, pos, rotation, fishRoot);
var fish = Pool.Instance.Get(int.Parse(yz.fishNumber), pos, rotation, fishRoot);
@@ -1294,7 +1349,12 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
foreach (var sit in sitList)
{
if (sit.user != null && sit.user == killFish.userId)
{
sit.goldNum += killFish.gold;
sit.tMP_GoldNum.text = sit.goldNum.ToString();
}
}
}
AudioManager.Instance.PlayerFX(audioID);
@@ -1311,13 +1371,22 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
var award = Instantiate(
monster.effect_DieAward != null ? monster.effect_DieAward : dieFXPrefabAward,
currGameType.subPanelParent.parent);
try
{
award.GetComponent<RectTransform>().anchoredPosition =
CoordinateTransformation.WorldPos_ToCanvas(
monster.transform.position,
UIManager.Instance.uiRoot.GetComponent<Canvas>());
}
catch
{
award.transform.position = monster.transform.position;
award.GetComponent<RectTransform>().anchoredPosition =
CoordinateTransformation.WorldPos_ToCanvas(
monster.transform.position,
UIManager.Instance.uiRoot.GetComponent<Canvas>());
var coinScript = award.GetComponent<CoinScript>();
}
var coinScript = award.GetComponent<BJBase>();
foreach (var item in currGameType.list_Sits)
{
if (killFish.userId == item.user)