diff --git a/Assets/MyGame/Scenes/HHWK.unity b/Assets/MyGame/Scenes/HHWK.unity index 988f400f1..49c078862 100644 --- a/Assets/MyGame/Scenes/HHWK.unity +++ b/Assets/MyGame/Scenes/HHWK.unity @@ -131,6 +131,7 @@ GameObject: serializedVersion: 6 m_Component: - component: {fileID: 814180751} + - component: {fileID: 814180752} m_Layer: 0 m_Name: BG m_TagString: Untagged @@ -154,6 +155,18 @@ Transform: - {fileID: 1987591213} m_Father: {fileID: 0} m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!210 &814180752 +SortingGroup: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 814180750} + m_Enabled: 1 + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: -9000 + m_SortAtRoot: 0 --- !u!1 &1610434798 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/MyGame/Scripts/Characters/Monster/MonsterMoveLine.cs b/Assets/MyGame/Scripts/Characters/Monster/MonsterMoveLine.cs index ac4c30097..b97ddda4f 100644 --- a/Assets/MyGame/Scripts/Characters/Monster/MonsterMoveLine.cs +++ b/Assets/MyGame/Scripts/Characters/Monster/MonsterMoveLine.cs @@ -9,12 +9,13 @@ using UnityEngine.ResourceManagement.AsyncOperations; using Unity.Collections; using Unity.Jobs; using Unity.Burst; - +using System; +[Serializable] public class MonsterMoveLine { public static Dictionary dic_BezierCurveDatas = new Dictionary(); public static List curves = new List(); - + [Serializable] public class BezierCurveData { public string name; diff --git a/Assets/MyGame/Scripts/Manager/CreateFishManager.cs b/Assets/MyGame/Scripts/Manager/CreateFishManager.cs index b2b551245..b9abdaa92 100644 --- a/Assets/MyGame/Scripts/Manager/CreateFishManager.cs +++ b/Assets/MyGame/Scripts/Manager/CreateFishManager.cs @@ -618,17 +618,17 @@ public class CreateFishManager : MonoSingleton //bossTimer = 3f; if (!fishTypeConfig.TryGetValue(FishTypeEnum.Boss鱼, out var bossList) || bossList.Count == 0) return; - //foreach (var item in bossList) - //{ - // if (item.fishNumber == "13037") - // item.isCreate = 2; + foreach (var item in bossList) + { + if (item.fishNumber == "13037") + item.isCreate = 2; - // // if (item.fishNumber == "11027") - // // item.isCreate = 2; - // // if (item.fishNumber == "11030") - // // item.isCreate = 2; + if (item.fishNumber == "11035") + item.isCreate = 2; + // if (item.fishNumber == "11030") + // item.isCreate = 2; - //} + } StartCoroutine(buchongfu(bossList, bossCount, fishDatas_hashCodekey_Boss, bossRecentList, bossRecentMax)); diff --git a/Assets/MyGame/Scripts/Manager/GameManager.cs b/Assets/MyGame/Scripts/Manager/GameManager.cs index 889b2685a..7fca80f26 100644 --- a/Assets/MyGame/Scripts/Manager/GameManager.cs +++ b/Assets/MyGame/Scripts/Manager/GameManager.cs @@ -16,7 +16,8 @@ using UnityEngine.Video; public class GameManager : MonoSingleton { [Header("人机")] - public bool enableBot = true; // 人机开关 + public bool enableBot = true; // 人机总开关 + public BotConfig botConfig; // 人机AI详细配置(Inspector可调,本地测试用) public GameConfig gameConfig; public Dictionary dic_fishTypeConfigs = new Dictionary(); diff --git a/Assets/MyGame/Scripts/Net/WebResponses/BotConfig.cs b/Assets/MyGame/Scripts/Net/WebResponses/BotConfig.cs new file mode 100644 index 000000000..50e4efed0 --- /dev/null +++ b/Assets/MyGame/Scripts/Net/WebResponses/BotConfig.cs @@ -0,0 +1,125 @@ +using System; +using UnityEngine; + +/// +/// 机器人AI配置 — 本地测试用 Inspector 调节,后续从后端 GameConfig / RoomChangeResponse 下发 +/// +[Serializable] +public class BotConfig +{ + [Header("全局")] + [Tooltip("机器人总开关")] + public bool enabled = true; + + [Tooltip("AI状态: active=正常 | idle=待机 | aggressive=激进")] + public string aiState = "active"; + + [Tooltip("爆率因子: 1.0=正常, >1容易杀, <1难杀")] + public float luckFactor = 1f; + + [Tooltip("状态刷新间隔(秒), 0=不自动刷新")] + public float stateRefreshInterval; + + [Header("技能配置")] + public BotSkillConfig skills; + + [Header("active 状态参数")] + public BotBehaviorConfig activeBehavior; + + [Header("idle 状态参数")] + public BotBehaviorConfig idleBehavior; + + [Header("aggressive 状态参数")] + public BotBehaviorConfig aggressiveBehavior; +} + +/// +/// 技能概率配置 — 每种技能独立随机,可以同时开多种 +/// +[Serializable] +public class BotSkillConfig +{ + [Header("刷新")] + [Tooltip("每隔多少秒重新掷骰子决定技能组合")] + public float skillRefreshInterval = 8f; + + [Space] + [Header("锁定 - 自动瞄准最近鱼")] + [Range(0f, 1f)] public float lockProb = 0.6f; + public float lockMinTime = 5f; + public float lockMaxTime = 20f; + + [Space] + [Header("狂暴 - 开火速度翻倍")] + [Range(0f, 1f)] public float frenzyProb = 0.55f; + public float frenzyMinTime = 3f; + public float frenzyMaxTime = 8f; + + [Space] + [Header("三发散弹 - 一次3发")] + [Range(0f, 1f)] public float tripleProb = 0.55f; + public float tripleMinTime = 4f; + public float tripleMaxTime = 12f; + + [Space] + [Header("双倍炮 - 消耗翻倍")] + [Range(0f, 1f)] public float doubleProb = 0.5f; + public float doubleMinTime = 3f; + public float doubleMaxTime = 6f; +} + +/// +/// 行为参数 — 每个 aiState 一组 +/// +[Serializable] +public class BotBehaviorConfig +{ + [Header("开火")] + [Tooltip("开火间隔下限(秒)")] + public float fireIntervalMin = 0.3f; + [Tooltip("开火间隔上限(秒)")] + public float fireIntervalMax = 1.2f; + [Tooltip("开火概率(0~1): 每个 interval 触发开火的概率,0.9=经常开火偶尔停顿")] + [Range(0f, 1f)] public float fireProb = 0.9f; + + [Header("旋转")] + [Tooltip("炮台旋转速度(度/秒)")] + public float rotateSpeed = 40f; + + [Header("目标")] + [Tooltip("锁定保持时间下限(秒)")] + public float targetHoldTimeMin = 2f; + [Tooltip("锁定保持时间上限(秒)")] + public float targetHoldTimeMax = 5f; + [Tooltip("超时后切换目标的概率(0~1)")] + [Range(0f, 1f)] public float targetSwitchChance = 0.7f; + [Tooltip("优先高分鱼: 0=纯距离, 1=纯分数")] + [Range(0f, 1f)] public float targetPreferHighScore; + [Tooltip("允许打Boss")] + public bool canTargetBoss = true; + [Tooltip("允许打特殊鱼")] + public bool canTargetSpecial = true; +} + +/// +/// 每个 bot 座位的技能运行时状态 +/// +[Serializable] +public class BotSkillRuntime +{ + public bool lockActive; + public float lockEndTime; + + public bool frenzyActive; + public float frenzyEndTime; + + public bool tripleActive; + public float tripleEndTime; + + public bool doubleActive; + public float doubleEndTime; + + public float nextRefreshTime; + + public bool HasAnySkill => lockActive || frenzyActive || tripleActive || doubleActive; +} diff --git a/Assets/MyGame/Scripts/Net/WebResponses/BotConfig.cs.meta b/Assets/MyGame/Scripts/Net/WebResponses/BotConfig.cs.meta new file mode 100644 index 000000000..35a8c914d --- /dev/null +++ b/Assets/MyGame/Scripts/Net/WebResponses/BotConfig.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ce119537e3174d046b4fdc0cb3078623 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/MyGame/Scripts/Net/WebSocketManager.cs b/Assets/MyGame/Scripts/Net/WebSocketManager.cs index 8e5a9027d..32b32409f 100644 --- a/Assets/MyGame/Scripts/Net/WebSocketManager.cs +++ b/Assets/MyGame/Scripts/Net/WebSocketManager.cs @@ -65,7 +65,7 @@ namespace Assets.MyGame.Scripts.Net case SocketType.login: break; case SocketType.room: - //WebSocketSendList.JoinRoom("11109", GameManager.Instance.user.id, 1); + WebSocketSendList.JoinRoom("11109", GameManager.Instance.user.id, 1); break; case SocketType.game: break; @@ -77,7 +77,8 @@ namespace Assets.MyGame.Scripts.Net default: break; } - + if (action != null) + action?.Invoke(); return exist; } } diff --git a/Assets/MyGame/aa/Game/FLZY/BOSS/QL/Game173_Effect_LDJT.prefab b/Assets/MyGame/aa/Game/FLZY/BOSS/QL/Game173_Effect_LDJT.prefab index 1ec718f90..5fc0f31ca 100644 --- a/Assets/MyGame/aa/Game/FLZY/BOSS/QL/Game173_Effect_LDJT.prefab +++ b/Assets/MyGame/aa/Game/FLZY/BOSS/QL/Game173_Effect_LDJT.prefab @@ -132341,7 +132341,7 @@ Animator: m_Controller: {fileID: 9100000, guid: 3900815b8fd78d0499f86a7585d2b0b0, type: 2} m_CullingMode: 0 m_UpdateMode: 0 - m_ApplyRootMotion: 0 + m_ApplyRootMotion: 1 m_LinearVelocityBlending: 0 m_StabilizeFeet: 0 m_WarningMessage: @@ -132361,11 +132361,32 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: e4f5dd9a6b3cca14b960a02a2a8ab3a4, type: 3} m_Name: m_EditorClassIdentifier: + bjEndUI: {fileID: 0} + useScorePanel: 1 tMP_Score: {fileID: 6528776512666913368} + scorePanelPrefab: {fileID: 0} currScore: 0 maxScore: 0 + scoreCount: 0 posID: 0 paoBei: 0 + fishScore: 0 + bJbeishu: 0 + showDelay: 3 + moveDuration: 0.5 + moveEase: 6 + startOffset: {x: 0, y: 0, z: -100} + bjEndUIOffsetY: 150 + coinFlyDuration: 0.5 + coinArrivalInterval: 0.1 + isSelf: 0 + autoFinishOnScoreFull: 1 + totalBJCount: 0 + currBJCount: 0 + isEffEnd: 0 + isScoreStart: 0 + isScoreEnd: 0 + isGoldEffectStart: 0 skeletonGraphic: {fileID: 7973729193475036454} tMP_longzhu1: {fileID: 2498335782564118400} tMP_longzhu2: {fileID: 5579055612232908101} diff --git a/Assets/MyGame/aa/Game/FLZY/BOSS/YGLG/FLZY_Boss_YGLG.cs b/Assets/MyGame/aa/Game/FLZY/BOSS/YGLG/FLZY_Boss_YGLG.cs index 53631dafb..bed97c968 100644 --- a/Assets/MyGame/aa/Game/FLZY/BOSS/YGLG/FLZY_Boss_YGLG.cs +++ b/Assets/MyGame/aa/Game/FLZY/BOSS/YGLG/FLZY_Boss_YGLG.cs @@ -35,7 +35,7 @@ public class FLZY_Boss_YGLG : MonsterControl_BossBase public override void Init(string pathId, float Time, bool isyuzhen = false, string yzID = "") { base.Init(pathId, Time, isyuzhen, yzID); - transform.position = Vector3.zero; + //transform.position = Vector3.zero; } public override void OnMoveUpdata() diff --git a/Assets/MyGame/aa/Game/HHWK/Boss/BaoChuanJuXie/HHWK_BCJX_Boss.cs b/Assets/MyGame/aa/Game/HHWK/Boss/BaoChuanJuXie/HHWK_BCJX_Boss.cs index 7d4631016..3db9bca26 100644 --- a/Assets/MyGame/aa/Game/HHWK/Boss/BaoChuanJuXie/HHWK_BCJX_Boss.cs +++ b/Assets/MyGame/aa/Game/HHWK/Boss/BaoChuanJuXie/HHWK_BCJX_Boss.cs @@ -23,7 +23,7 @@ public class HHWK_BCJX_Boss : MonsterControl_BossBase public override void Init(string pathId, float Time, bool isyuzhen = false, string yzID = "") { base.Init(pathId, Time, isyuzhen, yzID); - if (pathId == "1") + if (pathId != "1") { Vector3 vector3 = Vector3.one; vector3.x *= -1; diff --git a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs index e8f350840..42c273080 100644 --- a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs +++ b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs @@ -103,6 +103,7 @@ using UnityEngine.InputSystem; using UnityEngine.Playables; using UnityEngine.SceneManagement; using UnityEngine.UI; +using Random = UnityEngine.Random; public class GameMainPanel_FishBase : GameMainPanel_Base { @@ -150,15 +151,12 @@ public class GameMainPanel_FishBase : GameMainPanel_Base [Header("攻击参数")] public float attackTime = 0.5f; [Header("人机参数")] - public float botRotateSpeed = 40f; // 人机炮台旋转速度(度/秒),和自动扫射速度一致 - public float botTargetHoldTime = 2.5f; // 人机锁定目标保持时间(秒) + public float botRotateSpeed = 40f; // 兜底旋转速度(BotConfig 为空时用) float clickTime = 0; private Dictionary botFireTimer = new Dictionary(); - private Dictionary botLastAngle = new Dictionary(); // botUserId → 最后一次开火角度 - private Dictionary> botBulletIds = new Dictionary>(); // botUserId → 子弹ID列表 // 人机开火计时 - // bot 目标锁定:posID → (目标guid, 切换时间戳) - private Dictionary botTargetGuid = new Dictionary(); - private Dictionary botTargetSwitchTime = new Dictionary(); + private Dictionary botLastAngle = new Dictionary(); + // bot 技能运行时 + private Dictionary botSkills = new Dictionary(); public GameObject bullet_Test; public GameObject bulletParent; float changeTurretTime = 0f; @@ -1904,13 +1902,18 @@ public class GameMainPanel_FishBase : GameMainPanel_Base #region 人机AI private void HandleBotAI() { - // 只有房主控制人机 if (SitPosData.roomOwnerSit == null || currSitData != SitPosData.roomOwnerSit) return; - if (!GameManager.Instance.enableBot) return; + + var cfg = GameManager.Instance.botConfig; + bool enabled = cfg != null ? cfg.enabled : GameManager.Instance.enableBot; + if (!enabled) return; var fishList = CreateFishManager.Instance; if (fishList == null || fishList.fishDatas_hashCodekey == null) return; + BotBehaviorConfig behavior = GetBotBehavior(cfg); + float rotateSpeed = behavior != null ? behavior.rotateSpeed : botRotateSpeed; + foreach (var sit in list_Sits) { if (!sit.isBot || sit.gameObject.activeSelf == false) continue; @@ -1918,81 +1921,153 @@ public class GameMainPanel_FishBase : GameMainPanel_Base Vector3 turretPos = sit.tra_CurrTurret.position; - // ---- 目标锁定:优先沿用当前目标,失效/超时才换新 ---- - MonsterContral target = null; - float now = Time.time; + // ====== 技能刷新 ====== + if (cfg != null && cfg.skills != null) + RefreshBotSkills(sit, cfg.skills); + var skill = botSkills.ContainsKey(sit.posID) ? botSkills[sit.posID] : null; - // 检查当前锁定的目标是否还可用 - if (botTargetGuid.TryGetValue(sit.posID, out string currGuid)) + // ====== 找目标:Boss > 黄金鱼 > 特殊鱼 > 普通鱼 ====== + MonsterContral target = SelectBotTarget(sit, fishList, turretPos); + + if (target != null) { - if (fishList.fishDatas_hashCodekey.TryGetValue(currGuid, out var m) - && m != null && m.gameObject.activeInHierarchy) - { - // 目标还活着,检查是否超时 - float switchT = botTargetSwitchTime.ContainsKey(sit.posID) ? botTargetSwitchTime[sit.posID] : 0f; - if (now < switchT) - { - // 检查目标是否还在炮台前方 - Vector3 fishPos = m.transform.position; - bool inFront = sit.IsFlipped ? (fishPos.y < turretPos.y) : (fishPos.y > turretPos.y); - if (inFront) target = m; - } - } + // 旋转朝向目标(持续旋转,不管发不发炮) + if (skill == null || !skill.lockActive) + RotateBotToTarget(sit, target.transform.position, rotateSpeed); } - // 目标失效 → 找新目标 - if (target == null) - { - float bestDist = float.MaxValue; - foreach (var kv in fishList.fishDatas_hashCodekey) - { - 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; - if (d < bestDist) { bestDist = d; target = m; } - } - - if (target != null) - { - botTargetGuid[sit.posID] = target.guid; - botTargetSwitchTime[sit.posID] = now + botTargetHoldTime; - } - } - - if (target == null) continue; - - // 旋转朝向鱼(仅本地旋转,不广播 SyncRotate) - RotateBotToTarget(sit, target.transform.position); - - // 定时开火 + // ====== 持续射击 ====== if (!botFireTimer.ContainsKey(sit.posID)) botFireTimer[sit.posID] = 0f; botFireTimer[sit.posID] += Time.deltaTime; - if (botFireTimer[sit.posID] >= attackTime) + + float fireInterval = behavior != null + ? Random.Range(behavior.fireIntervalMin, behavior.fireIntervalMax) + : attackTime; + if (skill != null && skill.frenzyActive) + fireInterval *= 0.5f; + + if (botFireTimer[sit.posID] >= fireInterval) { botFireTimer[sit.posID] = 0f; + float angle = sit.currentAngle; botLastAngle[sit.user] = angle; - // 1. BotFireCannon → 后端扣金币、发 bulletIds、广播 RoomFireNotice、概率触发 RoomKillNotice + + int count = 1; + long gold = sit.consumeGoldNum; + if (skill != null) + { + if (skill.tripleActive) count = 3; + if (skill.doubleActive) gold *= 2; + } + WebSocketSendList.BotFireCannon( GameManager.Instance.gameData.currRoomData.roomId, - sit.user, - sit.consumeGoldNum, - 1 - ); - // 2. SyncGameData → 角度/视觉同步给其他客户端 - SyncFire_ForBot(sit, angle); + sit.user, gold, count); + SyncFire_ForBot(sit, angle, gold, count); } } } - /// 人机炮台旋转:和 RotateToLockTarget 完全一致的坐标转换,仅本地旋转不广播 - private void RotateBotToTarget(SitPosData sit, Vector3 fishWorldPos) + /// + /// 按优先级选目标:特殊Boss(5) > Boss(2) > 黄金鱼(3) > 特殊鱼(4) > 普通鱼(1) + /// 同一优先级内选最近的,只选炮台前方的鱼 + /// + private MonsterContral SelectBotTarget(SitPosData sit, CreateFishManager fishList, Vector3 turretPos) + { + MonsterContral best = null; + float bestDist = float.MaxValue; + int bestPri = int.MaxValue; + + foreach (var kv in fishList.fishDatas_hashCodekey) + { + 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)) + { + bestPri = pri; + bestDist = d; + best = m; + } + } + + return best; + } + + private int GetFishPriority(int fishType) + { + switch (fishType) + { + case 5: return 0; // 特殊Boss — 最高优先 + case 2: return 1; // Boss鱼 + case 3: return 2; // 黄金鱼 + case 4: return 3; // 特殊鱼 + default: return 4; // 普通鱼 + } + } + + /// 根据 aiState 取对应行为参数,cfg 为 null 时返回 null + private BotBehaviorConfig GetBotBehavior(BotConfig cfg) + { + if (cfg == null) return null; + switch (cfg.aiState) + { + case "idle": return cfg.idleBehavior ?? cfg.activeBehavior; + case "aggressive": return cfg.aggressiveBehavior ?? cfg.activeBehavior; + default: return cfg.activeBehavior; + } + } + + /// 技能掷骰子:每隔 skillRefreshInterval 秒独立决定各技能开关 + private void RefreshBotSkills(SitPosData sit, BotSkillConfig skillCfg) + { + if (skillCfg == null) return; + + if (!botSkills.TryGetValue(sit.posID, out var s)) + { + s = new BotSkillRuntime(); + botSkills[sit.posID] = s; + } + + if (Time.time < s.nextRefreshTime) return; + s.nextRefreshTime = Time.time + skillCfg.skillRefreshInterval; + + // 独立掷骰子:还在持续中就沿用,否则重新掷 + s.lockActive = (s.lockActive && Time.time < s.lockEndTime) + || Random.value < skillCfg.lockProb; + if (s.lockActive && Time.time >= s.lockEndTime) + s.lockEndTime = Time.time + Random.Range(skillCfg.lockMinTime, skillCfg.lockMaxTime); + + s.frenzyActive = (s.frenzyActive && Time.time < s.frenzyEndTime) + || Random.value < skillCfg.frenzyProb; + if (s.frenzyActive && Time.time >= s.frenzyEndTime) + s.frenzyEndTime = Time.time + Random.Range(skillCfg.frenzyMinTime, skillCfg.frenzyMaxTime); + + s.tripleActive = (s.tripleActive && Time.time < s.tripleEndTime) + || Random.value < skillCfg.tripleProb; + if (s.tripleActive && Time.time >= s.tripleEndTime) + s.tripleEndTime = Time.time + Random.Range(skillCfg.tripleMinTime, skillCfg.tripleMaxTime); + + s.doubleActive = (s.doubleActive && Time.time < s.doubleEndTime) + || Random.value < skillCfg.doubleProb; + if (s.doubleActive && Time.time >= s.doubleEndTime) + s.doubleEndTime = Time.time + Random.Range(skillCfg.doubleMinTime, skillCfg.doubleMaxTime); + } + + /// 人机炮台旋转 + private void RotateBotToTarget(SitPosData sit, Vector3 fishWorldPos, float rotateSpeed = -1f) { Vector2 screenPos = Camera.main.WorldToScreenPoint(fishWorldPos); @@ -2011,16 +2086,15 @@ public class GameMainPanel_FishBase : GameMainPanel_Base // 平滑旋转:像真人一样缓慢转动,避免瞬间闪现 float current = sit.currentAngle; - float maxDelta = botRotateSpeed * Time.deltaTime; + float speed = rotateSpeed > 0f ? rotateSpeed : botRotateSpeed; + float maxDelta = speed * Time.deltaTime; float smoothed = Mathf.MoveTowardsAngle(current, angle, maxDelta); sit.SetRotation(smoothed); } /// 人机开火同步(房主代发) - private void SyncFire_ForBot(SitPosData botSit, float angle) + private void SyncFire_ForBot(SitPosData botSit, float angle, long gold, int count) { - bool isSanShe = toggle_Three.isOn; - bool isDouble = toggle_Shuang.isOn; SyncGameData sgd = new SyncGameData { sitPos = botSit.posID, @@ -2029,9 +2103,9 @@ public class GameMainPanel_FishBase : GameMainPanel_Base frameData = new FrameData_FireBullet { angle = angle, - gold = botSit.consumeGoldNum, - isSanShe = isSanShe, - twoRTruuect = isDouble, + gold = gold, + isSanShe = count >= 3, + twoRTruuect = false, isSuoDing = false, } }; diff --git a/Assets/MyGame/aa/UI/Home/Sub/JJJPanel.prefab b/Assets/MyGame/aa/UI/Home/Sub/JJJPanel.prefab index 86ef66ab7..a2a222aab 100644 --- a/Assets/MyGame/aa/UI/Home/Sub/JJJPanel.prefab +++ b/Assets/MyGame/aa/UI/Home/Sub/JJJPanel.prefab @@ -498,7 +498,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!224 &2240831687397372415 RectTransform: m_ObjectHideFlags: 0 @@ -1557,7 +1557,7 @@ RectTransform: m_AnchorMin: {x: 0, y: 1} m_AnchorMax: {x: 1, y: 1} m_AnchoredPosition: {x: 0, y: 0} - m_SizeDelta: {x: 0, y: 0} + m_SizeDelta: {x: 0, y: 156.39} m_Pivot: {x: 0, y: 1} --- !u!222 &6471194083618413022 CanvasRenderer: @@ -2910,6 +2910,7 @@ MonoBehaviour: img_DisReceive: {fileID: 7555849612512069883} txt_coinsNum: {fileID: 1582126856504394273} txt_TimeNum: {fileID: 4439275919574394212} + txt_JieShao: {fileID: 1652518100479989480} tra_itemParent: {fileID: 138125964109178341} jJJItemPrefab: {fileID: 8382726376953176281} --- !u!222 &4127708294653599189 @@ -3309,6 +3310,7 @@ GameObject: - component: {fileID: 5110941090233518657} - component: {fileID: 5337867815149946794} - component: {fileID: 1146322170064182606} + - component: {fileID: 3188025623166685728} m_Layer: 0 m_Name: BY_jiujijin_015 m_TagString: Untagged @@ -3373,6 +3375,62 @@ MonoBehaviour: m_FillOrigin: 0 m_UseSpriteMesh: 0 m_PixelsPerUnitMultiplier: 1 +--- !u!114 &3188025623166685728 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6968090748301552078} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 4e29b1a8efbd4b44bb3f3716e73f07ff, type: 3} + m_Name: + m_EditorClassIdentifier: + m_Navigation: + m_Mode: 3 + m_WrapAround: 0 + m_SelectOnUp: {fileID: 0} + m_SelectOnDown: {fileID: 0} + m_SelectOnLeft: {fileID: 0} + m_SelectOnRight: {fileID: 0} + m_Transition: 1 + m_Colors: + m_NormalColor: {r: 1, g: 1, b: 1, a: 1} + m_HighlightedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_PressedColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 1} + m_SelectedColor: {r: 0.9607843, g: 0.9607843, b: 0.9607843, a: 1} + m_DisabledColor: {r: 0.78431374, g: 0.78431374, b: 0.78431374, a: 0.5019608} + m_ColorMultiplier: 1 + m_FadeDuration: 0.1 + m_SpriteState: + m_HighlightedSprite: {fileID: 0} + m_PressedSprite: {fileID: 0} + m_SelectedSprite: {fileID: 0} + m_DisabledSprite: {fileID: 0} + m_AnimationTriggers: + m_NormalTrigger: Normal + m_HighlightedTrigger: Highlighted + m_PressedTrigger: Pressed + m_SelectedTrigger: Selected + m_DisabledTrigger: Disabled + m_Interactable: 1 + m_TargetGraphic: {fileID: 1146322170064182606} + m_OnClick: + m_PersistentCalls: + m_Calls: + - m_Target: {fileID: 396840008078746686} + m_TargetAssemblyTypeName: UnityEngine.GameObject, UnityEngine + m_MethodName: SetActive + m_Mode: 6 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 1 + m_CallState: 2 --- !u!1 &7296351711350652844 GameObject: m_ObjectHideFlags: 0 @@ -4103,7 +4161,19 @@ MonoBehaviour: m_TargetGraphic: {fileID: 3885569884753230168} m_OnClick: m_PersistentCalls: - m_Calls: [] + m_Calls: + - m_Target: {fileID: 396840008078746686} + m_TargetAssemblyTypeName: UnityEngine.GameObject, UnityEngine + m_MethodName: SetActive + m_Mode: 6 + m_Arguments: + m_ObjectArgument: {fileID: 0} + m_ObjectArgumentAssemblyTypeName: UnityEngine.Object, UnityEngine + m_IntArgument: 0 + m_FloatArgument: 0 + m_StringArgument: + m_BoolArgument: 0 + m_CallState: 2 --- !u!1 &8585067189318063193 GameObject: m_ObjectHideFlags: 0 diff --git a/Assets/MyGame/aa/UI/Home/Sub/UIHome_BY_JJJPanel.cs b/Assets/MyGame/aa/UI/Home/Sub/UIHome_BY_JJJPanel.cs index 96a6eef96..af56e8e7b 100644 --- a/Assets/MyGame/aa/UI/Home/Sub/UIHome_BY_JJJPanel.cs +++ b/Assets/MyGame/aa/UI/Home/Sub/UIHome_BY_JJJPanel.cs @@ -1,5 +1,6 @@ using Assets.MyGame.Scripts.Net; using Assets.MyGame.Scripts.Net.API.GameConfig_SubClass; +using System.Collections; using TMPro; using UnityEngine; using UnityEngine.UI; @@ -17,6 +18,8 @@ public class UIHome_BY_JJJPanel : SubUIBase public JJJItem jJJItemPrefab; private ReliefConfig reliefCfg; + private Coroutine _countdownCoroutine; + private string _introTemplate; // 前两行固定文案模板 public override void Awake() { @@ -37,6 +40,16 @@ public class UIHome_BY_JJJPanel : SubUIBase RefreshPanel(); } + protected override void OnHide() + { + base.OnHide(); + if (_countdownCoroutine != null) + { + StopCoroutine(_countdownCoroutine); + _countdownCoroutine = null; + } + } + private void RefreshPanel() { APIRequestList.GetReliefConfig(jjjData => @@ -47,7 +60,10 @@ public class UIHome_BY_JJJPanel : SubUIBase int totalCount = reliefCfg.count; int remaining = user.@static.reliefGoldCount; int claimed = totalCount - remaining; - txt_JieShao.text = $"1.金币低于{reliefCfg.limit}可以领取{reliefCfg.gold}\r\n2.每天可以领取{reliefCfg.count}次\r\n3.剩余00:00:00刷新领取次数"; + + // 固定前两行模板,第三行由协程实时更新 + _introTemplate = $"1.金币低于{reliefCfg.limit}可以领取{reliefCfg.gold}\r\n2.每天可以领取{reliefCfg.count}次\r\n"; + txt_coinsNum.text = "金币" + reliefCfg.gold.ToString(); txt_TimeNum.text = $"剩余次数:{remaining}"; @@ -59,11 +75,15 @@ public class UIHome_BY_JJJPanel : SubUIBase btn_Receive.interactable = canReceive; BuildTimesList(totalCount, claimed, canReceive); + + // 启动倒计时协程 + StartCountdown(); }); } private void BuildTimesList(int totalCount, int claimedCount, bool canReceive) { + if (tra_itemParent == null) return; for (int i = tra_itemParent.childCount - 1; i >= 0; i--) Destroy(tra_itemParent.GetChild(i).gameObject); @@ -79,4 +99,45 @@ public class UIHome_BY_JJJPanel : SubUIBase item.Init(isClaimed, isCanClaim, isLocked, reliefCfg.gold); } } + + // ==================== 实时倒计时 ==================== + + private void StartCountdown() + { + if (_countdownCoroutine != null) + StopCoroutine(_countdownCoroutine); + _countdownCoroutine = StartCoroutine(CountdownLoop()); + } + + private IEnumerator CountdownLoop() + { + var wait = new WaitForSeconds(1f); + + while (true) + { + UpdateCountdownText(); + yield return wait; + } + } + + private void UpdateCountdownText() + { + if (txt_JieShao == null || string.IsNullOrEmpty(_introTemplate)) return; + + // 计算到次日 00:00:00 的剩余时间 + System.DateTime now = System.DateTime.Now; + System.DateTime tomorrow = now.Date.AddDays(1); + System.TimeSpan remaining = tomorrow - now; + + // 跨天检测:刷新面板 + if (remaining.TotalSeconds <= 0) + { + txt_JieShao.text = _introTemplate + "3.剩余00:00:00刷新领取次数"; + RefreshPanel(); + return; + } + + string countdown = $"{remaining.Hours:D2}:{remaining.Minutes:D2}:{remaining.Seconds:D2}"; + txt_JieShao.text = _introTemplate + $"3.剩余{countdown}刷新领取次数"; + } }