From 43b29df7c03706937c299e6ec80575e2048125d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=A3=AE2003?= <2384017988@qq.com> Date: Sun, 5 Jul 2026 17:39:30 +0800 Subject: [PATCH] 1 --- .../Scripts/Manager/CreateFishManager.cs | 22 ++++- Assets/MyGame/Scripts/Manager/GameManager.cs | 3 + .../Scripts/Net/WebResponses/BotConfig.cs | 24 ++--- Assets/MyGame/aa/Game/FLZY/BOSS/BJEndUI.cs | 2 +- .../MyGame/aa/Game/FLZY/BOSS/BJEventBase.cs | 2 +- .../aa/Game/FLZY/BOSS/FLXJ/FLXJEvent.cs | 2 +- .../aa/Game/FLZY/BOSS/GSL/GSLDieEvent.cs | 2 +- .../aa/UI/Game/GameMainPanel_FishBase.cs | 92 ++++++++++++++++--- 8 files changed, 115 insertions(+), 34 deletions(-) diff --git a/Assets/MyGame/Scripts/Manager/CreateFishManager.cs b/Assets/MyGame/Scripts/Manager/CreateFishManager.cs index b9abdaa92..15a50159d 100644 --- a/Assets/MyGame/Scripts/Manager/CreateFishManager.cs +++ b/Assets/MyGame/Scripts/Manager/CreateFishManager.cs @@ -153,6 +153,9 @@ public class CreateFishManager : MonoSingleton private List bossRecentList = new List(); // 最近出现过的Boss(cool down) private int bossRecentMax = 3; // N次内不重复出现 + /// Boss鱼路线奇偶切换标记:true=下次选奇数路线,false=下次选偶数路线 + private bool bossNextPathOdd = true; + private RoomFishProbabilityConfig yzCreateData; // 鱼阵创建数据 private float yzTimer = 999f; // 鱼阵刷新倒计时(秒) private int yzCount; // 本轮同时激活阵型数量 @@ -996,9 +999,24 @@ public class CreateFishManager : MonoSingleton // 普通鱼(type==1)才从 pathList 随机选路径;鱼阵(type==2)由后续逻辑决定 if (fish.type == 1) { - var pathList = FishDatas[fish.fishNumber].pathList; + var ft = FishDatas[fish.fishNumber]; + var pathList = ft.pathList; if (pathList != null && pathList.Count > 0) - pathId = pathList[Random.Range(0, pathList.Count)]; + { + // Boss鱼(2)/特殊Boss(5):路线奇偶交替,避免同奇/同偶路径相互覆盖 + if (ft != null && (ft.fishType == 2 || ft.fishType == 5)) + { + var filtered = pathList.Where(p => (p % 2 != 0) == bossNextPathOdd).ToList(); + if (filtered.Count == 0) + filtered = pathList; + pathId = filtered[Random.Range(0, filtered.Count)]; + bossNextPathOdd = !bossNextPathOdd; + } + else + { + pathId = pathList[Random.Range(0, pathList.Count)]; + } + } } else { diff --git a/Assets/MyGame/Scripts/Manager/GameManager.cs b/Assets/MyGame/Scripts/Manager/GameManager.cs index 7fca80f26..bb9d948eb 100644 --- a/Assets/MyGame/Scripts/Manager/GameManager.cs +++ b/Assets/MyGame/Scripts/Manager/GameManager.cs @@ -185,6 +185,9 @@ public class GameManager : MonoSingleton } protected override void Awake() { + // ⭐ botConfig 默认初始化,避免 null 导致技能系统不跑 + if (botConfig == null) botConfig = new BotConfig(); + // ⭐ 游戏启动时加载已保存的画质和帧率设置 int quality = PlayerPrefs.GetInt("GraphicsQuality", 1); QualitySettings.SetQualityLevel(quality, true); diff --git a/Assets/MyGame/Scripts/Net/WebResponses/BotConfig.cs b/Assets/MyGame/Scripts/Net/WebResponses/BotConfig.cs index 50e4efed0..01e0599c7 100644 --- a/Assets/MyGame/Scripts/Net/WebResponses/BotConfig.cs +++ b/Assets/MyGame/Scripts/Net/WebResponses/BotConfig.cs @@ -4,7 +4,6 @@ using UnityEngine; /// /// 机器人AI配置 — 本地测试用 Inspector 调节,后续从后端 GameConfig / RoomChangeResponse 下发 /// -[Serializable] public class BotConfig { [Header("全局")] @@ -21,49 +20,48 @@ public class BotConfig public float stateRefreshInterval; [Header("技能配置")] - public BotSkillConfig skills; + public BotSkillConfig skills = new BotSkillConfig(); [Header("active 状态参数")] - public BotBehaviorConfig activeBehavior; + public BotBehaviorConfig activeBehavior = new BotBehaviorConfig(); [Header("idle 状态参数")] - public BotBehaviorConfig idleBehavior; + public BotBehaviorConfig idleBehavior = new BotBehaviorConfig(); [Header("aggressive 状态参数")] - public BotBehaviorConfig aggressiveBehavior; + public BotBehaviorConfig aggressiveBehavior = new BotBehaviorConfig(); } /// /// 技能概率配置 — 每种技能独立随机,可以同时开多种 /// -[Serializable] public class BotSkillConfig { [Header("刷新")] [Tooltip("每隔多少秒重新掷骰子决定技能组合")] - public float skillRefreshInterval = 8f; + public float skillRefreshInterval = 1f; [Space] [Header("锁定 - 自动瞄准最近鱼")] - [Range(0f, 1f)] public float lockProb = 0.6f; + [Range(0f, 1f)] public float lockProb = 1f; public float lockMinTime = 5f; public float lockMaxTime = 20f; [Space] [Header("狂暴 - 开火速度翻倍")] - [Range(0f, 1f)] public float frenzyProb = 0.55f; + [Range(0f, 1f)] public float frenzyProb = 1f; public float frenzyMinTime = 3f; public float frenzyMaxTime = 8f; [Space] [Header("三发散弹 - 一次3发")] - [Range(0f, 1f)] public float tripleProb = 0.55f; + [Range(0f, 1f)] public float tripleProb = 1f; public float tripleMinTime = 4f; public float tripleMaxTime = 12f; [Space] [Header("双倍炮 - 消耗翻倍")] - [Range(0f, 1f)] public float doubleProb = 0.5f; + [Range(0f, 1f)] public float doubleProb = 1f; public float doubleMinTime = 3f; public float doubleMaxTime = 6f; } @@ -71,7 +69,6 @@ public class BotSkillConfig /// /// 行为参数 — 每个 aiState 一组 /// -[Serializable] public class BotBehaviorConfig { [Header("开火")] @@ -84,7 +81,7 @@ public class BotBehaviorConfig [Header("旋转")] [Tooltip("炮台旋转速度(度/秒)")] - public float rotateSpeed = 40f; + public float rotateSpeed = 80f; [Header("目标")] [Tooltip("锁定保持时间下限(秒)")] @@ -104,7 +101,6 @@ public class BotBehaviorConfig /// /// 每个 bot 座位的技能运行时状态 /// -[Serializable] public class BotSkillRuntime { public bool lockActive; diff --git a/Assets/MyGame/aa/Game/FLZY/BOSS/BJEndUI.cs b/Assets/MyGame/aa/Game/FLZY/BOSS/BJEndUI.cs index fab8a151d..00846dd7e 100644 --- a/Assets/MyGame/aa/Game/FLZY/BOSS/BJEndUI.cs +++ b/Assets/MyGame/aa/Game/FLZY/BOSS/BJEndUI.cs @@ -18,7 +18,7 @@ public class BJEndUI : MonoBehaviour public void Init(int beishu, int score) { - tMP_beishu.text = beishu.ToString(); + tMP_beishu.text = ""+ beishu.ToString(); if (useScoreAnim) StartCoroutine(ScoreAnim(score)); diff --git a/Assets/MyGame/aa/Game/FLZY/BOSS/BJEventBase.cs b/Assets/MyGame/aa/Game/FLZY/BOSS/BJEventBase.cs index 7fdef1929..2ad1465c4 100644 --- a/Assets/MyGame/aa/Game/FLZY/BOSS/BJEventBase.cs +++ b/Assets/MyGame/aa/Game/FLZY/BOSS/BJEventBase.cs @@ -388,7 +388,7 @@ public class BJEventBase : MonoBehaviour } var endUI = Instantiate(bjEndUI, uiPos, Quaternion.identity, UIManager.Instance.uiRoot); - endUI.Init(paoBei, maxScore); + endUI.Init(bJbeishu, maxScore); } // 删除分数面板 diff --git a/Assets/MyGame/aa/Game/FLZY/BOSS/FLXJ/FLXJEvent.cs b/Assets/MyGame/aa/Game/FLZY/BOSS/FLXJ/FLXJEvent.cs index cfa1ebae7..9cde0a667 100644 --- a/Assets/MyGame/aa/Game/FLZY/BOSS/FLXJ/FLXJEvent.cs +++ b/Assets/MyGame/aa/Game/FLZY/BOSS/FLXJ/FLXJEvent.cs @@ -129,7 +129,7 @@ public class FLXJEvent : BJEventBase { var uiPos = GetSeatPosition() + Vector3.up * bjEndUIOffsetY; var endUI = Instantiate(bjEndUI, uiPos, Quaternion.identity, UIManager.Instance.uiRoot); - endUI.Init(paoBei, maxScore); + endUI.Init(bJbeishu, maxScore); bjEndUI = null; // 防止 OnScoreEnd 重复创建 } OnScoreEnd(); diff --git a/Assets/MyGame/aa/Game/FLZY/BOSS/GSL/GSLDieEvent.cs b/Assets/MyGame/aa/Game/FLZY/BOSS/GSL/GSLDieEvent.cs index c8e1e18c9..e6f94a3c2 100644 --- a/Assets/MyGame/aa/Game/FLZY/BOSS/GSL/GSLDieEvent.cs +++ b/Assets/MyGame/aa/Game/FLZY/BOSS/GSL/GSLDieEvent.cs @@ -92,7 +92,7 @@ public class GSLDieEvent :BJEventBase { var uiPos = GetSeatPosition() + Vector3.up * bjEndUIOffsetY; var endUI = Instantiate(bjEndUI, uiPos, Quaternion.identity, UIManager.Instance.uiRoot); - endUI.Init(paoBei, maxScore); + endUI.Init(bJbeishu, maxScore); bjEndUI = null; // 防止 OnScoreEnd 重复创建 } OnScoreEnd(); diff --git a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs index 42c273080..fca4bd9ca 100644 --- a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs +++ b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs @@ -151,12 +151,16 @@ public class GameMainPanel_FishBase : GameMainPanel_Base [Header("攻击参数")] public float attackTime = 0.5f; [Header("人机参数")] - public float botRotateSpeed = 40f; // 兜底旋转速度(BotConfig 为空时用) + public float botRotateSpeed = 80f; // 兜底旋转速度(BotConfig 为空时用) float clickTime = 0; private Dictionary botFireTimer = new Dictionary(); private Dictionary botLastAngle = new Dictionary(); // bot 技能运行时 private Dictionary botSkills = new Dictionary(); + // bot 目标记忆 + private Dictionary botTargetGuid = new Dictionary(); + // bot 状态计时:开火后持续 Attack 动画,空闲 0.3s 切回 Idle + private Dictionary botIdleTimer = new Dictionary(); public GameObject bullet_Test; public GameObject bulletParent; float changeTurretTime = 0f; @@ -1926,15 +1930,35 @@ public class GameMainPanel_FishBase : GameMainPanel_Base RefreshBotSkills(sit, cfg.skills); var skill = botSkills.ContainsKey(sit.posID) ? botSkills[sit.posID] : null; - // ====== 找目标:Boss > 黄金鱼 > 特殊鱼 > 普通鱼 ====== - MonsterContral target = SelectBotTarget(sit, fishList, turretPos); + // ====== 目标选择(记住当前目标,死了/飞走了才换) ====== + MonsterContral target = GetOrFindBotTarget(sit, fishList, turretPos, skill); - if (target != null) + if (target == null) continue; + + // ====== 锁定技能:走真实锁定系统(显示锁定图标) ====== + if (skill != null && skill.lockActive) { - // 旋转朝向目标(持续旋转,不管发不发炮) - if (skill == null || !skill.lockActive) - RotateBotToTarget(sit, target.transform.position, rotateSpeed); + if (sit.monCotl_Lock != target) + { + sit.isLock = true; + sit.monCotl_Lock = target; + sit.monCotl_Lock_Position = target.colliderList != null && target.colliderList.Count > 0 + ? target.colliderList[0].transform : target.transform; + if (sit.lockFX != null) sit.lockFX.SetActive(true); + } } + else + { + if (sit.isLock) + { + sit.isLock = false; + sit.monCotl_Lock = null; + if (sit.lockFX != null) sit.lockFX.SetActive(false); + } + } + + // ====== 旋转(始终运行,Lerp自然减速) ====== + RotateBotToTarget(sit, target.transform.position, rotateSpeed); // ====== 持续射击 ====== if (!botFireTimer.ContainsKey(sit.posID)) @@ -1951,6 +1975,12 @@ public class GameMainPanel_FishBase : GameMainPanel_Base { botFireTimer[sit.posID] = 0f; + // 攻击动画 + sit.ChangeState(TurretState.Attack); + if (!botIdleTimer.ContainsKey(sit.posID)) + botIdleTimer[sit.posID] = 0f; + botIdleTimer[sit.posID] = 0f; + float angle = sit.currentAngle; botLastAngle[sit.user] = angle; @@ -1967,14 +1997,50 @@ public class GameMainPanel_FishBase : GameMainPanel_Base sit.user, gold, count); SyncFire_ForBot(sit, angle, gold, count); } + + // 空闲超时切回 Idle 动画 + if (!botIdleTimer.ContainsKey(sit.posID)) + botIdleTimer[sit.posID] = 0f; + botIdleTimer[sit.posID] += Time.deltaTime; + if (botIdleTimer[sit.posID] > 0.3f) + { + sit.ChangeState(TurretState.Idle); + botIdleTimer[sit.posID] = 0f; + } } } + /// + /// 获取或寻找目标:优先用记忆的目标(还在前方就沿用),死了/不在前方了再重新找 + /// + private MonsterContral GetOrFindBotTarget(SitPosData sit, CreateFishManager fishList, Vector3 turretPos, BotSkillRuntime skill) + { + // 1. 检查记忆目标是否还有效 + if (botTargetGuid.TryGetValue(sit.posID, out string guid)) + { + if (fishList.fishDatas_hashCodekey.TryGetValue(guid, out var m) + && m != null && m.gameObject.activeInHierarchy) + { + Vector3 fp = m.transform.position; + bool inFront = sit.IsFlipped ? fp.y < turretPos.y : fp.y > turretPos.y; + if (inFront) return m; + } + // 目标无效 → 清除记忆 + botTargetGuid.Remove(sit.posID); + } + + // 2. 重新找目标(Boss > 黄金鱼 > 特殊鱼 > 普通鱼,同类型打最近) + MonsterContral target = SelectBestTarget(sit, fishList, turretPos); + if (target != null) + botTargetGuid[sit.posID] = target.guid; + return target; + } + /// /// 按优先级选目标:特殊Boss(5) > Boss(2) > 黄金鱼(3) > 特殊鱼(4) > 普通鱼(1) /// 同一优先级内选最近的,只选炮台前方的鱼 /// - private MonsterContral SelectBotTarget(SitPosData sit, CreateFishManager fishList, Vector3 turretPos) + private MonsterContral SelectBestTarget(SitPosData sit, CreateFishManager fishList, Vector3 turretPos) { MonsterContral best = null; float bestDist = float.MaxValue; @@ -1985,14 +2051,11 @@ public class GameMainPanel_FishBase : GameMainPanel_Base var m = kv.Value; if (m == null || !m.gameObject.activeInHierarchy) continue; - // 只选炮台前方的鱼 Vector3 fishPos = m.transform.position; if (sit.IsFlipped && fishPos.y >= turretPos.y) continue; if (!sit.IsFlipped && fishPos.y <= turretPos.y) continue; float d = (fishPos - turretPos).sqrMagnitude; - - // 优先级: 特殊Boss=5→0, Boss=2→1, 黄金鱼=3→2, 特殊鱼=4→3, 普通鱼=1→4 int pri = GetFishPriority((int)m.fishenum); if (pri < bestPri || (pri == bestPri && d < bestDist)) @@ -2084,11 +2147,12 @@ public class GameMainPanel_FishBase : GameMainPanel_Base if (sit.IsFlipped) angle = (angle + 180f) % 360f; - // 平滑旋转:像真人一样缓慢转动,避免瞬间闪现 + // Lerp 旋转:自然减速,速度由 rotateSpeed 控制 float current = sit.currentAngle; float speed = rotateSpeed > 0f ? rotateSpeed : botRotateSpeed; - float maxDelta = speed * Time.deltaTime; - float smoothed = Mathf.MoveTowardsAngle(current, angle, maxDelta); + // t 越大旋转越快,clamp 防过冲 + float t = Mathf.Min(speed * 0.15f * Time.deltaTime, 1f); + float smoothed = Mathf.LerpAngle(current, angle, t); sit.SetRotation(smoothed); }