diff --git a/Assets/AddressableAssetsData/Windows/addressables_content_state.bin b/Assets/AddressableAssetsData/Windows/addressables_content_state.bin index f5de23cac..eff99eb80 100644 Binary files a/Assets/AddressableAssetsData/Windows/addressables_content_state.bin and b/Assets/AddressableAssetsData/Windows/addressables_content_state.bin differ diff --git a/Assets/MyGame/Scenes/UIScene.unity b/Assets/MyGame/Scenes/UIScene.unity index 79af10009..ef09ccfbc 100644 --- a/Assets/MyGame/Scenes/UIScene.unity +++ b/Assets/MyGame/Scenes/UIScene.unity @@ -1510,7 +1510,7 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 132536, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_IsActive - value: 0 + value: 1 objectReference: {fileID: 0} - target: {fileID: 22400762, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchoredPosition.y @@ -1518,11 +1518,11 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 22426080, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMax.x - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22426080, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMax.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22426080, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMin.y @@ -1530,51 +1530,51 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 22428984, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMax.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22428984, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMin.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22428984, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_SizeDelta.x - value: 165.4 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22428984, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_SizeDelta.y - value: 36 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22428984, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchoredPosition.x - value: 720.3 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22428984, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchoredPosition.y - value: -18 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22455554, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMax.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22455554, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMin.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22455554, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_SizeDelta.x - value: 165.4 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22455554, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_SizeDelta.y - value: 36 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22455554, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchoredPosition.x - value: 885.7 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22455554, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchoredPosition.y - value: -18 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22457152, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_Pivot.x @@ -1658,147 +1658,147 @@ PrefabInstance: objectReference: {fileID: 0} - target: {fileID: 22468896, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMax.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22468896, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMin.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22468896, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_SizeDelta.x - value: 165.4 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22468896, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_SizeDelta.y - value: 36 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22468896, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchoredPosition.x - value: 1216.5 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22468896, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchoredPosition.y - value: -18 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22485076, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMax.x - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22485076, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMax.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22485076, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_SizeDelta.x - value: -28 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22488670, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMax.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22488670, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMin.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22488670, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_SizeDelta.x - value: 165.4 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22488670, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_SizeDelta.y - value: 36 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22488670, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchoredPosition.x - value: 248.09999 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22488670, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchoredPosition.y - value: -18 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22495692, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMax.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22495692, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMin.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22495692, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_SizeDelta.x - value: 165.4 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22495692, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_SizeDelta.y - value: 36 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22495692, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchoredPosition.x - value: 1051.1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 22495692, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchoredPosition.y - value: -18 + value: 0 objectReference: {fileID: 0} - target: {fileID: 224619367409363176, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMax.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 224619367409363176, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMin.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 224619367409363176, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_SizeDelta.x - value: 306.8 + value: 0 objectReference: {fileID: 0} - target: {fileID: 224619367409363176, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_SizeDelta.y - value: 36 + value: 0 objectReference: {fileID: 0} - target: {fileID: 224619367409363176, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchoredPosition.x - value: 484.19998 + value: 0 objectReference: {fileID: 0} - target: {fileID: 224619367409363176, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchoredPosition.y - value: -18 + value: 0 objectReference: {fileID: 0} - target: {fileID: 224856348943071238, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMax.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 224856348943071238, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchorMin.y - value: 1 + value: 0 objectReference: {fileID: 0} - target: {fileID: 224856348943071238, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_SizeDelta.x - value: 165.4 + value: 0 objectReference: {fileID: 0} - target: {fileID: 224856348943071238, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_SizeDelta.y - value: 36 + value: 0 objectReference: {fileID: 0} - target: {fileID: 224856348943071238, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchoredPosition.x - value: 82.7 + value: 0 objectReference: {fileID: 0} - target: {fileID: 224856348943071238, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} propertyPath: m_AnchoredPosition.y - value: -18 + value: 0 objectReference: {fileID: 0} - target: {fileID: 958269219681220773, guid: 67117722a812a2e46ab8cb8eafbf5f5e, type: 3} @@ -3137,7 +3137,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 1 + m_IsActive: 0 --- !u!224 &616555263 RectTransform: m_ObjectHideFlags: 0 diff --git a/Assets/MyGame/Scripts/Manager/CreateFishManager.cs b/Assets/MyGame/Scripts/Manager/CreateFishManager.cs index 69881d7c8..bb46a2581 100644 --- a/Assets/MyGame/Scripts/Manager/CreateFishManager.cs +++ b/Assets/MyGame/Scripts/Manager/CreateFishManager.cs @@ -1516,19 +1516,18 @@ public class CreateFishManager : MonoSingleton /// 红包拆分后的每份金额,长度应 >= count /// 金币最终飞回的世界坐标(一般是炮台位置) /// 理论上要“死”的总数量(鱼 + 纯金币) - public void Id_DieListFish_FX(List guids, List coinNum, Vector3 v3Point, int count) + public void Id_DieListFish_FX(List guids, List coinNum, Vector3 v3Point, int count, bool isLocal = false) { if (coinNum == null || coinNum.Count == 0) return; - // 1. 先处理“真的有鱼”的部分 + // 1. 先处理"真的有鱼"的部分 int realCount = Mathf.Min(guids.Count, coinNum.Count, count); for (int i = 0; i < realCount; i++) { - // 用你原来的单条逻辑,不动 - Id_DieFish_FX(guids[i], coinNum[i], v3Point); + Id_DieFish_FX(guids[i], coinNum[i], v3Point, isLocal); } - // 2. 不足的部分,用“屏幕随机位置的金币特效”补齐 + // 2. 不足的部分,用"屏幕随机位置的金币特效"补齐 int needExtra = count - realCount; if (needExtra <= 0) return; @@ -1537,7 +1536,7 @@ public class CreateFishManager : MonoSingleton for (int i = 0; i < maxExtra; i++) { var red = coinNum[realCount + i]; - SpawnRandomCoinFX(red, v3Point); + SpawnRandomCoinFX(red, v3Point, isLocal); } } /// @@ -1621,7 +1620,7 @@ public class CreateFishManager : MonoSingleton /// /// 按 ID 杀死一条鱼(带特效 + 金币飞出动画)。 /// - public void Id_DieFish_FX(string fishId, RedPacketRecord coinNum, Vector3 v3Point) + public void Id_DieFish_FX(string fishId, RedPacketRecord coinNum, Vector3 v3Point, bool isLocal = false) { if (!fishDatas_hashCodekey.TryGetValue(fishId, out var monster)) return; if (false) @@ -1649,8 +1648,8 @@ public class CreateFishManager : MonoSingleton var coinScript = award.GetComponent(); coinScript.Init(coinNum.Amount, v3Point); - //coinScript.endPoint = v3Point; coinScript.isBoss = true; + coinScript.isLocalCoin = isLocal; coinScript.SetCoinCount(); } @@ -1664,7 +1663,7 @@ public class CreateFishManager : MonoSingleton /// /// 不依赖鱼,只在屏幕内随机一个位置生成金币特效,然后飞回指定点。 /// - private void SpawnRandomCoinFX(RedPacketRecord coinNum, Vector3 targetWorldPos) + private void SpawnRandomCoinFX(RedPacketRecord coinNum, Vector3 targetWorldPos, bool isLocal = false) { // 1. 随机一个屏幕坐标 Vector2 screenPos = new Vector2( @@ -1678,7 +1677,7 @@ public class CreateFishManager : MonoSingleton // 3. 实例化金币特效(沿用你原来的 award 逻辑) var award = Instantiate( - dieFXPrefabAward, // 或者用某个专门的“掉金币” prefab + dieFXPrefabAward, // 或者用某个专门的"掉金币" prefab currGameType.subPanelParent.parent); var rect = award.GetComponent(); @@ -1689,6 +1688,7 @@ public class CreateFishManager : MonoSingleton coinScript.Init(coinNum.Amount, targetWorldPos); coinScript.isBoss = true; + coinScript.isLocalCoin = isLocal; coinScript.SetCoinCount(); } @@ -1767,6 +1767,7 @@ public class CreateFishManager : MonoSingleton var coinScript = award.GetComponent(); coinScript.Init(killFish.gold, sitData.transform.position, killFish.userId, sitData.posID, killFish.param); + coinScript.isLocalCoin = sitData.user == GameManager.Instance.user.id; coinScript.isBoss = false; coinScript.JiaFen = onScoreAdd; coinScript.SetCoinCount(); @@ -1819,6 +1820,7 @@ public class CreateFishManager : MonoSingleton var coinScript = award.GetComponent(); coinScript.Init(killFish.gold, sitData.transform.position, killFish.userId, sitData.posID, killFish.param); + coinScript.isLocalCoin = sitData.user == GameManager.Instance.user.id; coinScript.isBoss = false; coinScript.JiaFen = onScoreAdd; coinScript.SetCoinCount(); @@ -1849,6 +1851,7 @@ public class CreateFishManager : MonoSingleton var coinScript = award.GetComponent(); coinScript.startPoint = award.transform.position; coinScript.Init(killFish.gold, sitData.transform.position, killFish.userId, sitData.posID, killFish.param); + coinScript.isLocalCoin = sitData.user == GameManager.Instance.user.id; coinScript.startPoint = award.transform.position; coinScript.isBoss = false; coinScript.JiaFen = onScoreAdd; diff --git a/Assets/MyGame/aa/Game/DefaultDieEffect/BJBase.cs b/Assets/MyGame/aa/Game/DefaultDieEffect/BJBase.cs index b0b2eef9b..6cb0ceeac 100644 --- a/Assets/MyGame/aa/Game/DefaultDieEffect/BJBase.cs +++ b/Assets/MyGame/aa/Game/DefaultDieEffect/BJBase.cs @@ -13,6 +13,7 @@ public class BJBase : MonoBehaviour public GameObject silver; public Vector3 endPoint; public bool isBoss; + public bool isLocalCoin; // 是否本地玩家的金币(金/银区分用) public Action JiaFen; public int coinCount; public string userID; diff --git a/Assets/MyGame/aa/Game/DefaultDieEffect/Coin/CoinScript.cs b/Assets/MyGame/aa/Game/DefaultDieEffect/Coin/CoinScript.cs index 33ab9f394..3a1d446c2 100644 --- a/Assets/MyGame/aa/Game/DefaultDieEffect/Coin/CoinScript.cs +++ b/Assets/MyGame/aa/Game/DefaultDieEffect/Coin/CoinScript.cs @@ -10,33 +10,8 @@ public class CoinScript : BJBase { tMP_CoinCount.text = NumAdd(coinCount.ToString()); - // 自己爆奖显示金,别人显示银 - bool isMine = IsLocalPlayer(); - if (gold != null) gold.SetActive(isMine); - if (silver != null) silver.SetActive(!isMine); - } - - private bool IsLocalPlayer() - { - // 优先用 userID 判断 - if (!string.IsNullOrEmpty(userID) - && GameManager.Instance != null - && GameManager.Instance.user != null - && userID == GameManager.Instance.user.id) - return true; - - // 兜底:用 sitID 判断(boss 杀小鱼时 userID 可能为空) - if (GameManager.Instance == null || GameManager.Instance.user == null) - return false; - - var sits = CreateFishManager.Instance?.currGameType?.list_Sits; - if (sits == null) return false; - - foreach (var sit in sits) - { - if (sit != null && sit.user == GameManager.Instance.user.id) - return sitID == sit.posID; - } - return false; + // 自己爆奖显示金,别人显示银(由 Ws_DieFish 在创建时设置 isLocalCoin) + if (gold != null) gold.SetActive(isLocalCoin); + if (silver != null) silver.SetActive(!isLocalCoin); } } diff --git a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs index 3f0fba6d7..c68852426 100644 --- a/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs +++ b/Assets/MyGame/aa/UI/Game/GameMainPanel_FishBase.cs @@ -170,6 +170,9 @@ public class GameMainPanel_FishBase : GameMainPanel_Base float clickTime = 0; private Dictionary botFireTimer = new Dictionary(); private Dictionary botLastAngle = new Dictionary(); + // bot 旋转广播节流:记录上次广播的角度/时间 + private Dictionary botLastSyncAngle = new Dictionary(); + private Dictionary botLastSyncTime = new Dictionary(); // bot 技能运行时 private Dictionary botSkills = new Dictionary(); // bot 目标记忆 @@ -213,7 +216,7 @@ public class GameMainPanel_FishBase : GameMainPanel_Base int l = GameManager.Instance.gameData.currRoomData.roomLevel; foreach (var item in GameManager.Instance.gameConfig.roomConfigs) { - if (item.gameType == t && l == GameManager.Instance.gameData.currRoomData.roomLevel) + if (item.gameType == t && l == item.roomLevel) { paoBeiList = item.cannonMultipleList; } @@ -368,7 +371,6 @@ public class GameMainPanel_FishBase : GameMainPanel_Base { base.OnHide(); - UnLoadResources(); // 场景可能未加载或已卸载,做保护避免重复卸载报错 var scene = SceneManager.GetSceneByName(sceneName); @@ -623,6 +625,7 @@ public class GameMainPanel_FishBase : GameMainPanel_Base } int ina = 0; + protected virtual void Update() { @@ -1030,38 +1033,15 @@ public class GameMainPanel_FishBase : GameMainPanel_Base float angle = currSitData.IsFlipped ? (autoRotateAngle + 180f) % 360f : autoRotateAngle; currSitData.SetRotation(angle); } - private Coroutine rotateCoroutine; + /// + /// 远程玩家/bot 旋转:直接把目标角度赋给炮台,不做任何过渡。 + /// 旋转和开炮都改成实时同步,收到广播立即应用。 + /// private void SmoothRotate(SitPosData sit, float angle) { - sit.SetRotation(angle); // 先立即更新角度(逻辑角度) - if (rotateCoroutine != null) - StopCoroutine(rotateCoroutine); - - rotateCoroutine = StartCoroutine(RotateIE_Angle(sit, Quaternion.Euler(0, 0, angle))); - } - - private IEnumerator RotateIE_Angle(SitPosData sit, Quaternion target) - { - float angleThreshold = 0.1f; - - while (true) - { - float angleDiff = Quaternion.Angle(sit.tra_CurrTurret.rotation, target); - if (angleDiff <= angleThreshold) - { - sit.tra_CurrTurret.rotation = target; - yield break; - } - - sit.tra_CurrTurret.rotation = Quaternion.Lerp( - sit.tra_CurrTurret.rotation, - target, - 0.6f - ); - - yield return null; - } + if (sit == null || sit.tra_CurrTurret == null) return; + sit.SetRotation(angle); } #endregion @@ -1897,8 +1877,13 @@ public class GameMainPanel_FishBase : GameMainPanel_Base { if (sync.sitPos == currSitData.posID) return; + var sit = list_Sits[sync.sitPos]; + // ⭐ 房主不处理机器人旋转广播:房主在 RotateBotToTarget 里已直接旋转本地炮台, + // 再走 SmoothRotate 会和本地直接旋转冲突 + if (sit != null && sit.isBot && currSitData == SitPosData.roomOwnerSit) return; + var data = FrameDataParser.Parse(sync.frameData); - SmoothRotate(list_Sits[sync.sitPos], data.angle); + SmoothRotate(sit, data.angle); } public void SyncGameData_FireBullit(FireCannonSendData sync) @@ -1981,11 +1966,15 @@ public class GameMainPanel_FishBase : GameMainPanel_Base { var data = JsonConvert.DeserializeObject(sync.frameData.ToString()); + // 用 sync.sitPos 判断是否本地玩家发的(服务器不会丢这个字段) + bool isLocalSender = sync.sitPos == currSitData.posID; + CreateFishManager.Instance.Id_DieListFish_FX( data.guids, data.coinNum, new Vector3(data.x, data.y, data.z), - data.count + data.count, + isLocalSender ); } @@ -2750,7 +2739,7 @@ public class GameMainPanel_FishBase : GameMainPanel_Base 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); @@ -2775,6 +2764,30 @@ public class GameMainPanel_FishBase : GameMainPanel_Base float t = Mathf.Min(speed * 0.15f * Time.deltaTime, 1f); float smoothed = Mathf.LerpAngle(current, angle, t); sit.SetRotation(smoothed); + + // ⭐ 机器人旋转帧同步:和开炮一样实时广播 + // 只保留极小节流(角度>2° 或 0.05s)避免每帧都广播造成网络洪流 + float lastAngle = botLastSyncAngle.TryGetValue(sit.posID, out float la) ? la : -999f; + float lastTime = botLastSyncTime.TryGetValue(sit.posID, out float lt) ? lt : 0f; + if (Mathf.Abs(Mathf.DeltaAngle(lastAngle, smoothed)) > 2f || (Time.time - lastTime) > 0.05f) + { + SyncBotRotate(sit, smoothed); + botLastSyncAngle[sit.posID] = smoothed; + botLastSyncTime[sit.posID] = Time.time; + } + } + + /// 机器人旋转广播(房主代发,复用 rotateTurrect 帧类型) + private void SyncBotRotate(SitPosData botSit, float angle) + { + SyncGameData sgd = new SyncGameData + { + sitPos = botSit.posID, + frameType = FrameDataType.rotateTurrect, + time = BeijingTimeManager.Instance.CurrentTimestampMs, + frameData = new FrameData_Rotate { angle = angle } + }; + WebSocketSendList.SyncGameData(sgd); } /// 人机开火同步(房主代发)