diff --git a/Assets/MyGame/Scenes/UIScene.unity b/Assets/MyGame/Scenes/UIScene.unity index e2d2470c8..d9036957e 100644 --- a/Assets/MyGame/Scenes/UIScene.unity +++ b/Assets/MyGame/Scenes/UIScene.unity @@ -5552,11 +5552,6 @@ PrefabInstance: serializedVersion: 3 m_TransformParent: {fileID: 1096182889} m_Modifications: - - target: {fileID: 2189820374461339302, guid: f206f68250e35c54481406a83c165790, - type: 3} - propertyPath: m_IsActive - value: 0 - objectReference: {fileID: 0} - target: {fileID: 4683725052380794649, guid: f206f68250e35c54481406a83c165790, type: 3} propertyPath: m_Pivot.x @@ -5660,12 +5655,12 @@ PrefabInstance: - target: {fileID: 5436103631707523789, guid: f206f68250e35c54481406a83c165790, type: 3} propertyPath: m_SizeDelta.x - value: 0 + value: -683 objectReference: {fileID: 0} - target: {fileID: 6568873253317409902, guid: f206f68250e35c54481406a83c165790, type: 3} propertyPath: m_SizeDelta.y - value: 0 + value: 14 objectReference: {fileID: 0} - target: {fileID: 7032782682867687973, guid: f206f68250e35c54481406a83c165790, type: 3} @@ -5697,17 +5692,12 @@ PrefabInstance: propertyPath: m_Name value: ZhanLing objectReference: {fileID: 0} - - target: {fileID: 7077596146806315097, guid: f206f68250e35c54481406a83c165790, + - target: {fileID: 7033739248829094286, guid: f206f68250e35c54481406a83c165790, type: 3} - propertyPath: m_AnchorMax.y + propertyPath: m_IsActive value: 0 objectReference: {fileID: 0} - - target: {fileID: 7741008535677535188, guid: f206f68250e35c54481406a83c165790, - type: 3} - propertyPath: m_AnchorMax.y - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 8156378713621244176, guid: f206f68250e35c54481406a83c165790, + - target: {fileID: 7077596146806315097, guid: f206f68250e35c54481406a83c165790, type: 3} propertyPath: m_AnchorMax.y value: 1 @@ -5715,7 +5705,7 @@ PrefabInstance: - target: {fileID: 8876291267844903025, guid: f206f68250e35c54481406a83c165790, type: 3} propertyPath: m_SizeDelta.x - value: 0 + value: 235.37 objectReference: {fileID: 0} m_RemovedComponents: [] m_RemovedGameObjects: [] diff --git a/Assets/MyGame/Scripts/Items/Bullits/BullitMove.cs b/Assets/MyGame/Scripts/Items/Bullits/BullitMove.cs index 00ea890ee..a6472d879 100644 --- a/Assets/MyGame/Scripts/Items/Bullits/BullitMove.cs +++ b/Assets/MyGame/Scripts/Items/Bullits/BullitMove.cs @@ -198,9 +198,34 @@ public class BullitMove : MonoBehaviour if (userid == GameManager.Instance.user.id) { + // 真人玩家击杀 var v2 = GameManager.Instance.gameData.currRoomData; WebSocketSendList.KillFish(v2.roomId, userid, monster.monsterData.fishTypeConfig.fishNumber, monster.guid, (int)CreateFishManager.Instance.currGameType.currSitData.consumeGoldNum, bulletID, "63215f0afa3f5b25"); } + else if (!string.IsNullOrEmpty(userid) && userid.StartsWith("bot_")) + { + // 机器人击杀:只有房主客户端发送 BotKillFish + if (SitPosData.roomOwnerSit != null && SitPosData.roomOwnerSit.user == GameManager.Instance.user.id) + { + var v2 = GameManager.Instance.gameData.currRoomData; + // 从 bot 座位获取炮倍 + long gold = 100; + var panel = CreateFishManager.Instance.currGameType; + if (panel != null && panel.list_Sits != null) + { + var sit = panel.list_Sits.Find(s => s.user == userid); + if (sit != null) gold = sit.consumeGoldNum; + } + WebSocketSendList.BotKillFish( + v2.roomId, + userid, + monster.monsterData.fishTypeConfig.fishNumber, + monster.guid, + gold, + bulletID + ); + } + } monster.OnHurt(); Destroy(gameObject); diff --git a/Assets/MyGame/Scripts/Net/APIRequest/Params/HallRequest.cs b/Assets/MyGame/Scripts/Net/APIRequest/Params/HallRequest.cs index f29ffc35d..13e2e88d4 100644 --- a/Assets/MyGame/Scripts/Net/APIRequest/Params/HallRequest.cs +++ b/Assets/MyGame/Scripts/Net/APIRequest/Params/HallRequest.cs @@ -187,4 +187,11 @@ namespace Assets.MyGame.Scripts.Net.APIRequest.Params { public int type; // ½ø½×ÀàÐÍ 1=¾«Ӣ 2=ÖÁ×ð } + + /// »ñȡÓû§ÈÎÎñÁбí£¨GET£© + [Serializable] + public class GetUserTaskListParam : RequestParamBase + { + public int taskType = -1; // -1=ȫ²¿ + } } diff --git a/Assets/MyGame/Scripts/Net/APIRequestList_Hall.cs b/Assets/MyGame/Scripts/Net/APIRequestList_Hall.cs index 4b524ca98..8bd10a339 100644 --- a/Assets/MyGame/Scripts/Net/APIRequestList_Hall.cs +++ b/Assets/MyGame/Scripts/Net/APIRequestList_Hall.cs @@ -207,9 +207,10 @@ namespace Assets.MyGame.Scripts.Net /// 参数:用户ID /// 返回:UserTaskListResponse(任务列表) /// - public static void GetUserTaskList(Action callback) + public static void GetUserTaskList(Action> callback) { - APIManager.Response(APIType.Hall_GetUserTaskList, callback); + APIManager.Response>(APIType.Hall_GetUserTaskList, + new GetUserTaskListParam { taskType = -1 }, callback); } /// diff --git a/Assets/MyGame/Scripts/Net/APIResponses/HallResponses.cs b/Assets/MyGame/Scripts/Net/APIResponses/HallResponses.cs index 1e830a07d..653cce4eb 100644 --- a/Assets/MyGame/Scripts/Net/APIResponses/HallResponses.cs +++ b/Assets/MyGame/Scripts/Net/APIResponses/HallResponses.cs @@ -284,4 +284,25 @@ namespace Assets.MyGame.Scripts.Net.APIResponses public string message; public List purchasedAdvances; } + + /// 用户任务 DTO(/api/Hall/GetUserTaskList?taskType=-1) + [Serializable] + public class UserTaskDto + { + public string id; + public string userId; + public string number; + public string remark; + public int taskType; // 任务类型 + public int taskEvent; // 任务事件 + public int taskCount; // 任务次数要求 + public int count; // 当前完成次数 + public bool isFinish; // 是否完成 + public string otherId; + public bool isGet; // 是否已领取 + public int taskAddTime; + public long taskEndTime; + public long taskFinishTime; + public int exp; // 奖励经验 + } } \ No newline at end of file diff --git a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs index 823f88149..3cec76910 100644 --- a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs +++ b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs @@ -149,10 +149,16 @@ public class GameMainPanel_FishBase : GameMainPanel_Base [Header("攻击参数")] public float attackTime = 0.5f; + [Header("人机参数")] + public float botRotateSpeed = 360f; // 人机炮台旋转速度(度/秒) + public float botTargetHoldTime = 2.5f; // 人机锁定目标保持时间(秒) 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(); public GameObject bullet_Test; public GameObject bulletParent; float changeTurretTime = 0f; @@ -1862,6 +1868,10 @@ public class GameMainPanel_FishBase : GameMainPanel_Base sit.goldNum = goldNum; sit.consumeGoldNum = consumeGold; + // ⭐ 在 ShowPlayer 之前标记 isBot,否则 ShowPlayer 里的 AssignRoomOwner 会把 bot 设为房主 + if (!string.IsNullOrEmpty(user) && user.StartsWith("bot_")) + sit.isBot = true; + sit.tMP_GoldNum.text = goldNum.ToString(); sit.tMP_DiamondNum.text = diamondNum.ToString(); sit.tMP_TurretConsumeNum.text = consumeGold.ToString(); @@ -1870,6 +1880,13 @@ public class GameMainPanel_FishBase : GameMainPanel_Base if (!string.IsNullOrEmpty(cannonId) && int.TryParse(cannonId, out int turretNum)) sit.LoadTurret(turretNum); + else if (sit.isBot) + { + // bot 没有炮台ID时给一个默认炮台 + var turretList = TurretResourcesData.GetTurretDataByType(1); + if (turretList != null && turretList.Count > 0) + sit.LoadTurret(turretList[0].turretNumber); + } if (!string.IsNullOrEmpty(wingId) && int.TryParse(wingId, out int wingNum)) sit.LoadWing(wingNum); @@ -1899,17 +1916,54 @@ public class GameMainPanel_FishBase : GameMainPanel_Base if (!sit.isBot || sit.gameObject.activeSelf == false) continue; if (sit.tra_CurrTurret == null) continue; - // 找最近鱼 - MonsterContral target = null; - float bestDist = float.MaxValue; Vector3 turretPos = sit.tra_CurrTurret.position; - foreach (var kv in fishList.fishDatas_hashCodekey) + + // ---- 目标锁定:优先沿用当前目标,失效/超时才换新 ---- + MonsterContral target = null; + float now = Time.time; + + // 检查当前锁定的目标是否还可用 + if (botTargetGuid.TryGetValue(sit.posID, out string currGuid)) { - var m = kv.Value; - if (m == null || !m.gameObject.activeInHierarchy) continue; - float d = (m.transform.position - turretPos).sqrMagnitude; - if (d < bestDist) { bestDist = d; target = m; } + 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 (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) @@ -1937,16 +1991,22 @@ public class GameMainPanel_FishBase : GameMainPanel_Base } } - /// 人机炮台旋转:直接用世界坐标算角度,仅本地旋转,不广播 + /// 人机炮台旋转:和 RotateToLockTarget 完全一致的坐标转换,仅本地旋转不广播 private void RotateBotToTarget(SitPosData sit, Vector3 fishWorldPos) { - Vector3 turretWorldPos = sit.tra_CurrTurret.position; - Vector2 dir = (Vector2)(fishWorldPos - turretWorldPos); - if (dir.sqrMagnitude < 1f) return; + Vector2 screenPos = Camera.main.WorldToScreenPoint(fishWorldPos); + + RectTransformUtility.ScreenPointToLocalPointInRectangle( + sit.tra_CurrTurret.transform.parent as RectTransform, + screenPos, null, out Vector2 localPos); + + Vector2 dir = localPos - sit.tra_CurrTurret.GetComponent().anchoredPosition; + + // 鱼太近时 dir 接近零向量,Atan2 不稳定 → 跳过 + if (dir.sqrMagnitude < 25f) return; float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg - 90f; - // 上方座位(2,3)炮台默认朝上,加180°让它朝下打鱼 if (sit.IsFlipped) angle = (angle + 180f) % 360f; sit.SetRotation(angle); diff --git a/Assets/MyGame/aa/UI/Home/Sub/ZhanLing_Panel.cs b/Assets/MyGame/aa/UI/Home/Sub/ZhanLing_Panel.cs index eccbeb929..5adea061f 100644 --- a/Assets/MyGame/aa/UI/Home/Sub/ZhanLing_Panel.cs +++ b/Assets/MyGame/aa/UI/Home/Sub/ZhanLing_Panel.cs @@ -160,10 +160,17 @@ public class ZhanLing_Panel : SubUIBase if (lv100 != null && levelGiftitem_100 != null) { bool showDuiGou = claimedSet.Contains(_maxLevel); + bool reachedLevel = level >= _maxLevel; + + LevelGiftType giftType100 = LevelGiftType.MianFei; + if (lv100.luxuryGiftType > 0 && _userData.isLuxury) giftType100 |= LevelGiftType.JingYing; + if (lv100.supremeGiftType > 0 && _userData.isSupreme) giftType100 |= LevelGiftType.ZhiZun; + levelGiftitem_100.Init( GetIconUrl(lv100.normalGiftType), lv100.normalGiftCount, - "", 0, "", 0, - _maxLevel, LevelGiftType.MianFei, level >= _maxLevel && showDuiGou); + GetIconUrl(lv100.luxuryGiftType), lv100.luxuryGiftCount, + GetIconUrl(lv100.supremeGiftType), lv100.supremeGiftCount, + _maxLevel, giftType100, reachedLevel && showDuiGou); levelGiftitem_100.gameObject.SetActive(true); } } @@ -177,11 +184,17 @@ public class ZhanLing_Panel : SubUIBase for (int i = renWuItemParent.childCount - 1; i >= 0; i--) Destroy(renWuItemParent.GetChild(i).gameObject); - // 示例任务(后续对接任务列表 API) - CreateTaskItem(10, 10, 20, "每日登录", 0.5f, UIPanel.None); - CreateTaskItem(20, 10, 20, "捕鱼10条", 0.5f, UIPanel.None); - CreateTaskItem(30, 0, 30, "充值任意金额", 0f, UIPanel.None); + APIRequestList.GetUserTaskList(tasks => + { + if (tasks == null) return; + foreach (var t in tasks) + { + float progress = t.taskCount > 0 ? (float)t.count / t.taskCount : 0f; + CreateTaskItem(t.exp, t.count, t.taskCount, t.remark, progress, UIPanel.None); + } + }); } + private void CreateTaskItem(int expCount, int currJinDu, int maxJinDu, string label, float progress, UIPanel targetPanel) {