Browse Source

Merge branch 'zst' into tanlf

181404010226 1 tuần trước cách đây
mục cha
commit
8a03dc894e

Những thai đổi đã bị hủy bỏ vì nó quá lớn
+ 462 - 110
assets/Scenes/MainScene.scene


+ 539 - 0
assets/resources/DetailPrefabs.prefab

@@ -0,0 +1,539 @@
+[
+  {
+    "__type__": "cc.Prefab",
+    "_name": "DetailPrefabs",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_native": "",
+    "data": {
+      "__id__": 1
+    },
+    "optimizationPolicy": 0,
+    "persistent": false
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "DetailPrefabs",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": null,
+    "_children": [
+      {
+        "__id__": 2
+      },
+      {
+        "__id__": 8
+      },
+      {
+        "__id__": 14
+      }
+    ],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 20
+      }
+    ],
+    "_prefab": {
+      "__id__": 22
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 10,
+      "y": -10,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Avatar",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 3
+      },
+      {
+        "__id__": 5
+      }
+    ],
+    "_prefab": {
+      "__id__": 7
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 4
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 40,
+      "height": 36
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "4fgbkOpLBPBKxD4YZ5aWzU"
+  },
+  {
+    "__type__": "cc.Sprite",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 2
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 6
+    },
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_spriteFrame": {
+      "__uuid__": "57520716-48c8-4a19-8acf-41c9f8777fb0@f9941",
+      "__expectedType__": "cc.SpriteFrame"
+    },
+    "_type": 0,
+    "_fillType": 0,
+    "_sizeMode": 1,
+    "_fillCenter": {
+      "__type__": "cc.Vec2",
+      "x": 0,
+      "y": 0
+    },
+    "_fillStart": 0,
+    "_fillRange": 0,
+    "_isTrimmedMode": true,
+    "_useGrayscale": false,
+    "_atlas": null,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "bctzSiaEpFiok1t++VXyKV"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "416uw1499NVq8tZjphWAhC",
+    "instance": null,
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "Name",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 9
+      },
+      {
+        "__id__": 11
+      }
+    ],
+    "_prefab": {
+      "__id__": 13
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": -56.903,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 8
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 10
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 52.81982421875,
+      "height": 50.4
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "bfSZz4dNZANrtxiJby746s"
+  },
+  {
+    "__type__": "cc.Label",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 8
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 12
+    },
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 255
+    },
+    "_string": "label",
+    "_horizontalAlign": 1,
+    "_verticalAlign": 1,
+    "_actualFontSize": 25,
+    "_fontSize": 25,
+    "_fontFamily": "Arial",
+    "_lineHeight": 40,
+    "_overflow": 0,
+    "_enableWrapText": true,
+    "_font": null,
+    "_isSystemFontUsed": true,
+    "_spacingX": 0,
+    "_isItalic": false,
+    "_isBold": false,
+    "_isUnderline": false,
+    "_underlineHeight": 2,
+    "_cacheMode": 0,
+    "_enableOutline": false,
+    "_outlineColor": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 255
+    },
+    "_outlineWidth": 2,
+    "_enableShadow": false,
+    "_shadowColor": {
+      "__type__": "cc.Color",
+      "r": 0,
+      "g": 0,
+      "b": 0,
+      "a": 255
+    },
+    "_shadowOffset": {
+      "__type__": "cc.Vec2",
+      "x": 2,
+      "y": 2
+    },
+    "_shadowBlur": 2,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "ac3N/rHlpLeaQzg5xR/yOr"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "54kDIn4VdPToru/ccDVhbw",
+    "instance": null,
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.Node",
+    "_name": "DetailButton",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "_parent": {
+      "__id__": 1
+    },
+    "_children": [],
+    "_active": true,
+    "_components": [
+      {
+        "__id__": 15
+      },
+      {
+        "__id__": 17
+      }
+    ],
+    "_prefab": {
+      "__id__": 19
+    },
+    "_lpos": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": -89.763,
+      "z": 0
+    },
+    "_lrot": {
+      "__type__": "cc.Quat",
+      "x": 0,
+      "y": 0,
+      "z": 0,
+      "w": 1
+    },
+    "_lscale": {
+      "__type__": "cc.Vec3",
+      "x": 1,
+      "y": 1,
+      "z": 1
+    },
+    "_mobility": 0,
+    "_layer": 33554432,
+    "_euler": {
+      "__type__": "cc.Vec3",
+      "x": 0,
+      "y": 0,
+      "z": 0
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 14
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 16
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 153,
+      "height": 41
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "4e1TCNT7dKX5wuY1PMKAi/"
+  },
+  {
+    "__type__": "cc.Sprite",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 14
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 18
+    },
+    "_customMaterial": null,
+    "_srcBlendFactor": 2,
+    "_dstBlendFactor": 4,
+    "_color": {
+      "__type__": "cc.Color",
+      "r": 255,
+      "g": 255,
+      "b": 255,
+      "a": 255
+    },
+    "_spriteFrame": {
+      "__uuid__": "dc58cc6b-a25d-4cbe-804b-beb94fed686c@f9941",
+      "__expectedType__": "cc.SpriteFrame"
+    },
+    "_type": 0,
+    "_fillType": 0,
+    "_sizeMode": 1,
+    "_fillCenter": {
+      "__type__": "cc.Vec2",
+      "x": 0,
+      "y": 0
+    },
+    "_fillStart": 0,
+    "_fillRange": 0,
+    "_isTrimmedMode": true,
+    "_useGrayscale": false,
+    "_atlas": null,
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "14VIC1pmxHfKPBhHjAC9uk"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "bb/1iqT5hHGqRdI5llT+kJ",
+    "instance": null,
+    "targetOverrides": null,
+    "nestedPrefabInstanceRoots": null
+  },
+  {
+    "__type__": "cc.UITransform",
+    "_name": "",
+    "_objFlags": 0,
+    "__editorExtras__": {},
+    "node": {
+      "__id__": 1
+    },
+    "_enabled": true,
+    "__prefab": {
+      "__id__": 21
+    },
+    "_contentSize": {
+      "__type__": "cc.Size",
+      "width": 100,
+      "height": 100
+    },
+    "_anchorPoint": {
+      "__type__": "cc.Vec2",
+      "x": 0.5,
+      "y": 0.5
+    },
+    "_id": ""
+  },
+  {
+    "__type__": "cc.CompPrefabInfo",
+    "fileId": "b1KZKc1jtCi5gFTpHaVYpm"
+  },
+  {
+    "__type__": "cc.PrefabInfo",
+    "root": {
+      "__id__": 1
+    },
+    "asset": {
+      "__id__": 0
+    },
+    "fileId": "820p2BA6tHlqUONpsHuHsM",
+    "targetOverrides": null
+  }
+]

+ 13 - 0
assets/resources/DetailPrefabs.prefab.meta

@@ -0,0 +1,13 @@
+{
+  "ver": "1.1.50",
+  "importer": "prefab",
+  "imported": true,
+  "uuid": "1e79a3a1-db6d-4712-b59b-22a85f527cba",
+  "files": [
+    ".json"
+  ],
+  "subMetas": {},
+  "userData": {
+    "syncNodeName": "DetailPrefabs"
+  }
+}

+ 0 - 0
assets/MainUI/PassUI/黑影.png → assets/resources/avatars/black.png


+ 2 - 2
assets/MainUI/PassUI/黑影.png.meta → assets/resources/avatars/black.png.meta

