This commit is contained in:
2026-07-31 17:57:24 +08:00
parent d782290966
commit 14b8fa6085
3 changed files with 49 additions and 15 deletions
@@ -1373,6 +1373,12 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
private void FireBullet(SitPosData sit, float angle, bool isSanShe, bool isDouble, bool isLock, List<string> bullitIDs,
List<string> fireTargetMonsterIDs = null, List<long> bulletGolds = null)
{
// ⭐ 防御:sit 或 bullitIDs 为空时直接返回,避免空引用
if (sit == null || bullitIDs == null || bullitIDs.Count == 0)
{
Debug.LogWarning("[FireBullet] sit 或 bullitIDs 为空,跳过本次开火");
return;
}
Vector2 startPos = sit.GetBulletStartPos();
// ⭐ 按索引取该发子弹的服务端权威扣费金额(bullets[i].gold),没有则回退到0(ConsumeGold内部用consumeGoldNum)
@@ -1401,7 +1407,9 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
{
if (CreateFishManager.Instance.fishDatas_hashCodekey.TryGetValue(fireTargetMonsterIDs[i], out var m)
&& m != null && m.gameObject.activeInHierarchy
&& IsFishPathLockable(m))
// ⭐ 手动锁定的主目标(i==0 且是本地玩家主锁)不受路径进度限制
&& ((i == 0 && sit == currSitData && m == currSitData.monCotl_Lock && currSitData.isManualLock)
|| IsFishPathLockable(m)))
{
targetMonster = m;
targetHitPos = ResolveLockTransform(m);
@@ -1425,9 +1433,11 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
}
else if (isSanShe)
{
CreateBullet(sit, startPos, angle - 20, isDouble, isLock, bullitIDs[0], null, null, GetBulletGold(0));
CreateBullet(sit, startPos, angle, isDouble, isLock, bullitIDs[1], null, null, GetBulletGold(1));
CreateBullet(sit, startPos, angle + 20, isDouble, isLock, bullitIDs[2], null, null, GetBulletGold(2));
// ⭐ 安全取值:bullitIDs 不足3个时复用最后一个,避免越界
string SafeBid(int i) => i < bullitIDs.Count ? bullitIDs[i] : bullitIDs[bullitIDs.Count - 1];
CreateBullet(sit, startPos, angle - 20, isDouble, isLock, SafeBid(0), null, null, GetBulletGold(0));
CreateBullet(sit, startPos, angle, isDouble, isLock, SafeBid(1), null, null, GetBulletGold(1));
CreateBullet(sit, startPos, angle + 20, isDouble, isLock, SafeBid(2), null, null, GetBulletGold(2));
}
else
{
@@ -1624,9 +1634,9 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
#region 路径进度过滤(锁定范围控制)
/// <summary>bot/玩家锁定时,鱼路径进度下限:小于此值表示鱼刚出生,不锁定</summary>
private const float BotLockPathMin = 0.2f;
private const float BotLockPathMin = 0.1f;
/// <summary>bot/玩家锁定时,鱼路径进度上限:大于此值表示鱼即将离场,不锁定</summary>
private const float BotLockPathMax = 0.8f;
private const float BotLockPathMax = 0.9f;
/// <summary>
/// 计算鱼在路径上的进度 [0, 1]。
@@ -1647,7 +1657,8 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
/// <summary>
/// 判断鱼的路径进度是否在可锁定范围内 [BotLockPathMin, BotLockPathMax]
/// 刚出生(< 0.2)或即将离场(> 0.8)的鱼不能锁定,避免锁定后立即丢失目标
/// 刚出生(< 0.1)或即将离场(> 0.9)的鱼不能锁定,避免锁定后立即丢失目标
/// ⭐ 注意:本函数仅用于自动锁定/bot/三发查找;玩家手动锁定不调用此函数
/// </summary>
private bool IsFishPathLockable(MonsterContral m)
{
@@ -1684,10 +1695,11 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
if (CreateFishManager.Instance == null) return result;
// ① 主锁目标排第一(打哪锁哪)—— 必须也满足路径可锁定,否则三发列表会被它污染
// ① 主锁目标排第一(打哪锁哪)
// ⭐ 手动锁定:只看鱼是否还活着;自动锁定:还要满足路径可锁定
if (currSitData.isLock && currSitData.monCotl_Lock != null &&
currSitData.monCotl_Lock.gameObject.activeInHierarchy &&
IsFishPathLockable(currSitData.monCotl_Lock))
(currSitData.isManualLock || IsFishPathLockable(currSitData.monCotl_Lock)))
{
Transform pos = currSitData.monCotl_Lock_Position != null && currSitData.monCotl_Lock_Position.gameObject.activeInHierarchy
? currSitData.monCotl_Lock_Position
@@ -1820,6 +1832,8 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
Transform lockTr = ResolveLockTransform(monster, out colliderIndex, true);
// ⭐ lockPoint 和 colliderList 全部未激活 → 不锁定这条鱼
if (lockTr == null) return;
// ⭐ 标记为手动锁定:不受路径进度(0.1~0.9)限制,鱼离场前一直锁定
currSitData.isManualLock = true;
currSitData.SetLockTarget(monster, lockTr);
SyncLock(new List<string> { monster?.guid }, colliderIndex);
@@ -1902,11 +1916,11 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
var monster = currSitData.monCotl_Lock;
// ⭐ 目标无效判定:被回收/销毁 OR 路径离场(progress > 0.8)
// 离场的鱼仍 active,但不应该继续锁定
// ⭐ 目标无效判定:被回收/销毁
// 路径进度检查仅对自动锁定生效;手动锁定不检查(玩家自己锁的鱼离场前一直跟)
bool mainInvalid = monster == null
|| !monster.gameObject.activeInHierarchy
|| !IsFishPathLockable(monster);
|| (!currSitData.isManualLock && !IsFishPathLockable(monster));
if (mainInvalid)
{
@@ -1955,11 +1969,13 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
// 激活后,当锁定的鱼死亡,自动转换到下一个目标
if (!_autoLockActivated) return;
// 已经有锁定目标并且还活着且未离场,就不重复找
// 已经有锁定目标并且还活着,就不重复找
// ⭐ 手动锁定:只看鱼是否还活着,不检查路径进度(玩家自己锁的鱼离场前一直跟)
// 自动锁定:还要检查路径进度(超出 0.1~0.9 范围视为失效,换下一条)
if (currSitData.isLock &&
currSitData.monCotl_Lock != null &&
currSitData.monCotl_Lock.gameObject.activeInHierarchy &&
IsFishPathLockable(currSitData.monCotl_Lock))
(currSitData.isManualLock || IsFishPathLockable(currSitData.monCotl_Lock)))
{
return;
}
@@ -1973,6 +1989,8 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
Transform lockTr = ResolveLockTransform(target, out colliderIndex);
// ⭐ lockPoint 和 colliderList 全部未激活(出场效果中) → 不锁定,等下一帧再找
if (lockTr == null) return;
// ⭐ 标记为自动锁定:受路径进度(0.1~0.9)限制
currSitData.isManualLock = false;
currSitData.SetLockTarget(target, lockTr);
SyncLock(new List<string> { target?.guid }, colliderIndex);
@@ -2348,6 +2366,12 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
}
var data = FrameDataParser.Parse<FrameData_FireBullet>(sync.extra.frameData);
// ⭐ 边界检查:防止 sitPos 越界导致 IndexOutOfRangeException
if (sync.extra.sitPos < 0 || sync.extra.sitPos >= list_Sits.Count)
{
Debug.LogWarning($"[SyncGameData_FireBullit] sitPos 越界: {sync.extra.sitPos}");
return;
}
var targetSit = list_Sits[sync.extra.sitPos];
FireBullet(targetSit, data.angle, data.isSanShe, data.twoRTruuect, data.isSuoDing, sync.bulletIds, data.monsterIDs, bulletGolds);
}