Procházet zdrojové kódy

血条位置解决

181404010226 před 1 měsícem
rodič
revize
0e638c6085

+ 50 - 60
assets/Scenes/GameLevel.scene

@@ -26,7 +26,7 @@
     "_active": true,
     "_components": [],
     "_prefab": {
-      "__id__": 1437
+      "__id__": 1436
     },
     "_lpos": {
       "__type__": "cc.Vec3",
@@ -57,7 +57,7 @@
     },
     "autoReleaseAssets": false,
     "_globals": {
-      "__id__": 1477
+      "__id__": 1476
     },
     "_id": "29694223-a59c-44b3-acb0-80ab92d103f5"
   },
@@ -10206,7 +10206,7 @@
     "_lpos": {
       "__type__": "cc.Vec3",
       "x": 0,
-      "y": -535.204,
+      "y": -683.562,
       "z": 0
     },
     "_lrot": {
@@ -49025,9 +49025,6 @@
       },
       {
         "__id__": 1435
-      },
-      {
-        "__id__": 1436
       }
     ],
     "guideMaskAreasRoot": {
@@ -49254,13 +49251,6 @@
     "eventName": "",
     "delaySeconds": -1
   },
-  {
-    "__type__": "GuideStepRef",
-    "category": "tap",
-    "action": "tap",
-    "eventName": "",
-    "delaySeconds": -1
-  },
   {
     "__type__": "cc.PrefabInfo",
     "root": null,
@@ -49269,49 +49259,49 @@
     "instance": null,
     "targetOverrides": [
       {
-        "__id__": 1438
+        "__id__": 1437
       },
       {
-        "__id__": 1441
+        "__id__": 1440
       },
       {
-        "__id__": 1444
+        "__id__": 1443
       },
       {
-        "__id__": 1447
+        "__id__": 1446
       },
       {
-        "__id__": 1450
+        "__id__": 1449
       },
       {
-        "__id__": 1453
+        "__id__": 1452
       },
       {
-        "__id__": 1456
+        "__id__": 1455
       },
       {
-        "__id__": 1459
+        "__id__": 1458
       },
       {
-        "__id__": 1462
+        "__id__": 1461
       },
       {
-        "__id__": 1465
+        "__id__": 1464
       },
       {
-        "__id__": 1467
+        "__id__": 1466
       },
       {
-        "__id__": 1469
+        "__id__": 1468
       },
       {
-        "__id__": 1471
+        "__id__": 1470
       },
       {
-        "__id__": 1473
+        "__id__": 1472
       },
       {
-        "__id__": 1475
+        "__id__": 1474
       }
     ],
     "nestedPrefabInstanceRoots": [
@@ -49338,7 +49328,7 @@
       "__id__": 345
     },
     "sourceInfo": {
-      "__id__": 1439
+      "__id__": 1438
     },
     "propertyPath": [
       "skillSpriteNode"
@@ -49347,7 +49337,7 @@
       "__id__": 345
     },
     "targetInfo": {
-      "__id__": 1440
+      "__id__": 1439
     }
   },
   {
@@ -49368,7 +49358,7 @@
       "__id__": 345
     },
     "sourceInfo": {
-      "__id__": 1442
+      "__id__": 1441
     },
     "propertyPath": [
       "skillNameNode"
@@ -49377,7 +49367,7 @@
       "__id__": 345
     },
     "targetInfo": {
-      "__id__": 1443
+      "__id__": 1442
     }
   },
   {
@@ -49398,7 +49388,7 @@
       "__id__": 345
     },
     "sourceInfo": {
-      "__id__": 1445
+      "__id__": 1444
     },
     "propertyPath": [
       "skillIntroduceNode"
@@ -49407,7 +49397,7 @@
       "__id__": 345
     },
     "targetInfo": {
-      "__id__": 1446
+      "__id__": 1445
     }
   },
   {
@@ -49428,7 +49418,7 @@
       "__id__": 393
     },
     "sourceInfo": {
-      "__id__": 1448
+      "__id__": 1447
     },
     "propertyPath": [
       "skillSpriteNode"
@@ -49437,7 +49427,7 @@
       "__id__": 393
     },
     "targetInfo": {
-      "__id__": 1449
+      "__id__": 1448
     }
   },
   {
@@ -49458,7 +49448,7 @@
       "__id__": 393
     },
     "sourceInfo": {
-      "__id__": 1451
+      "__id__": 1450
     },
     "propertyPath": [
       "skillNameNode"
@@ -49467,7 +49457,7 @@
       "__id__": 393
     },
     "targetInfo": {
-      "__id__": 1452
+      "__id__": 1451
     }
   },
   {
@@ -49488,7 +49478,7 @@
       "__id__": 393
     },
     "sourceInfo": {
-      "__id__": 1454
+      "__id__": 1453
     },
     "propertyPath": [
       "skillIntroduceNode"
@@ -49497,7 +49487,7 @@
       "__id__": 393
     },
     "targetInfo": {
-      "__id__": 1455
+      "__id__": 1454
     }
   },
   {
@@ -49518,7 +49508,7 @@
       "__id__": 297
     },
     "sourceInfo": {
-      "__id__": 1457
+      "__id__": 1456
     },
     "propertyPath": [
       "skillSpriteNode"
@@ -49527,7 +49517,7 @@
       "__id__": 297
     },
     "targetInfo": {
-      "__id__": 1458
+      "__id__": 1457
     }
   },
   {
@@ -49548,7 +49538,7 @@
       "__id__": 297
     },
     "sourceInfo": {
-      "__id__": 1460
+      "__id__": 1459
     },
     "propertyPath": [
       "skillNameNode"
@@ -49557,7 +49547,7 @@
       "__id__": 297
     },
     "targetInfo": {
-      "__id__": 1461
+      "__id__": 1460
     }
   },
   {
@@ -49578,7 +49568,7 @@
       "__id__": 297
     },
     "sourceInfo": {
-      "__id__": 1463
+      "__id__": 1462
     },
     "propertyPath": [
       "skillIntroduceNode"
@@ -49587,7 +49577,7 @@
       "__id__": 297
     },
     "targetInfo": {
-      "__id__": 1464
+      "__id__": 1463
     }
   },
   {
@@ -49616,7 +49606,7 @@
       "__id__": 297
     },
     "targetInfo": {
-      "__id__": 1466
+      "__id__": 1465
     }
   },
   {
@@ -49639,7 +49629,7 @@
       "__id__": 345
     },
     "targetInfo": {
-      "__id__": 1468
+      "__id__": 1467
     }
   },
   {
@@ -49662,7 +49652,7 @@
       "__id__": 393
     },
     "targetInfo": {
-      "__id__": 1470
+      "__id__": 1469
     }
   },
   {
@@ -49684,7 +49674,7 @@
       "__id__": 1338
     },
     "targetInfo": {
-      "__id__": 1472
+      "__id__": 1471
     }
   },
   {
@@ -49706,7 +49696,7 @@
       "__id__": 1338
     },
     "targetInfo": {
-      "__id__": 1474
+      "__id__": 1473
     }
   },
   {
@@ -49728,7 +49718,7 @@
     ],
     "target": null,
     "targetInfo": {
-      "__id__": 1476
+      "__id__": 1475
     }
   },
   {
@@ -49740,28 +49730,28 @@
   {
     "__type__": "cc.SceneGlobals",
     "ambient": {
-      "__id__": 1478
+      "__id__": 1477
     },
     "shadows": {
-      "__id__": 1479
+      "__id__": 1478
     },
     "_skybox": {
-      "__id__": 1480
+      "__id__": 1479
     },
     "fog": {
-      "__id__": 1481
+      "__id__": 1480
     },
     "octree": {
-      "__id__": 1482
+      "__id__": 1481
     },
     "skin": {
-      "__id__": 1483
+      "__id__": 1482
     },
     "lightProbeInfo": {
-      "__id__": 1484
+      "__id__": 1483
     },
     "postSettings": {
-      "__id__": 1485
+      "__id__": 1484
     },
     "bakedWithStationaryMainLight": false,
     "bakedWithHighpLightmap": false

+ 7 - 2
assets/scripts/Animations/HPBarAnimation.ts

@@ -137,7 +137,12 @@ export class HPBarAnimation extends Component {
      * 显示血条
      */
     public showHealthBar() {
-        this.updateBarPosition();
+        // 仅在首次显示时进行定位计算,避免每次受击重复计算
+        const barNode = (this.hpBarRootNode && this.hpBarRootNode.isValid) ? this.hpBarRootNode : this.node;
+        const wasActive = barNode.active;
+        if (!wasActive) {
+            this.updateBarPosition();
+        }
         if (this.hpBarRootNode && this.hpBarRootNode.isValid) {
             this.hpBarRootNode.active = true;
             if (this.debugLogs) console.log(`[HPBarAnimation] showHealthBar: active=true path=${this.getNodePath(this.hpBarRootNode)}`);
@@ -197,7 +202,7 @@ export class HPBarAnimation extends Component {
         newProgress = Math.max(0, Math.min(1, newProgress));
         if (showBar) {
             this.showHealthBar();
-            this.updateBarPosition();
+            // 定位仅在首次显示时执行,避免受击重复计算
         }
         
         // 如果血量增加或没有变化,直接更新

+ 17 - 44
assets/scripts/CombatSystem/BallController.ts

@@ -1703,21 +1703,9 @@ export class BallController extends Component {
      * 维持所有小球的恒定速度
      */
     private maintainAllBallsSpeed() {
-        // 维持主小球速度
-        if (this.activeBall && this.activeBall.isValid) {
-            this.maintainBallSpeed(this.activeBall);
-        }
-        
-        // 维持额外小球的速度
-        const gameArea = find('Canvas/GameLevelUI/GameArea');
-        if (gameArea) {
-            const additionalBalls = gameArea.children.filter(child => 
-                child.name === 'AdditionalBall' && child.isValid
-            );
-            
-            for (const ball of additionalBalls) {
-                this.maintainBallSpeed(ball);
-            }
+        const balls = this.getAllActiveBalls();
+        for (const ball of balls) {
+            this.maintainBallSpeed(ball);
         }
     }
     
@@ -1954,33 +1942,17 @@ export class BallController extends Component {
         // 清空之前的暂停速度记录
         this.allBallsPausedVelocities.clear();
 
-        // 暂停主球
-        if (this.activeBall && this.activeBall.isValid) {
-            const rb = this.activeBall.getComponent(RigidBody2D);
+        // 暂停所有活跃小球(包括主球和任何复制/新增的小球)
+        const balls = this.getAllActiveBalls();
+        for (const ball of balls) {
+            const rb = ball.getComponent(RigidBody2D);
             if (rb) {
-                this.allBallsPausedVelocities.set(this.activeBall, rb.linearVelocity.clone());
+                this.allBallsPausedVelocities.set(ball, rb.linearVelocity.clone());
                 rb.linearVelocity = new Vec2(0, 0);
                 rb.sleep();
             }
         }
 
-        // 暂停所有额外球
-        const gameArea = find('Canvas/GameLevelUI/GameArea');
-        if (gameArea) {
-            const additionalBalls = gameArea.children.filter(child => 
-                child.name === 'AdditionalBall' && child.isValid
-            );
-            
-            for (const ball of additionalBalls) {
-                const rb = ball.getComponent(RigidBody2D);
-                if (rb) {
-                    this.allBallsPausedVelocities.set(ball, rb.linearVelocity.clone());
-                    rb.linearVelocity = new Vec2(0, 0);
-                    rb.sleep();
-                }
-            }
-        }
-
         console.log(`[BallController] 已暂停 ${this.allBallsPausedVelocities.size} 个小球`);
     }
 
@@ -2191,23 +2163,24 @@ export class BallController extends Component {
      */
     private getAllActiveBalls(): Node[] {
         const balls: Node[] = [];
+        const gameArea = find('Canvas/GameLevelUI/GameArea');
         
-        // 添加
+        // 主球优先加入
         if (this.activeBall && this.activeBall.isValid) {
             balls.push(this.activeBall);
         }
         
-        // 查找所有额外小球
-        const gameArea = find('Canvas/GameLevelUI/GameArea');
+        // 包含所有处于球碰撞分组的节点(不依赖名称),避免遗漏复制出的主球
         if (gameArea) {
-            // 遍历GameArea的所有子节点,查找小球
-            gameArea.children.forEach(child => {
-                if (child.name === 'AdditionalBall' && child.isValid) {
+            for (const child of gameArea.children) {
+                if (!child.isValid) continue;
+                if (child === this.activeBall) continue;
+                const collider = child.getComponent(CircleCollider2D);
+                if (collider && collider.group === this.colliderGroup) {
                     balls.push(child);
                 }
-            });
+            }
         }
-        
         return balls;
     }
     

+ 24 - 1
assets/scripts/CombatSystem/BlockSelection/GameBlockSelection.ts

@@ -839,13 +839,36 @@ export class GameBlockSelection extends Component {
 
     // 生成方块选择(不再控制UI显示,只负责生成方块)
     public generateBlockSelection() {
+        // 尝试确保拿到 BlockManager(兼容场景切换后生命周期先后顺序)
+        if (!this.blockManager) {
+            // 1) 通过已绑定的节点拿组件
+            if (this.blockManagerNode && this.blockManagerNode.isValid) {
+                this.blockManager = this.blockManagerNode.getComponent(BlockManager);
+            }
+            // 2) 回退到路径查找(确保场景加载后也能获取到)
+            if (!this.blockManager) {
+                const bmNode = find('Canvas/GameLevelUI/BlockController');
+                if (bmNode) {
+                    this.blockManager = bmNode.getComponent(BlockManager) as any;
+                    if (!this.blockManager) {
+                        // 兼容字符串组件名(某些环境下主动通过字符串拿组件)
+                        this.blockManager = bmNode.getComponent('BlockManager') as any;
+                    }
+                }
+            }
+            // 3) 如果武器配置已预加载,补传一次给 BlockManager
+            if (this.blockManager && this.weaponsConfigData && typeof (this.blockManager as any).setPreloadedWeaponsConfig === 'function') {
+                (this.blockManager as any).setPreloadedWeaponsConfig(this.weaponsConfigData);
+                console.log('[GameBlockSelection] 懒加载后已向BlockManager传递武器配置');
+            }
+        }
+
         // 直接生成方块,不再依赖shouldGenerateBlocks标志
         if (this.blockManager) {
             this.blockManager.refreshBlocks();
         } else {
             console.warn('[GameBlockSelection] BlockManager未找到,无法生成随机方块');
         }
-
         // 触发进入备战状态事件
         EventBus.getInstance().emit(GameEvents.ENTER_BATTLE_PREPARATION);
     }

+ 11 - 60
assets/scripts/CombatSystem/EnemyInstance.ts

@@ -437,56 +437,7 @@ export class EnemyInstance extends Component {
         }
     }
 
-    /**
-     * 动态调整血条位置,使其始终显示在碰撞体上方
-     */
-    private updateHPBarPosition(): void {
-        // 获取血条根节点
-        const hpBarRoot = this.node.getChildByName('HPBar');
-        if (!hpBarRoot) {
-            console.warn('[EnemyInstance] 未找到HPBar节点,无法调整血条位置');
-            return;
-        }
-
-        // 获取EnemySprite节点和其碰撞器
-        const enemySprite = this.node.getChildByName('EnemySprite');
-        if (!enemySprite) {
-            console.error('[EnemyInstance] 未找到EnemySprite子节点,无法计算血条位置');
-            return;
-        }
-
-        const collider = enemySprite.getComponent(Collider2D);
-        const uiTransform = enemySprite.getComponent(UITransform);
-        if (!collider || !uiTransform) {
-            console.warn('[EnemyInstance] EnemySprite节点缺少必要组件,无法计算血条位置');
-            return;
-        }
-
-        // 计算碰撞体的顶部位置
-        let colliderTopY = 0;
-        const anchorPoint = uiTransform.anchorPoint;
-        
-        if (collider instanceof BoxCollider2D) {
-            const boxCollider = collider as BoxCollider2D;
-            // 碰撞体顶部 = 碰撞体偏移Y + 碰撞体高度的一半
-            colliderTopY = boxCollider.offset.y + boxCollider.size.height / 2;
-        } else if (collider instanceof CircleCollider2D) {
-            const circleCollider = collider as CircleCollider2D;
-            // 碰撞体顶部 = 碰撞体偏移Y + 半径
-            colliderTopY = circleCollider.offset.y + circleCollider.radius;
-        }
-
-        // 血条位置设置为碰撞体顶部上方一定距离
-        const hpBarOffset = -35; // 血条距离碰撞体顶部的距离
-        const hpBarY = colliderTopY + hpBarOffset;
-
-        // 设置血条位置
-        const hpBarTransform = hpBarRoot.getComponent(UITransform);
-        if (hpBarTransform) {
-            hpBarRoot.setPosition(0, hpBarY, 0);
-            console.log(`[EnemyInstance] 血条位置已更新: Y = ${hpBarY.toFixed(2)} (碰撞体顶部: ${colliderTopY.toFixed(2)})`);
-        }
-    }
+    // 已统一到 HPBarAnimation.updateBarPosition,移除本地冗余定位实现
 
     // 碰撞开始事件
     onBeginContact(selfCollider: Collider2D, otherCollider: Collider2D, contact: IPhysics2DContact | null) {
@@ -1042,7 +993,7 @@ export class EnemyInstance extends Component {
             
             // 动画切换后延迟更新血条位置,确保动画尺寸已生效
             this.scheduleOnce(() => {
-                this.updateHPBarPosition();
+                this.hpBarAnimation?.updateBarPosition(true);
             }, 0.1);
             
             // 获取动画时长并在动画即将结束时发射抛掷物
@@ -1153,7 +1104,7 @@ export class EnemyInstance extends Component {
         
         // 动画切换后延迟更新血条位置,确保动画尺寸已生效
         this.scheduleOnce(() => {
-            this.updateHPBarPosition();
+            this.hpBarAnimation?.updateBarPosition(true);
         }, 0.1);
     }
 
@@ -1173,7 +1124,7 @@ export class EnemyInstance extends Component {
         
         // 动画切换后延迟更新血条位置,确保动画尺寸已生效
         this.scheduleOnce(() => {
-            this.updateHPBarPosition();
+            this.hpBarAnimation?.updateBarPosition(true);
         }, 0.1);
     }
 
@@ -1193,7 +1144,7 @@ export class EnemyInstance extends Component {
         
         // 动画切换后延迟更新血条位置,确保动画尺寸已生效
         this.scheduleOnce(() => {
-            this.updateHPBarPosition();
+            this.hpBarAnimation?.updateBarPosition(true);
         }, 0.1);
     }
 
@@ -1211,9 +1162,9 @@ export class EnemyInstance extends Component {
             console.log(`[EnemyInstance] 安全播放待机动画: ${idleName}`);
             
             // 动画切换后延迟更新血条位置,确保动画尺寸已生效
-            this.scheduleOnce(() => {
-                this.updateHPBarPosition();
-            }, 0.1);
+        this.scheduleOnce(() => {
+            this.hpBarAnimation?.updateBarPosition(true);
+        }, 0.1);
         }
     }
 
@@ -1238,9 +1189,9 @@ export class EnemyInstance extends Component {
             console.log(`[EnemyInstance] 播放近战攻击动画: ${attackName}`);
             
             // 动画切换后延迟更新血条位置,确保动画尺寸已生效
-            this.scheduleOnce(() => {
-                this.updateHPBarPosition();
-            }, 0.1);
+        this.scheduleOnce(() => {
+            this.hpBarAnimation?.updateBarPosition(true);
+        }, 0.1);
             
             // 获取动画时长并在动画结束时造成伤害
             const animationDuration = animation.duration;

+ 21 - 4
assets/scripts/CombatSystem/MenuSystem/MenuController.ts

@@ -2,6 +2,7 @@ import { _decorator, Component, Node, Button, find } from 'cc';
 import { PopUPAni } from '../../Animations/PopUPAni';
 import EventBus, { GameEvents } from '../../Core/EventBus';
 import { GameManager, AppState } from '../../LevelSystem/GameManager';
+import { SaveDataManager } from '../../LevelSystem/SaveDataManager';
 import { GameStartMove } from '../../Animations/GameStartMove';
 import { SoundController } from './SoundController';
 import { Audio } from '../../AudioManager/AudioManager';
@@ -124,6 +125,15 @@ export class MenuController extends Component {
     private updateMenuButtonVisibility() {
         // 检查当前应用状态
         const currentAppState = this.gameManager ? this.gameManager.getCurrentAppState() : null;
+        // 检查是否为第一关
+        const isFirstLevel = (() => {
+            try {
+                const save = SaveDataManager.getInstance();
+                return save && typeof save.getCurrentLevel === 'function' && save.getCurrentLevel() === 1;
+            } catch {
+                return false;
+            }
+        })();
         
         // 在游戏外界面中,检查是否在需要隐藏菜单按钮的界面
         if (currentAppState !== AppState.IN_GAME && this.isInHiddenMenuUI()) {
@@ -132,10 +142,17 @@ export class MenuController extends Component {
             if (this.menuButton1) this.menuButton1.node.active = false;
             console.log('[MenuController] 在游戏外界面中隐藏菜单按钮');
         } else if (currentAppState === AppState.IN_GAME) {
-            // 游戏中显示menuButton1,隐藏menuButton
-            if (this.menuButton) this.menuButton.node.active = false;
-            if (this.menuButton1) this.menuButton1.node.active = true;
-            console.log('[MenuController] 游戏中显示menuButton1');
+            // 第一关隐藏游戏中的菜单按钮
+            if (isFirstLevel) {
+                if (this.menuButton) this.menuButton.node.active = false;
+                if (this.menuButton1) this.menuButton1.node.active = false;
+                console.log('[MenuController] 第一关隐藏MenueButton-001');
+            } else {
+                // 非第一关:游戏中显示menuButton1,隐藏menuButton
+                if (this.menuButton) this.menuButton.node.active = false;
+                if (this.menuButton1) this.menuButton1.node.active = true;
+                console.log('[MenuController] 游戏中显示menuButton1');
+            }
         } else {
             // 主界面显示menuButton,隐藏menuButton1
             if (this.menuButton) this.menuButton.node.active = true;

+ 1 - 5
assets/scripts/Core/NewbieGuideManager.ts

@@ -42,11 +42,7 @@ export class NewbieGuideManager {
      * 这个方法应该在MainUIController的onLoad中调用
      */
     public checkAndStartNewbieGuideOnSceneLoad(): void {
-        if (this.hasCheckedOnSceneLoad) {
-            return; // 避免重复检查
-        }
-        
-        this.hasCheckedOnSceneLoad = true;
+        // 每次场景加载都重新评估引导状态,避免状态在后续关卡残留
         console.log('[NewbieGuideManager] 场景加载时检查新手引导状态');
         
         const currentLevel = this.saveDataManager?.getCurrentLevel?.() ?? 1;

+ 51 - 16
assets/scripts/Utils/AnalyticsManager.ts

@@ -623,11 +623,31 @@ export class AnalyticsManager {
      * 获取用户ID
      */
     private getUserId(): string {
-        // 尝试从本地存储获取用户ID,如果没有则生成新的
-        let userId = localStorage.getItem('analytics_user_id');
+        const storage: any = (globalThis as any).localStorage;
+        const wxAny: any = (globalThis as any).wx;
+        let userId: string | null = null;
+
+        try {
+            if (storage && typeof storage.getItem === 'function') {
+                userId = storage.getItem('analytics_user_id');
+            } else if (wxAny && typeof wxAny.getStorageSync === 'function') {
+                userId = wxAny.getStorageSync('analytics_user_id') || null;
+            }
+        } catch {
+            // ignore storage errors
+        }
+
         if (!userId) {
             userId = 'user_' + Date.now() + '_' + Math.random().toString(36).substr(2, 9);
-            localStorage.setItem('analytics_user_id', userId);
+            try {
+                if (storage && typeof storage.setItem === 'function') {
+                    storage.setItem('analytics_user_id', userId);
+                } else if (wxAny && typeof wxAny.setStorageSync === 'function') {
+                    wxAny.setStorageSync('analytics_user_id', userId);
+                }
+            } catch {
+                // ignore storage errors
+            }
         }
         return userId;
     }
@@ -636,19 +656,34 @@ export class AnalyticsManager {
      * 初始化设备信息
      */
     private initDeviceInfo(): void {
-        this.deviceInfo = {
-            platform: 'web',
-            user_agent: navigator.userAgent,
-            screen_width: screen.width,
-            screen_height: screen.height,
-            language: navigator.language,
-            timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
-        };
-
-        // 如果是微信小游戏环境,获取更多信息
-        if (typeof wx !== 'undefined') {
-            this.deviceInfo.platform = 'wechat_game';
-            // 可以调用wx.getSystemInfo等API获取更详细的设备信息
+        const safeNavigator: any = (globalThis as any).navigator || {};
+        const safeScreen: any = (globalThis as any).screen || {};
+        const wxAny: any = (globalThis as any).wx;
+
+        // 优先使用微信小游戏的系统信息,无需时区字段
+        if (wxAny && typeof wxAny.getSystemInfoSync === 'function') {
+            const sys = wxAny.getSystemInfoSync();
+            this.deviceInfo = {
+                platform: 'wechat_game',
+                user_agent: safeNavigator.userAgent || 'wechat_game',
+                screen_width: sys.screenWidth ?? safeScreen.width ?? 0,
+                screen_height: sys.screenHeight ?? safeScreen.height ?? 0,
+                language: sys.language || safeNavigator.language || 'zh_CN',
+                brand: sys.brand,
+                model: sys.model,
+                system: sys.system,
+                version: sys.version,
+                pixelRatio: sys.pixelRatio
+            };
+        } else {
+            // Web 环境的基础设备信息,移除时区字段以避免 Intl 依赖
+            this.deviceInfo = {
+                platform: 'web',
+                user_agent: safeNavigator.userAgent || 'unknown',
+                screen_width: safeScreen.width || 0,
+                screen_height: safeScreen.height || 0,
+                language: safeNavigator.language || 'en'
+            };
         }
     }
     /**