@@ -11,7 +11,7 @@
     "6c48a": {
       "importer": "texture",
       "uuid": "42006915-e751-448b-8224-d043a88e6ac8@6c48a",
-      "displayName": "黑影",
+      "displayName": "black",
       "id": "6c48a",
       "name": "texture",
       "userData": {
@@ -35,7 +35,7 @@
     "f9941": {
       "importer": "sprite-frame",
       "uuid": "42006915-e751-448b-8224-d043a88e6ac8@f9941",
-      "displayName": "黑影",
+      "displayName": "black",
       "id": "f9941",
       "name": "spriteFrame",
       "userData": {

+ 218 - 11
assets/scripts/GameFlowManager.ts

@@ -8,6 +8,8 @@ import { PhoneManager } from './PhoneManager';
 import { RosterManager } from './RosterManager';
 import { PersonalInfoManager } from './PersonalInfoManager';
 import { LieDetectorManager } from './LieDetectorManager';
+import { GameLifeManager } from './GameLifeManager';
+import { SummaryManager } from './SummaryManager';
 
 const { ccclass, property } = _decorator;
 
@@ -79,6 +81,18 @@ export class GameFlowManager extends Component {
     })
     lieDetectorManager: LieDetectorManager = null;
 
+    @property({
+        type: GameLifeManager,
+        tooltip: '游戏生命值管理器引用'
+    })
+    gameLifeManager: GameLifeManager = null;
+
+    @property({
+        type: SummaryManager,
+        tooltip: '总结管理器引用'
+    })
+    summaryManager: SummaryManager = null;
+
     // 当前关卡中的NPC索引
     private currentNpcIndex: number = -1;
     
@@ -92,6 +106,9 @@ export class GameFlowManager extends Component {
         // 注册按钮事件
         this.registerButtonEvents();
         
+        // 设置生命值管理器回调
+        this.setupLifeManagerCallbacks();
+        
         // 开始游戏流程
         this.startGameFlow();
     }
@@ -118,6 +135,9 @@ export class GameFlowManager extends Component {
         // 检查个人资料管理器是否被正确引用
         if (!this.personalInfoManager) {
             console.error('个人资料管理器未设置');
+        } else if (this.dataManager) {
+            // 设置DataManager引用
+            this.personalInfoManager.dataManager = this.dataManager;
         }
         
         // 检查测谎仪管理器是否被正确引用
@@ -125,7 +145,39 @@ export class GameFlowManager extends Component {
             console.error('测谎仪管理器未设置');
         }
         
+        // 检查生命值管理器是否被正确引用
+        if (!this.gameLifeManager) {
+            console.error('生命值管理器未设置');
+        }
+        
+        // 检查总结管理器是否被正确引用
+        if (!this.summaryManager) {
+            console.error('总结管理器未设置');
+        }
+        
         console.log('所有UI管理器已初始化');
+
+        if (this.summaryManager) {
+            this.summaryManager.onShowCharacterDetail = (characterId) => {
+                const npcData = this.dataManager.getNPCById(characterId);
+                if (!npcData) return;
+                
+                // 确保PersonalInfoManager有DataManager引用
+                if (this.personalInfoManager && this.dataManager) {
+                    this.personalInfoManager.dataManager = this.dataManager;
+                    
+                    console.log(`在SummaryManager中显示角色详情: ID=${characterId}, 名称=${npcData.characterName}`);
+                    
+                    this.personalInfoManager.displayCharacterInfo({
+                        characterId: npcData.characterId,
+                        info: npcData.personal?.info || "无个人资料",
+                        avatarPath: `avatars/${npcData.characterId}/avatar_${npcData.characterId}_5`
+                    });
+                    
+                    this.personalInfoManager.showPersonalInfoPanel();
+                }
+            };
+        }
     }
 
     /**
@@ -147,6 +199,103 @@ export class GameFlowManager extends Component {
         }
     }
 
+    /**
+     * 设置生命值管理器回调
+     */
+    private setupLifeManagerCallbacks(): void {
+        if (this.gameLifeManager) {
+            this.gameLifeManager.setCallbacks(
+                // 复活后的回调,继续游戏流程
+                () => {
+                    console.log('玩家已复活,继续游戏');
+                    // 重新启用按钮
+                    this.enableButtons();
+                },
+                // 游戏结束的回调,显示当天总结
+                () => {
+                    console.log('游戏结束,显示当天总结');
+                    // 禁用按钮
+                    this.disableButtons();
+                }
+            );
+        }
+    }
+
+    /**
+     * 重新开始游戏流程
+     * 在切换关卡后调用此方法重新开始游戏
+     */
+    public restartGameFlow(): void {
+        console.log('GameFlowManager.restartGameFlow被调用,重新开始游戏流程');
+        
+        // 重置NPC索引
+        this.currentNpcIndex = -1;
+        
+        // 获取新关卡数据
+        const currentLevel = this.dataManager.getCurrentLevel();
+        if (!currentLevel) {
+            console.error('无法获取当前关卡数据');
+            return;
+        }
+        
+        console.log(`开始关卡: ${currentLevel.name}`);
+        
+        // 从关卡NPC列表中随机选择NPC
+        this.setupRandomNpcs(currentLevel);
+        
+        // 如果有生命值管理器,重置状态和生命值
+        if (this.gameLifeManager) {
+            // 重置总结面板显示状态
+            this.gameLifeManager.resetSummaryPanelState();
+            
+            // 重置生命值
+            this.gameLifeManager.resetLife();
+        }
+        
+        // 显示第一个NPC
+        this.showNextNpc();
+    }
+    
+    /**
+     * 从关卡NPC列表中随机选择NPC
+     * @param levelData 关卡数据
+     */
+    private setupRandomNpcs(levelData: any): void {
+        if (!levelData || !levelData.npcs || !Array.isArray(levelData.npcs)) {
+            console.error('关卡数据中缺少有效的NPC列表');
+            this.currentNpcs = [];
+            return;
+        }
+        
+        // 获取原始NPC列表的副本
+        const allNpcs = [...levelData.npcs];
+        
+        // 打乱NPC顺序
+        this.shuffleArray(allNpcs);
+        
+        // 获取要选择的NPC数量
+        const randomNpcCount = levelData.randomNpcCount || allNpcs.length;
+        console.log(`本关卡需要随机选择 ${randomNpcCount} 个角色`);
+        
+        // 选择指定数量的NPC
+        this.currentNpcs = allNpcs.slice(0, randomNpcCount);
+        
+        console.log(`已随机选择 ${this.currentNpcs.length} 个角色`);
+    }
+    
+    /**
+     * 随机打乱数组顺序
+     * @param array 要打乱的数组
+     */
+    private shuffleArray(array: any[]): void {
+        for (let i = array.length - 1; i > 0; i--) {
+            // 生成随机索引
+            const j = Math.floor(Math.random() * (i + 1));
+            // 交换元素
+            [array[i], array[j]] = [array[j], array[i]];
+        }
+    }
+
     /**
      * 开始游戏流程
      */
@@ -160,11 +309,8 @@ export class GameFlowManager extends Component {
 
         console.log(`开始关卡: ${currentLevel.name}`);
         
-        // 获取当前关卡的NPC列表
-        this.currentNpcs = currentLevel.npcs;
-        
-        // 重置NPC索引
-        this.currentNpcIndex = -1;
+        // 从关卡NPC列表中随机选择NPC
+        this.setupRandomNpcs(currentLevel);
         
         // 显示第一个NPC
         this.showNextNpc();
@@ -174,12 +320,25 @@ export class GameFlowManager extends Component {
      * 显示下一个NPC
      */
     public showNextNpc(): void {
+        // 如果已经显示了总结面板,不再继续处理NPC
+        if (this.gameLifeManager && this.gameLifeManager.hasSummaryPanelShown()) {
+            console.log('总结面板已显示,不再继续处理NPC');
+            return;
+        }
+        
         this.currentNpcIndex++;
         
         // 检查是否还有NPC
         if (this.currentNpcIndex >= this.currentNpcs.length) {
             console.log('当前关卡所有NPC已处理完毕');
-            // 可以在这里添加关卡完成逻辑
+            // 显示总结面板
+            if (this.summaryManager) {
+                if (this.gameLifeManager) {
+                    this.gameLifeManager.showSummaryPanel();
+                } else {
+                    this.summaryManager.showSummaryPanel();
+                }
+            }
             return;
         }
         
@@ -251,6 +410,27 @@ export class GameFlowManager extends Component {
         // 禁用按钮,防止连续点击
         this.disableButtons();
         
+        // 获取当前NPC数据
+        const npcData = this.getCurrentNpcData();
+        
+        // 记录放行统计
+        if (this.summaryManager && npcData) {
+            this.summaryManager.recordPassedNPC(npcData);
+        }
+        
+        // 检查是否放行了假角色,如果是则扣除生命值
+        if (npcData && npcData.type === 'fake') {
+            console.log('错误:放行了伪装者');
+            if (this.gameLifeManager) {
+                this.gameLifeManager.decreaseLife(1);
+                
+                // 如果生命值为0,则不继续游戏流程,等待失败面板处理
+                if (this.gameLifeManager.getCurrentLife() <= 0) {
+                    return;
+                }
+            }
+        }
+        
         // 让角色向右移动,动画完成后显示下一个NPC
         this.characterManager.moveCharacterRight(() => {
             this.showNextNpc();
@@ -264,6 +444,27 @@ export class GameFlowManager extends Component {
         // 禁用按钮,防止连续点击
         this.disableButtons();
         
+        // 获取当前NPC数据
+        const npcData = this.getCurrentNpcData();
+        
+        // 记录驱赶统计
+        if (this.summaryManager && npcData) {
+            this.summaryManager.recordDismissedNPC(npcData);
+        }
+        
+        // 检查是否赶走了真角色,如果是则扣除生命值
+        if (npcData && npcData.type === 'real') {
+            console.log('错误:赶走了真实角色');
+            if (this.gameLifeManager) {
+                this.gameLifeManager.decreaseLife(1);
+                
+                // 如果生命值为0,则不继续游戏流程,等待失败面板处理
+                if (this.gameLifeManager.getCurrentLife() <= 0) {
+                    return;
+                }
+            }
+        }
+        
         // 让角色向左移动,动画完成后显示下一个NPC
         this.characterManager.moveCharacterLeft(() => {
             this.showNextNpc();
@@ -371,7 +572,7 @@ export class GameFlowManager extends Component {
             return;
         }
         
-        // 2. 构建人员数据,包括完整的头像路径
+        // 2. 构建人员数据,包括完整的头像路径和姓名
         const personnelData = currentLevel.npcs.map(npc => {
             return {
                 name: npc.characterName,
@@ -401,15 +602,21 @@ export class GameFlowManager extends Component {
             return;
         }
         
-        // 显示个人资料
-        if (this.personalInfoManager) {
+        console.log(`显示当前NPC资料: ID=${npcData.characterId}, 名称=${npcData.characterName}`);
+        
+        // 确保PersonalInfoManager已设置DataManager引用
+        if (this.personalInfoManager && this.dataManager) {
+            // 设置DataManager引用
+            this.personalInfoManager.dataManager = this.dataManager;
+            
+            // 显示个人资料
             this.personalInfoManager.displayCharacterInfo({
                 characterId: npcData.characterId,
                 info: npcData.personal?.info || "无个人资料",
-                avatarPath: `avatars/${npcData.characterId}/avatar_${npcData.characterId}_5/spriteFrame`
+                avatarPath: `avatars/${npcData.characterId}/avatar_${npcData.characterId}_5`
             });
         } else {
-            console.error('个人资料管理器未设置');
+            console.error('个人资料管理器或数据管理器未设置');
         }
     }
 

+ 273 - 0
assets/scripts/GameLifeManager.ts

@@ -0,0 +1,273 @@
+import { _decorator, Component, Node, Label, Sprite, Button } from 'cc';
+import { SummaryManager } from './SummaryManager';
+const { ccclass, property } = _decorator;
+
+/**
+ * 游戏生命值管理器,处理生命值和挑战失败、当天总结UI
+ */
+@ccclass('GameLifeManager')
+export class GameLifeManager extends Component {
+    @property({
+        tooltip: '最大生命值',
+        min: 0,
+        max: 3
+    })
+    maxLife: number = 3;
+    
+    @property({
+        type: [Sprite],
+        tooltip: '生命值图标数组'
+    })
+    lifeIcons: Sprite[] = [];
+    
+    @property({
+        type: Node,
+        tooltip: '挑战失败UI面板'
+    })
+    failurePanel: Node = null;
+    
+    @property({
+        type: Button,
+        tooltip: '复活按钮'
+    })
+    reviveButton: Button = null;
+    
+    @property({
+        type: Button,
+        tooltip: '取消按钮'
+    })
+    cancelButton: Button = null;
+    
+    @property({
+        type: SummaryManager,
+        tooltip: '总结管理器引用'
+    })
+    summaryManager: SummaryManager = null;
+    
+    // 当前生命值
+    private currentLife: number = 3;
+    
+    // 回调函数
+    private onReviveCallback: () => void = null;
+    private onGameOverCallback: () => void = null;
+    
+    // 是否已经显示过总结面板
+    private hasSummaryShown: boolean = false;
+    
+    start() {
+        // 初始化生命值
+        this.currentLife = this.maxLife;
+        this.updateLifeDisplay();
+        
+        // 隐藏面板
+        if (this.failurePanel) {
+            this.failurePanel.active = false;
+        }
+        
+        // 重置显示标志
+        this.hasSummaryShown = false;
+        
+        // 注册按钮事件
+        this.setupButtons();
+    }
+    
+    /**
+     * 设置按钮事件
+     */
+    private setupButtons() {
+        if (this.reviveButton) {
+            this.reviveButton.node.on(Button.EventType.CLICK, this.handleRevive, this);
+        }
+        
+        if (this.cancelButton) {
+            this.cancelButton.node.on(Button.EventType.CLICK, this.handleCancel, this);
+        }
+    }
+    
+    /**
+     * 设置回调函数
+     * @param onRevive 复活后的回调
+     * @param onGameOver 游戏结束的回调
+     */
+    public setCallbacks(onRevive: () => void, onGameOver: () => void) {
+        this.onReviveCallback = onRevive;
+        this.onGameOverCallback = onGameOver;
+    }
+    
+    /**
+     * 减少生命值
+     * @param amount 减少的数量,默认为1
+     * @returns 剩余生命值
+     */
+    public decreaseLife(amount: number = 1): number {
+        this.currentLife = Math.max(0, this.currentLife - amount);
+        console.log(`扣除${amount}点生命值,当前生命值: ${this.currentLife}`);
+        
+        // 更新生命值显示
+        this.updateLifeDisplay();
+        
+        // 检查是否游戏结束
+        if (this.currentLife <= 0) {
+            this.showFailurePanel();
+            return 0;
+        }
+        
+        return this.currentLife;
+    }
+    
+    /**
+     * 增加生命值
+     * @param amount 增加的数量,默认为1
+     * @returns 剩余生命值
+     */
+    public increaseLife(amount: number = 1): number {
+        this.currentLife = Math.min(this.maxLife, this.currentLife + amount);
+        console.log(`恢复${amount}点生命值,当前生命值: ${this.currentLife}`);
+        
+        // 更新生命值显示
+        this.updateLifeDisplay();
+        
+        return this.currentLife;
+    }
+    
+    /**
+     * 更新生命值显示
+     */
+    private updateLifeDisplay() {
+        if (this.lifeIcons.length === 0) return;
+        
+        // 更新每个生命值图标的显示状态
+        for (let i = 0; i < this.lifeIcons.length; i++) {
+            if (i < this.currentLife) {
+                // 显示生命值图标
+                this.lifeIcons[i].node.active = true;
+            } else {
+                // 隐藏生命值图标
+                this.lifeIcons[i].node.active = false;
+            }
+        }
+    }
+    
+    /**
+     * 显示挑战失败面板
+     */
+    private showFailurePanel() {
+        if (this.failurePanel) {
+            this.failurePanel.active = true;
+            this.failurePanel.setSiblingIndex(999); // 确保显示在最前面
+        }
+    }
+    
+    /**
+     * 隐藏挑战失败面板
+     */
+    private hideFailurePanel() {
+        if (this.failurePanel) {
+            this.failurePanel.active = false;
+        }
+    }
+    
+    /**
+     * 显示当天总结面板
+     */
+    public showSummaryPanel() {
+        // 标记已显示总结面板
+        this.hasSummaryShown = true;
+        console.log('GameLifeManager.showSummaryPanel被调用,准备显示总结面板');
+        
+        // 使用SummaryManager显示总结面板
+        if (this.summaryManager) {
+            console.log('summaryManager引用存在,调用showSummaryPanel方法');
+            this.summaryManager.showSummaryPanel();
+        } else {
+            console.error('summaryManager引用不存在,无法显示总结面板');
+        }
+    }
+    
+    /**
+     * 处理复活按钮点击
+     */
+    private handleRevive() {
+        // 隐藏失败面板
+        this.hideFailurePanel();
+        
+        // 恢复1点生命值
+        this.increaseLife(1);
+        
+        // 调用复活回调
+        if (this.onReviveCallback) {
+            this.onReviveCallback();
+        }
+    }
+    
+    /**
+     * 处理取消按钮点击
+     */
+    private handleCancel() {
+        // 隐藏失败面板
+        this.hideFailurePanel();
+        
+        // 显示当天总结面板
+        this.showSummaryPanel();
+        
+        // 调用游戏结束回调
+        if (this.onGameOverCallback) {
+            this.onGameOverCallback();
+        }
+    }
+    
+    /**
+     * 获取当前生命值
+     */
+    public getCurrentLife(): number {
+        return this.currentLife;
+    }
+    
+    /**
+     * 获取最大生命值
+     */
+    public getMaxLife(): number {
+        return this.maxLife;
+    }
+    
+    /**
+     * 检查是否已显示总结面板
+     */
+    public hasSummaryPanelShown(): boolean {
+        return this.hasSummaryShown;
+    }
+    
+    /**
+     * 重置总结面板显示状态
+     */
+    public resetSummaryPanelState(): void {
+        this.hasSummaryShown = false;
+    }
+    
+    /**
+     * 重置生命值
+     * 在关卡切换时调用
+     */
+    public resetLife(): void {
+        console.log('GameLifeManager.resetLife被调用,重置生命值');
+        
+        // 恢复到最大生命值
+        this.currentLife = this.maxLife;
+        
+        // 更新生命值显示
+        this.updateLifeDisplay();
+        
+        console.log(`生命值已重置为 ${this.currentLife}`);
+    }
+    
+    onDestroy() {
+        // 清理按钮事件
+        if (this.reviveButton) {
+            this.reviveButton.node.off(Button.EventType.CLICK, this.handleRevive, this);
+        }
+        
+        if (this.cancelButton) {
+            this.cancelButton.node.off(Button.EventType.CLICK, this.handleCancel, this);
+        }
+    }
+} 

+ 9 - 0
assets/scripts/GameLifeManager.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "43e06872-8a55-42f4-a0bd-035f2bb9472f",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

+ 139 - 9
assets/scripts/PersonalInfoManager.ts

@@ -1,4 +1,5 @@
-import { _decorator, Component, Node, Button, Sprite, Label, SpriteFrame, resources, tween, Vec3, UIOpacity } from 'cc';
+import { _decorator, Component, Node, Button, Sprite, Label, SpriteFrame, resources } from 'cc';
+import { DataManager } from './DataManager';
 const { ccclass, property } = _decorator;
 
 @ccclass('PersonalInfoManager')
@@ -27,6 +28,18 @@ export class PersonalInfoManager extends Component {
     })
     infoText: Label = null;
     
+    @property({
+        type: Label,
+        tooltip: '角色姓名、房间号、ID等信息标签'
+    })
+    nameInfoLabel: Label = null;
+    
+    @property({
+        type: DataManager,
+        tooltip: '数据管理器引用'
+    })
+    dataManager: DataManager = null;
+    
     @property({
         tooltip: '动画时间(秒)',
         range: [0.1, 2.0, 0.1]
@@ -173,6 +186,8 @@ export class PersonalInfoManager extends Component {
             return;
         }
         
+        console.log(`PersonalInfoManager.displayCharacterInfo: ID=${data.characterId}, 头像路径=${data.avatarPath}`);
+        
         // 保存当前显示的角色ID
         this.currentCharacterId = data.characterId;
         
@@ -183,20 +198,135 @@ export class PersonalInfoManager extends Component {
         
         // 加载并设置头像
         if (this.characterAvatar && data.avatarPath) {
-            resources.load(data.avatarPath, SpriteFrame, (err, spriteFrame) => {
-                if (err) {
-                    console.error(`加载头像失败: ${data.avatarPath}`, err);
-                    return;
-                }
-                
-                this.characterAvatar.spriteFrame = spriteFrame;
-            });
+            const characterId = data.characterId;
+            
+            // 列出所有可能尝试的路径格式
+            const pathsToTry = [
+                `${data.avatarPath}/spriteFrame`,
+                data.avatarPath,
+                `avatars/${characterId}/avatar_${characterId}_5/spriteFrame`,
+                `avatars/${characterId}/avatar_${characterId}_5`,
+                `avatars/${characterId}/spriteFrame`,
+                `avatars/${characterId}`
+            ];
+            
+            // 递归尝试加载所有可能的路径
+            this.tryLoadSpriteFrameWithPaths(this.characterAvatar, pathsToTry, 0);
         }
         
+        // 获取更详细的NPC信息并显示
+        this.updateDetailedNPCInfo(data.characterId);
+        
         // 显示面板
         this.showPersonalInfoPanel();
     }
     
+    /**
+     * 递归尝试加载所有可能的路径
+     * @param sprite 要设置的精灵组件
+     * @param paths 尝试的路径数组
+     * @param index 当前尝试的路径索引
+     */
+    private tryLoadSpriteFrameWithPaths(sprite: Sprite, paths: string[], index: number): void {
+        if (index >= paths.length) {
+            console.error('所有可能的路径都尝试失败,使用默认图像');
+            // 所有路径都失败,创建一个默认的灰色方形作为备用
+            this.createDefaultSpriteFrame(sprite);
+            return;
+        }
+        
+        const currentPath = paths[index];
+        console.log(`PersonalInfoManager - 尝试加载路径(${index+1}/${paths.length}): ${currentPath}`);
+        
+        resources.load(currentPath, SpriteFrame, (err, spriteFrame) => {
+            if (err) {
+                console.warn(`路径加载失败: ${currentPath}`, err);
+                // 尝试下一个路径
+                this.tryLoadSpriteFrameWithPaths(sprite, paths, index + 1);
+                return;
+            }
+            
+            // 成功加载,设置spriteFrame
+            sprite.spriteFrame = spriteFrame;
+            console.log(`成功加载头像: ${currentPath}`);
+        });
+    }
+    
+    /**
+     * 创建一个默认的SpriteFrame用于显示
+     * @param sprite 要设置的精灵组件
+     */
+    private createDefaultSpriteFrame(sprite: Sprite): void {
+        console.log('创建默认图像');
+        
+        // 使用内置资源或默认资源
+        const defaultIcon = "default_sprite";
+        resources.load(defaultIcon, SpriteFrame, (err, spriteFrame) => {
+            if (err) {
+                console.warn(`无法加载默认图像 ${defaultIcon}`, err);
+                return;
+            }
+            
+            sprite.spriteFrame = spriteFrame;
+            console.log('已设置默认图像');
+        });
+    }
+    
+    /**
+     * 更新详细的NPC信息
+     * @param characterId 角色ID
+     */
+    private updateDetailedNPCInfo(characterId: number) {
+        if (!this.nameInfoLabel) return;
+        if (!this.dataManager) {
+            console.error('未设置DataManager引用');
+            return;
+        }
+        
+        // 获取NPC数据
+        const npcData = this.dataManager.getNPCById(characterId);
+        if (!npcData) {
+            console.error(`无法找到ID为${characterId}的NPC数据`);
+            return;
+        }
+        
+        // 获取通行证信息
+        const passInfo = npcData.pass;
+        
+        // 获取个人信息
+        const personalInfo = npcData.personal;
+        
+        // 构建详细信息文本
+        let detailedInfo = '';
+        
+        // 添加姓名
+        detailedInfo += `姓名: ${npcData.characterName}\n`;
+        
+        // 添加房间号
+        if (passInfo && passInfo.room) {
+            detailedInfo += `房间号: ${passInfo.room}\n`;
+        }
+        
+        // 添加ID
+        if (passInfo && passInfo.identityId) {
+            detailedInfo += `ID: ${passInfo.identityId}\n`;
+        } else if (personalInfo && personalInfo.id) {
+            detailedInfo += `ID: ${personalInfo.id}\n`;
+        }
+        
+        // 添加同住人信息
+        if (personalInfo && personalInfo.hasRoommate && personalInfo.roommate) {
+            detailedInfo += `同住人: ${personalInfo.roommate.id || '未知'}\n`;
+        } else if (personalInfo && personalInfo.hasRoommate) {
+            detailedInfo += `同住人: 有(未详)\n`;
+        } else if (personalInfo) {
+            detailedInfo += `同住人: 无\n`;
+        }
+        
+        // 设置详细信息文本
+        this.nameInfoLabel.string = detailedInfo;
+    }
+    
     onDestroy() {
         if (this.closeButton) {
             this.closeButton.node.off('click');

+ 878 - 0
assets/scripts/SummaryManager.ts

@@ -0,0 +1,878 @@
+import { _decorator, Component, Node, Label, Button, Sprite, SpriteFrame, resources, instantiate, UIOpacity, Widget, UITransform, director, Canvas, AssetManager } from 'cc';
+import { DataManager } from './DataManager';
+import { GameFlowManager } from './GameFlowManager';
+
+const { ccclass, property } = _decorator;
+
+// 定义UI详情数据接口
+interface DetailItemData {
+    name: string;
+    avatarPath: string;
+    characterId: number;
+}
+
+// 定义统计结果类型
+interface GameStats {
+    passedRealCount: number;     // 放行的邻居数量
+    dismissedFakeCount: number;  // 驱赶的伪人数量
+    passedFakeCount: number;     // 放行的伪人数量
+    dismissedRealCount: number;  // 驱赶的邻居数量
+    passedRealList: DetailItemData[];    // 放行的邻居列表
+    dismissedFakeList: DetailItemData[]; // 驱赶的伪人列表
+    passedFakeList: DetailItemData[];    // 放行的伪人列表
+    dismissedRealList: DetailItemData[]; // 驱赶的邻居列表
+    grade: string;               // 评分:A/B/C/D
+}
+
+@ccclass('SummaryManager')
+export class SummaryManager extends Component {
+    @property({
+        type: Node,
+        tooltip: '总结面板节点'
+    })
+    summaryPanel: Node = null;
+
+    @property({
+        type: Label,
+        tooltip: '放行邻居数量文本'
+    })
+    passedRealCountLabel: Label = null;
+
+    @property({
+        type: Label,
+        tooltip: '驱赶伪人数量文本'
+    })
+    dismissedFakeCountLabel: Label = null;
+
+    @property({
+        type: Label,
+        tooltip: '放行伪人数量文本'
+    })
+    passedFakeCountLabel: Label = null;
+
+    @property({
+        type: Label,
+        tooltip: '驱赶邻居数量文本'
+    })
+    dismissedRealCountLabel: Label = null;
+
+    @property({
+        type: Label,
+        tooltip: '等级评分文本'
+    })
+    gradeLabel: Label = null;
+
+    @property({
+        type: Button,
+        tooltip: '查看放行伪人详情按钮'
+    })
+    viewPassedFakeButton: Button = null;
+
+    @property({
+        type: Button,
+        tooltip: '查看驱赶邻居详情按钮'
+    })
+    viewDismissedRealButton: Button = null;
+
+    @property({
+        type: Node,
+        tooltip: '详情面板节点'
+    })
+    detailPanel: Node = null;
+
+    @property({
+        type: Label,
+        tooltip: '详情面板标题'
+    })
+    detailTitleLabel: Label = null;
+
+    @property({
+        type: Node,
+        tooltip: '详情内容容器节点'
+    })
+    detailContentContainer: Node = null;
+
+    @property({
+        type: Node,
+        tooltip: '详情条目预制体'
+    })
+    detailItemPrefab: Node = null;
+
+    @property({
+        type: Button,
+        tooltip: '详情面板关闭按钮'
+    })
+    detailCloseButton: Button = null;
+
+    @property({
+        type: Node, 
+        tooltip: '角色详情面板'
+    })
+    characterDetailPanel: Node = null;
+
+    @property({
+        type: DataManager,
+        tooltip: '数据管理器引用'
+    })
+    dataManager: DataManager = null;
+
+    @property({
+        type: Button,
+        tooltip: '确认按钮'
+    })
+    confirmButton: Button = null;
+
+    @property({
+        type: GameFlowManager,
+        tooltip: '游戏流程管理器引用'
+    })
+    gameFlowManager: GameFlowManager = null;
+
+    // 游戏统计数据
+    private gameStats: GameStats = {
+        passedRealCount: 0,
+        dismissedFakeCount: 0,
+        passedFakeCount: 0,
+        dismissedRealCount: 0,
+        passedRealList: [],
+        dismissedFakeList: [],
+        passedFakeList: [],
+        dismissedRealList: [],
+        grade: 'D'
+    };
+
+    // 当前显示的详情类型
+    private currentDetailType: 'passedFake' | 'dismissedReal' = null;
+
+    // 在SummaryManager中添加回调属性
+    public onShowCharacterDetail: (characterId: number) => void = null;
+
+    // 添加初始化标记
+    private isInitialized: boolean = false;
+
+    // 添加标记表示是否正在显示总结面板
+    private isShowingSummary: boolean = false;
+
+    start() {
+        console.log('SummaryManager.start被调用');
+        
+        // 避免重复初始化
+        if (this.isInitialized) {
+            console.log('SummaryManager已经初始化过,跳过初始化流程');
+            return;
+        }
+        
+        // 如果正在显示总结面板,跳过隐藏面板的步骤
+        if (this.isShowingSummary) {
+            console.log('总结面板正在显示中,跳过隐藏面板的初始化步骤');
+            this.isInitialized = true;
+            this.setupButtons();
+            return;
+        }
+        
+        // 检查面板引用
+        if (!this.summaryPanel) {
+            console.error('summaryPanel未被赋值,请检查Inspector中的引用设置');
+        } else {
+            console.log('summaryPanel初始状态:', this.summaryPanel.active);
+            // 初始化隐藏面板,但先记录下它的初始状态以便调试
+            this.summaryPanel.active = false;
+            console.log('summaryPanel已设置为隐藏');
+        }
+
+        if (!this.detailPanel) {
+            console.error('detailPanel未被赋值,请检查Inspector中的引用设置');
+        } else {
+            console.log('detailPanel初始状态:', this.detailPanel.active);
+            this.detailPanel.active = false;
+            console.log('detailPanel已设置为隐藏');
+        }
+
+        if (!this.characterDetailPanel) {
+            console.error('characterDetailPanel未被赋值,请检查Inspector中的引用设置');
+        } else {
+            console.log('characterDetailPanel初始状态:', this.characterDetailPanel.active);
+            this.characterDetailPanel.active = false;
+            console.log('characterDetailPanel已设置为隐藏');
+        }
+
+        // 注册按钮事件
+        this.setupButtons();
+        
+        // 标记为已初始化
+        this.isInitialized = true;
+    }
+
+    /**
+     * 设置按钮事件
+     */
+    private setupButtons(): void {
+        // 查看放行伪人详情按钮
+        if (this.viewPassedFakeButton) {
+            this.viewPassedFakeButton.node.on(Button.EventType.CLICK, () => {
+                this.showDetailPanel('passedFake');
+            }, this);
+        }
+
+        // 查看驱赶邻居详情按钮
+        if (this.viewDismissedRealButton) {
+            this.viewDismissedRealButton.node.on(Button.EventType.CLICK, () => {
+                this.showDetailPanel('dismissedReal');
+            }, this);
+        }
+
+        // 详情面板关闭按钮
+        if (this.detailCloseButton) {
+            this.detailCloseButton.node.on(Button.EventType.CLICK, () => {
+                this.hideDetailPanel();
+            }, this);
+        }
+
+        // 确认按钮
+        if (this.confirmButton) {
+            this.confirmButton.node.on(Button.EventType.CLICK, this.handleConfirmButtonClick, this);
+        } else {
+            console.error('确认按钮未设置');
+        }
+    }
+
+    /**
+     * 记录放行NPC
+     * @param npcData NPC数据
+     */
+    public recordPassedNPC(npcData: any): void {
+        if (!npcData) return;
+
+        console.log(`记录放行NPC: ${npcData.characterName}, 类型: ${npcData.type}, ID: ${npcData.characterId}`);
+
+        const detailData: DetailItemData = {
+            name: npcData.characterName,
+            avatarPath: `avatars/${npcData.characterId}/avatar_${npcData.characterId}_5`,
+            characterId: npcData.characterId
+        };
+
+        if (npcData.type === 'real') {
+            // 放行了邻居
+            this.gameStats.passedRealCount++;
+            this.gameStats.passedRealList.push(detailData);
+            console.log(`放行邻居数量增加到 ${this.gameStats.passedRealCount}`);
+        } else if (npcData.type === 'fake') {
+            // 放行了伪人
+            this.gameStats.passedFakeCount++;
+            this.gameStats.passedFakeList.push(detailData);
+            console.log(`放行伪人数量增加到 ${this.gameStats.passedFakeCount}`);
+        }
+
+        // 更新评分
+        this.updateGrade();
+    }
+
+    /**
+     * 记录驱赶NPC
+     * @param npcData NPC数据
+     */
+    public recordDismissedNPC(npcData: any): void {
+        if (!npcData) return;
+
+        console.log(`记录驱赶NPC: ${npcData.characterName}, 类型: ${npcData.type}, ID: ${npcData.characterId}`);
+
+        const detailData: DetailItemData = {
+            name: npcData.characterName,
+            avatarPath: `avatars/${npcData.characterId}/avatar_${npcData.characterId}_5`,
+            characterId: npcData.characterId
+        };
+
+        if (npcData.type === 'real') {
+            // 驱赶了邻居
+            this.gameStats.dismissedRealCount++;
+            this.gameStats.dismissedRealList.push(detailData);
+            console.log(`驱赶邻居数量增加到 ${this.gameStats.dismissedRealCount}`);
+        } else if (npcData.type === 'fake') {
+            // 驱赶了伪人
+            this.gameStats.dismissedFakeCount++;
+            this.gameStats.dismissedFakeList.push(detailData);
+            console.log(`驱赶伪人数量增加到 ${this.gameStats.dismissedFakeCount}`);
+        }
+
+        // 更新评分
+        this.updateGrade();
+    }
+
+    /**
+     * 更新评分
+     */
+    private updateGrade(): void {
+        // 计算正确决策的百分比
+        const totalDecisions = this.gameStats.passedRealCount + this.gameStats.dismissedFakeCount + 
+                             this.gameStats.passedFakeCount + this.gameStats.dismissedRealCount;
+        
+        if (totalDecisions === 0) {
+            this.gameStats.grade = 'D';
+            return;
+        }
+
+        const correctDecisions = this.gameStats.passedRealCount + this.gameStats.dismissedFakeCount;
+        const correctPercentage = (correctDecisions / totalDecisions) * 100;
+
+        // 根据正确率确定等级
+        if (correctPercentage >= 90) {
+            this.gameStats.grade = 'A';
+        } else if (correctPercentage >= 70) {
+            this.gameStats.grade = 'B';
+        } else if (correctPercentage >= 50) {
+            this.gameStats.grade = 'C';
+        } else {
+            this.gameStats.grade = 'D';
+        }
+    }
+
+    /**
+     * 显示总结面板
+     */
+    public showSummaryPanel(): void {
+        console.log('SummaryManager.showSummaryPanel被调用');
+        
+        // 尝试检查资源路径
+        this.checkAvatarResources();
+        
+        // 标记为正在显示总结面板
+        this.isShowingSummary = true;
+        
+        // 确保已初始化
+        if (!this.isInitialized) {
+            console.log('SummaryManager未初始化,执行初始化');
+            this.isInitialized = true; // 标记为已初始化,避免start中再次隐藏面板
+        }
+        
+        if (!this.summaryPanel) {
+            console.error('summaryPanel未设置');
+            return;
+        }
+        
+        // 检查summaryPanel的父节点状态
+        const parentNode = this.summaryPanel.parent;
+        if (parentNode) {
+            console.log('summaryPanel父节点状态:', parentNode.name, '激活状态:', parentNode.active);
+            // 确保父节点也是激活的
+            if (!parentNode.active) {
+                console.log('激活summaryPanel的父节点');
+                parentNode.active = true;
+            }
+        } else {
+            console.error('summaryPanel没有父节点');
+        }
+        
+        // 强制设置可见性相关属性
+        this.summaryPanel.active = true;
+        
+        // 确保位于最顶层
+        this.summaryPanel.setSiblingIndex(999);
+        
+        // 尝试强制将面板移动到场景顶层
+        this.forceMoveToTop();
+        
+        // 如果节点有UIOpacity组件,确保不透明
+        const opacityComp = this.summaryPanel.getComponent(UIOpacity);
+        if (opacityComp) {
+            console.log('设置summaryPanel的不透明度为255');
+            opacityComp.opacity = 255;
+        }
+        
+        // 如果有widget组件,可能需要更新对齐
+        const widgetComp = this.summaryPanel.getComponent(Widget);
+        if (widgetComp) {
+            console.log('更新summaryPanel的Widget对齐');
+            widgetComp.updateAlignment();
+        }
+
+        // 检查summaryPanel的位置和大小
+        console.log('summaryPanel位置:', this.summaryPanel.position);
+        const uiTransform = this.summaryPanel.getComponent(UITransform);
+        if (uiTransform) {
+            console.log('summaryPanel大小:', uiTransform.contentSize);
+        } else {
+            console.log('summaryPanel没有UITransform组件');
+        }
+        console.log('summaryPanel缩放:', this.summaryPanel.scale);
+        console.log('summaryPanel角度:', this.summaryPanel.angle);
+        console.log('summaryPanel激活状态:', this.summaryPanel.active);
+
+        // 检查summaryPanel的子节点状态
+        const children = this.summaryPanel.children;
+        console.log(`summaryPanel有 ${children.length} 个子节点`);
+        children.forEach((child, index) => {
+            console.log(`子节点 ${index}: ${child.name}, 激活状态: ${child.active}`);
+        });
+
+        // 更新UI显示
+        this.updateSummaryUI();
+        
+        console.log('成功激活summaryPanel,位置:', this.summaryPanel.position);
+        
+        // 添加延迟操作,确保UI正确显示
+        this.scheduleOnce(() => {
+            console.log('延迟处理:再次确认summaryPanel是否显示');
+            if (this.summaryPanel) {
+                if (!this.summaryPanel.active) {
+                    console.log('延迟处理:summaryPanel未激活,尝试再次激活');
+                    this.summaryPanel.active = true;
+                }
+                
+                // 再次确保位于最顶层
+                this.summaryPanel.setSiblingIndex(999);
+                
+                // 再次强制更新UI显示
+                this.updateSummaryUI();
+                
+                console.log('延迟处理:summaryPanel状态:', this.summaryPanel.active);
+            }
+        }, 0.1); // 延迟0.1秒
+    }
+
+    /**
+     * 强制将总结面板移动到场景最顶层
+     */
+    private forceMoveToTop(): void {
+        console.log('尝试强制将总结面板移动到最顶层');
+        
+        // 查找当前场景的Canvas
+        const scene = director.getScene();
+        if (!scene) {
+            console.error('无法获取当前场景');
+            return;
+        }
+        
+        console.log('当前场景:', scene.name);
+        
+        // 遍历场景节点查找Canvas
+        let canvasNode = null;
+        const findCanvas = (node: Node) => {
+            if (node.getComponent(Canvas)) {
+                canvasNode = node;
+                return true;
+            }
+            
+            for (let i = 0; i < node.children.length; i++) {
+                if (findCanvas(node.children[i])) {
+                    return true;
+                }
+            }
+            
+            return false;
+        };
+        
+        findCanvas(scene);
+        
+        if (canvasNode) {
+            console.log('找到Canvas节点:', canvasNode.name);
+            
+            // 如果summaryPanel不在Canvas下,尝试将其移动到Canvas
+            if (this.summaryPanel.parent !== canvasNode) {
+                console.log('summaryPanel不在Canvas下,尝试移动');
+                
+                // 保存原始父节点以便恢复
+                const originalParent = this.summaryPanel.parent;
+                
+                // 记录当前位置
+                const originalPosition = this.summaryPanel.position.clone();
+                
+                // 尝试将面板添加到Canvas
+                this.summaryPanel.parent = canvasNode;
+                this.summaryPanel.setSiblingIndex(canvasNode.children.length - 1);
+                
+                console.log('summaryPanel已移动到Canvas下,索引:', this.summaryPanel.getSiblingIndex());
+            } else {
+                console.log('summaryPanel已在Canvas下,设置最高索引');
+                this.summaryPanel.setSiblingIndex(canvasNode.children.length - 1);
+            }
+        } else {
+            console.error('场景中未找到Canvas节点');
+        }
+    }
+
+    /**
+     * 隐藏总结面板
+     */
+    public hideSummaryPanel(): void {
+        console.log('SummaryManager.hideSummaryPanel被调用');
+        
+        // 更新显示标志
+        this.isShowingSummary = false;
+        
+        if (this.summaryPanel) {
+            this.summaryPanel.active = false;
+            console.log('总结面板已隐藏');
+        } else {
+            console.error('summaryPanel未设置,无法隐藏');
+        }
+    }
+
+    /**
+     * 更新总结UI显示
+     */
+    private updateSummaryUI(): void {
+        console.log('updateSummaryUI被调用,准备更新UI显示');
+        
+        // 检查标签引用是否存在
+        if (!this.passedRealCountLabel) {
+            console.error('passedRealCountLabel未设置');
+        } else {
+            console.log(`设置放行邻居数量: ${this.gameStats.passedRealCount}`);
+            this.passedRealCountLabel.string = String(this.gameStats.passedRealCount);
+        }
+
+        if (!this.dismissedFakeCountLabel) {
+            console.error('dismissedFakeCountLabel未设置');
+        } else {
+            console.log(`设置驱赶伪人数量: ${this.gameStats.dismissedFakeCount}`);
+            this.dismissedFakeCountLabel.string = String(this.gameStats.dismissedFakeCount);
+        }
+
+        if (!this.passedFakeCountLabel) {
+            console.error('passedFakeCountLabel未设置');
+        } else {
+            console.log(`设置放行伪人数量: ${this.gameStats.passedFakeCount}`);
+            this.passedFakeCountLabel.string = String(this.gameStats.passedFakeCount);
+        }
+
+        if (!this.dismissedRealCountLabel) {
+            console.error('dismissedRealCountLabel未设置');
+        } else {
+            console.log(`设置驱赶邻居数量: ${this.gameStats.dismissedRealCount}`);
+            this.dismissedRealCountLabel.string = String(this.gameStats.dismissedRealCount);
+        }
+
+        // 更新等级评分
+        if (!this.gradeLabel) {
+            console.error('gradeLabel未设置');
+        } else {
+            console.log(`设置评分等级: ${this.gameStats.grade}`);
+            this.gradeLabel.string = this.gameStats.grade;
+        }
+        
+        // 检查按钮状态
+        console.log(`放行伪人列表数量: ${this.gameStats.passedFakeList.length}`);
+        if (this.viewPassedFakeButton) {
+            // 根据列表是否有内容来启用/禁用按钮
+            this.viewPassedFakeButton.interactable = this.gameStats.passedFakeList.length > 0;
+            console.log(`设置放行伪人详情按钮状态: ${this.viewPassedFakeButton.interactable}`);
+        } else {
+            console.error('viewPassedFakeButton未设置');
+        }
+        
+        console.log(`驱赶邻居列表数量: ${this.gameStats.dismissedRealList.length}`);
+        if (this.viewDismissedRealButton) {
+            // 根据列表是否有内容来启用/禁用按钮
+            this.viewDismissedRealButton.interactable = this.gameStats.dismissedRealList.length > 0;
+            console.log(`设置驱赶邻居详情按钮状态: ${this.viewDismissedRealButton.interactable}`);
+        } else {
+            console.error('viewDismissedRealButton未设置');
+        }
+        
+        console.log('UI显示更新完成');
+    }
+
+    /**
+     * 显示详情面板
+     * @param detailType 详情类型
+     */
+    private showDetailPanel(detailType: 'passedFake' | 'dismissedReal'): void {
+        if (!this.detailPanel || !this.detailContentContainer) return;
+
+        this.currentDetailType = detailType;
+
+        // 设置标题
+        if (this.detailTitleLabel) {
+            this.detailTitleLabel.string = detailType === 'passedFake' ? '放进来的伪人' : '驱赶的邻居';
+        }
+
+        // 清空容器
+        this.detailContentContainer.removeAllChildren();
+
+        // 获取详情列表
+        const detailList = detailType === 'passedFake' ? 
+            this.gameStats.passedFakeList : this.gameStats.dismissedRealList;
+
+        // 创建详情条目
+        detailList.forEach(detail => {
+            this.createDetailItem(detail);
+        });
+
+        // 显示面板
+        this.detailPanel.active = true;
+        this.detailPanel.setSiblingIndex(1000); // 确保显示在总结面板之上
+    }
+
+    /**
+     * 隐藏详情面板
+     */
+    private hideDetailPanel(): void {
+        if (this.detailPanel) {
+            this.detailPanel.active = false;
+        }
+    }
+
+    /**
+     * 创建详情条目
+     * @param detailData 详情数据
+     */
+    private createDetailItem(detailData: DetailItemData): void {
+        if (!this.detailItemPrefab || !this.detailContentContainer) return;
+
+        console.log(`创建详情条目: ${detailData.name}, 头像路径: ${detailData.avatarPath}, 类型: ${this.currentDetailType}`);
+
+        // 实例化预制体
+        const itemNode = instantiate(this.detailItemPrefab);
+        this.detailContentContainer.addChild(itemNode);
+
+        // 设置名称
+        const nameLabel = itemNode.getChildByName('Name')?.getComponent(Label);
+        if (nameLabel) {
+            nameLabel.string = detailData.name;
+        }
+
+        // 设置头像
+        const avatarSprite = itemNode.getChildByName('Avatar')?.getComponent(Sprite);
+        if (avatarSprite) {
+            // 列出所有可能尝试的路径格式
+            let pathsToTry = [];
+            
+            if (this.currentDetailType === 'passedFake') {
+                // 如果是"放行的伪人",使用黑影图片
+                console.log('加载黑影头像');
+                pathsToTry = [
+                    'avatars/black/spriteFrame',
+                    'avatars/black',
+                    'avatars/黑影/spriteFrame',
+                    'avatars/黑影',
+                    'black/spriteFrame',
+                    'black',
+                    '黑影/spriteFrame',
+                    '黑影'
+                ];
+            } else {
+                // 如果是"驱赶的邻居"或其他,正常加载头像
+                console.log(`加载角色头像: ${detailData.avatarPath}`);
+                const baseAvatarPath = detailData.avatarPath;
+                pathsToTry = [
+                    `${baseAvatarPath}/spriteFrame`,
+                    baseAvatarPath,
+                    `avatars/${detailData.characterId}/avatar_${detailData.characterId}_5/spriteFrame`,
+                    `avatars/${detailData.characterId}/avatar_${detailData.characterId}_5`,
+                    `avatars/${detailData.characterId}/spriteFrame`,
+                    `avatars/${detailData.characterId}`
+                ];
+            }
+            
+            // 递归尝试加载所有可能的路径
+            this.tryLoadSpriteFrameWithPaths(avatarSprite, pathsToTry, 0);
+        }
+
+        // 设置查看详情按钮事件
+        const detailButton = itemNode.getChildByName('DetailButton')?.getComponent(Button);
+        if (detailButton) {
+            detailButton.node.on(Button.EventType.CLICK, () => {
+                this.showCharacterDetail(detailData.characterId);
+            }, this);
+        }
+    }
+    
+    /**
+     * 递归尝试加载所有可能的路径
+     * @param sprite 要设置的精灵组件
+     * @param paths 尝试的路径数组
+     * @param index 当前尝试的路径索引
+     */
+    private tryLoadSpriteFrameWithPaths(sprite: Sprite, paths: string[], index: number): void {
+        if (index >= paths.length) {
+            console.error('所有可能的路径都尝试失败,使用默认图像');
+            // 所有路径都失败,创建一个默认的灰色方形作为备用
+            this.createDefaultSpriteFrame(sprite);
+            return;
+        }
+        
+        const currentPath = paths[index];
+        console.log(`尝试加载路径(${index+1}/${paths.length}): ${currentPath}`);
+        
+        resources.load(currentPath, SpriteFrame, (err, spriteFrame) => {
+            if (err) {
+                console.warn(`路径加载失败: ${currentPath}`, err);
+                // 尝试下一个路径
+                this.tryLoadSpriteFrameWithPaths(sprite, paths, index + 1);
+                return;
+            }
+            
+            // 成功加载,设置spriteFrame
+            sprite.spriteFrame = spriteFrame;
+            console.log(`成功加载头像: ${currentPath}`);
+        });
+    }
+    
+    /**
+     * 创建一个默认的SpriteFrame用于显示
+     * @param sprite 要设置的精灵组件
+     */
+    private createDefaultSpriteFrame(sprite: Sprite): void {
+        console.log('创建默认图像');
+        
+        // 使用内置资源或默认资源
+        const defaultIcon = "default_sprite";
+        resources.load(defaultIcon, SpriteFrame, (err, spriteFrame) => {
+            if (err) {
+                console.warn(`无法加载默认图像 ${defaultIcon}`, err);
+                return;
+            }
+            
+            sprite.spriteFrame = spriteFrame;
+            console.log('已设置默认图像');
+        });
+    }
+
+    /**
+     * 显示角色详情
+     * @param characterId 角色ID
+     */
+    private showCharacterDetail(characterId: number): void {
+        if (!this.characterDetailPanel) return;
+        
+        console.log(`显示角色详情: ID=${characterId}`);
+        
+        // 获取角色数据
+        const npcData = this.dataManager.getNPCById(characterId);
+        if (!npcData) {
+            console.error(`无法找到ID为${characterId}的NPC数据`);
+            return;
+        }
+        
+        console.log(`找到NPC数据: ${npcData.characterName}`);
+        
+        // 通过事件系统通知GameFlow处理
+        // 或者提供一个回调函数由GameFlow注入
+        if (this.onShowCharacterDetail) {
+            console.log(`调用onShowCharacterDetail回调函数显示角色详情`);
+            this.onShowCharacterDetail(characterId);
+        } else {
+            console.error(`onShowCharacterDetail回调未设置,无法显示角色详情`);
+        }
+    }
+
+    /**
+     * 重置统计数据
+     */
+    public resetStats(): void {
+        console.log('SummaryManager.resetStats被调用,重置统计数据');
+        
+        this.gameStats = {
+            passedRealCount: 0,
+            dismissedFakeCount: 0,
+            passedFakeCount: 0,
+            dismissedRealCount: 0,
+            passedRealList: [],
+            dismissedFakeList: [],
+            passedFakeList: [],
+            dismissedRealList: [],
+            grade: 'D'
+        };
+        
+        // 重置显示标志,但不要隐藏面板
+        this.isShowingSummary = false;
+        
+        console.log('统计数据已重置');
+    }
+
+    /**
+     * 处理确认按钮点击
+     */
+    private handleConfirmButtonClick(): void {
+        console.log('确认按钮被点击,准备切换到下一关');
+        
+        // 隐藏当前面板
+        this.hideSummaryPanel();
+        
+        // 检查游戏流程管理器是否存在
+        if (!this.gameFlowManager) {
+            console.error('游戏流程管理器未设置,无法切换到下一关');
+            return;
+        }
+        
+        // 使用DataManager切换到下一关
+        if (this.dataManager) {
+            // 先重置统计数据
+            this.resetStats();
+            
+            // 切换到下一关
+            const hasNextLevel = this.dataManager.nextLevel();
+            
+            if (hasNextLevel) {
+                console.log('成功切换到下一关,准备开始新关卡');
+                
+                // 重新开始游戏流程
+                this.gameFlowManager.restartGameFlow();
+            } else {
+                console.log('已经是最后一关,游戏结束');
+                // 这里可以添加游戏结束的处理逻辑
+                // 例如显示通关画面等
+            }
+        } else {
+            console.error('DataManager未设置,无法切换关卡');
+        }
+    }
+
+    onEnable() {
+        console.log('SummaryManager.onEnable被调用');
+        
+        // 如果正在显示总结面板,确保面板保持显示状态
+        if (this.isShowingSummary && this.summaryPanel) {
+            console.log('onEnable: 总结面板正在显示中,确保保持显示状态');
+            this.summaryPanel.active = true;
+        }
+    }
+
+    onDestroy() {
+        // 清理按钮事件
+        if (this.viewPassedFakeButton) {
+            this.viewPassedFakeButton.node.off(Button.EventType.CLICK);
+        }
+
+        if (this.viewDismissedRealButton) {
+            this.viewDismissedRealButton.node.off(Button.EventType.CLICK);
+        }
+
+        if (this.detailCloseButton) {
+            this.detailCloseButton.node.off(Button.EventType.CLICK);
+        }
+        
+        if (this.confirmButton) {
+            this.confirmButton.node.off(Button.EventType.CLICK, this.handleConfirmButtonClick, this);
+        }
+    }
+
+    /**
+     * 检查头像资源目录结构
+     */
+    private checkAvatarResources(): void {
+        console.log('检查avatars资源目录结构...');
+        
+        // 检查black图片是否存在
+        resources.load('avatars/black/spriteFrame', SpriteFrame, (err, asset) => {
+            if (err) {
+                console.error('avatars/black不存在', err);
+            } else {
+                console.log('成功加载avatars/black');
+            }
+        });
+        
+        // 尝试列出avatars目录下的内容
+        resources.loadDir('avatars', (err, assets) => {
+            if (err) {
+                console.error('无法加载avatars目录', err);
+                return;
+            }
+            
+            console.log(`avatars目录中有 ${assets.length} 个资源:`);
+            assets.forEach((asset, index) => {
+                console.log(`${index + 1}. ${asset.name} (类型: ${typeof asset})`);
+            });
+        });
+    }
+} 

+ 9 - 0
assets/scripts/SummaryManager.ts.meta

@@ -0,0 +1,9 @@
+{
+  "ver": "4.0.24",
+  "importer": "typescript",
+  "imported": true,
+  "uuid": "e87542e4-3eac-44d4-a699-67fb82616fe9",
+  "files": [],
+  "subMetas": {},
+  "userData": {}
+}

Một số tệp đã không được hiển thị bởi vì quá nhiều tập tin thay đổi trong này khác