GameFlowManager.ts 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640
  1. import { _decorator, Component, Node, resources, sp, Asset, Button } from 'cc';
  2. import { DataManager } from './DataManager';
  3. import { CharacterManager } from './CharacterManager';
  4. import { QuestionAnswerManager } from './QuestionAnswerManager';
  5. import { AvatarManager } from './AvatarManager';
  6. import { PassCardManager } from './PassCardManager';
  7. import { PhoneManager } from './PhoneManager';
  8. import { RosterManager } from './RosterManager';
  9. import { PersonalInfoManager } from './PersonalInfoManager';
  10. import { LieDetectorManager } from './LieDetectorManager';
  11. import { GameLifeManager } from './GameLifeManager';
  12. import { SummaryManager } from './SummaryManager';
  13. const { ccclass, property } = _decorator;
  14. @ccclass('GameFlowManager')
  15. export class GameFlowManager extends Component {
  16. @property({
  17. type: DataManager,
  18. tooltip: '数据管理器引用'
  19. })
  20. dataManager: DataManager = null;
  21. @property({
  22. type: CharacterManager,
  23. tooltip: '角色管理器引用'
  24. })
  25. characterManager: CharacterManager = null;
  26. @property({
  27. type: QuestionAnswerManager,
  28. tooltip: '问答管理器引用'
  29. })
  30. questionAnswerManager: QuestionAnswerManager = null;
  31. @property({
  32. type: Button,
  33. tooltip: '放行按钮'
  34. })
  35. allowButton: Button = null;
  36. @property({
  37. type: Button,
  38. tooltip: '赶走按钮'
  39. })
  40. dismissButton: Button = null;
  41. @property({
  42. type: AvatarManager,
  43. tooltip: '头像管理器引用'
  44. })
  45. avatarManager: AvatarManager = null;
  46. @property({
  47. type: PassCardManager,
  48. tooltip: '通行证管理器引用'
  49. })
  50. passCardManager: PassCardManager = null;
  51. @property({
  52. type: PhoneManager,
  53. tooltip: '电话管理器引用'
  54. })
  55. phoneManager: PhoneManager = null;
  56. @property({
  57. type: RosterManager,
  58. tooltip: '名单管理器引用'
  59. })
  60. rosterManager: RosterManager = null;
  61. @property({
  62. type: PersonalInfoManager,
  63. tooltip: '个人资料管理器引用'
  64. })
  65. personalInfoManager: PersonalInfoManager = null;
  66. @property({
  67. type: LieDetectorManager,
  68. tooltip: '测谎仪管理器引用'
  69. })
  70. lieDetectorManager: LieDetectorManager = null;
  71. @property({
  72. type: GameLifeManager,
  73. tooltip: '游戏生命值管理器引用'
  74. })
  75. gameLifeManager: GameLifeManager = null;
  76. @property({
  77. type: SummaryManager,
  78. tooltip: '总结管理器引用'
  79. })
  80. summaryManager: SummaryManager = null;
  81. // 当前关卡中的NPC索引
  82. private currentNpcIndex: number = -1;
  83. // 当前关卡的NPC列表
  84. private currentNpcs: any[] = [];
  85. start() {
  86. // 初始化UI管理器
  87. this.initUIManagers();
  88. // 注册按钮事件
  89. this.registerButtonEvents();
  90. // 设置生命值管理器回调
  91. this.setupLifeManagerCallbacks();
  92. // 开始游戏流程
  93. this.startGameFlow();
  94. }
  95. /**
  96. * 初始化UI管理器
  97. */
  98. private initUIManagers(): void {
  99. // 检查通行证管理器是否被正确引用
  100. if (!this.passCardManager) {
  101. console.error('通行证管理器未设置');
  102. }
  103. // 检查电话管理器是否被正确引用
  104. if (!this.phoneManager) {
  105. console.error('电话管理器未设置');
  106. }
  107. // 检查名单管理器是否被正确引用
  108. if (!this.rosterManager) {
  109. console.error('名单管理器未设置');
  110. }
  111. // 检查个人资料管理器是否被正确引用
  112. if (!this.personalInfoManager) {
  113. console.error('个人资料管理器未设置');
  114. } else if (this.dataManager) {
  115. // 设置DataManager引用
  116. this.personalInfoManager.dataManager = this.dataManager;
  117. }
  118. // 检查测谎仪管理器是否被正确引用
  119. if (!this.lieDetectorManager) {
  120. console.error('测谎仪管理器未设置');
  121. }
  122. // 检查生命值管理器是否被正确引用
  123. if (!this.gameLifeManager) {
  124. console.error('生命值管理器未设置');
  125. }
  126. // 检查总结管理器是否被正确引用
  127. if (!this.summaryManager) {
  128. console.error('总结管理器未设置');
  129. }
  130. console.log('所有UI管理器已初始化');
  131. if (this.summaryManager) {
  132. this.summaryManager.onShowCharacterDetail = (characterId) => {
  133. const npcData = this.dataManager.getNPCById(characterId);
  134. if (!npcData) return;
  135. // 确保PersonalInfoManager有DataManager引用
  136. if (this.personalInfoManager && this.dataManager) {
  137. this.personalInfoManager.dataManager = this.dataManager;
  138. console.log(`在SummaryManager中显示角色详情: ID=${characterId}, 名称=${npcData.characterName}`);
  139. this.personalInfoManager.displayCharacterInfo({
  140. characterId: npcData.characterId,
  141. info: npcData.personal?.info || "无个人资料",
  142. avatarPath: `avatars/${npcData.characterId}/avatar_${npcData.characterId}_5`
  143. });
  144. this.personalInfoManager.showPersonalInfoPanel();
  145. }
  146. };
  147. }
  148. }
  149. /**
  150. * 注册按钮事件
  151. */
  152. private registerButtonEvents(): void {
  153. // 注册放行按钮点击事件
  154. if (this.allowButton) {
  155. this.allowButton.node.on(Button.EventType.CLICK, this.handleCharacterPassed, this);
  156. } else {
  157. console.error('放行按钮未设置');
  158. }
  159. // 注册赶走按钮点击事件
  160. if (this.dismissButton) {
  161. this.dismissButton.node.on(Button.EventType.CLICK, this.handleCharacterDismissed, this);
  162. } else {
  163. console.error('赶走按钮未设置');
  164. }
  165. }
  166. /**
  167. * 设置生命值管理器回调
  168. */
  169. private setupLifeManagerCallbacks(): void {
  170. if (this.gameLifeManager) {
  171. this.gameLifeManager.setCallbacks(
  172. // 复活后的回调,继续游戏流程
  173. () => {
  174. console.log('玩家已复活,继续游戏');
  175. // 重新启用按钮
  176. this.enableButtons();
  177. },
  178. // 游戏结束的回调,显示当天总结
  179. () => {
  180. console.log('游戏结束,显示当天总结');
  181. // 禁用按钮
  182. this.disableButtons();
  183. }
  184. );
  185. }
  186. }
  187. /**
  188. * 重新开始游戏流程
  189. * 在切换关卡后调用此方法重新开始游戏
  190. */
  191. public restartGameFlow(): void {
  192. console.log('GameFlowManager.restartGameFlow被调用,重新开始游戏流程');
  193. // 重置NPC索引
  194. this.currentNpcIndex = -1;
  195. // 获取新关卡数据
  196. const currentLevel = this.dataManager.getCurrentLevel();
  197. if (!currentLevel) {
  198. console.error('无法获取当前关卡数据');
  199. return;
  200. }
  201. console.log(`开始关卡: ${currentLevel.name}`);
  202. // 从关卡NPC列表中随机选择NPC
  203. this.setupRandomNpcs(currentLevel);
  204. // 如果有生命值管理器,重置状态和生命值
  205. if (this.gameLifeManager) {
  206. // 重置总结面板显示状态
  207. this.gameLifeManager.resetSummaryPanelState();
  208. // 重置生命值
  209. this.gameLifeManager.resetLife();
  210. }
  211. // 显示第一个NPC
  212. this.showNextNpc();
  213. }
  214. /**
  215. * 从关卡NPC列表中随机选择NPC
  216. * @param levelData 关卡数据
  217. */
  218. private setupRandomNpcs(levelData: any): void {
  219. if (!levelData || !levelData.npcs || !Array.isArray(levelData.npcs)) {
  220. console.error('关卡数据中缺少有效的NPC列表');
  221. this.currentNpcs = [];
  222. return;
  223. }
  224. // 获取原始NPC列表的副本
  225. const allNpcs = [...levelData.npcs];
  226. // 打乱NPC顺序
  227. this.shuffleArray(allNpcs);
  228. // 获取要选择的NPC数量
  229. const randomNpcCount = levelData.randomNpcCount || allNpcs.length;
  230. console.log(`本关卡需要随机选择 ${randomNpcCount} 个角色`);
  231. // 选择指定数量的NPC
  232. this.currentNpcs = allNpcs.slice(0, randomNpcCount);
  233. console.log(`已随机选择 ${this.currentNpcs.length} 个角色`);
  234. }
  235. /**
  236. * 随机打乱数组顺序
  237. * @param array 要打乱的数组
  238. */
  239. private shuffleArray(array: any[]): void {
  240. for (let i = array.length - 1; i > 0; i--) {
  241. // 生成随机索引
  242. const j = Math.floor(Math.random() * (i + 1));
  243. // 交换元素
  244. [array[i], array[j]] = [array[j], array[i]];
  245. }
  246. }
  247. /**
  248. * 开始游戏流程
  249. */
  250. private startGameFlow(): void {
  251. // 获取当前关卡数据
  252. const currentLevel = this.dataManager.getCurrentLevel();
  253. if (!currentLevel) {
  254. console.error('无法获取当前关卡数据');
  255. return;
  256. }
  257. console.log(`开始关卡: ${currentLevel.name}`);
  258. // 从关卡NPC列表中随机选择NPC
  259. this.setupRandomNpcs(currentLevel);
  260. // 显示第一个NPC
  261. this.showNextNpc();
  262. }
  263. /**
  264. * 显示下一个NPC
  265. */
  266. public showNextNpc(): void {
  267. // 如果已经显示了总结面板,不再继续处理NPC
  268. if (this.gameLifeManager && this.gameLifeManager.hasSummaryPanelShown()) {
  269. console.log('总结面板已显示,不再继续处理NPC');
  270. return;
  271. }
  272. this.currentNpcIndex++;
  273. // 检查是否还有NPC
  274. if (this.currentNpcIndex >= this.currentNpcs.length) {
  275. console.log('当前关卡所有NPC已处理完毕');
  276. // 显示总结面板
  277. if (this.summaryManager) {
  278. if (this.gameLifeManager) {
  279. this.gameLifeManager.showSummaryPanel();
  280. } else {
  281. this.summaryManager.showSummaryPanel();
  282. }
  283. }
  284. return;
  285. }
  286. // 获取当前NPC数据
  287. const npc = this.currentNpcs[this.currentNpcIndex];
  288. // 配置问答对
  289. this.setupQuestionAnswers(npc.qaPairs);
  290. // 如果有头像管理器,先加载头像
  291. if (this.avatarManager) {
  292. this.avatarManager.loadAvatar(npc.characterId);
  293. }
  294. // 配置角色外观,并在完成后让角色入场
  295. this.characterManager.setupCharacterAppearance(npc.characterId, npc.skinName, () => {
  296. // 让角色入场(只有在外观设置完成后才执行)
  297. this.characterManager.characterEnter();
  298. // 启用按钮
  299. this.enableButtons();
  300. });
  301. }
  302. /**
  303. * 启用决策按钮
  304. */
  305. private enableButtons(): void {
  306. if (this.allowButton) {
  307. this.allowButton.interactable = true;
  308. }
  309. if (this.dismissButton) {
  310. this.dismissButton.interactable = true;
  311. }
  312. }
  313. /**
  314. * 禁用决策按钮
  315. */
  316. private disableButtons(): void {
  317. if (this.allowButton) {
  318. this.allowButton.interactable = false;
  319. }
  320. if (this.dismissButton) {
  321. this.dismissButton.interactable = false;
  322. }
  323. }
  324. /**
  325. * 设置问答对
  326. * @param qaPairs 问答对数组
  327. */
  328. private setupQuestionAnswers(qaPairs: any[]): void {
  329. if (!this.questionAnswerManager) {
  330. console.error('问答管理器未设置');
  331. return;
  332. }
  333. // 替换所有问答对(而不是添加)
  334. this.questionAnswerManager.replaceAllQuestionAnswers(qaPairs);
  335. }
  336. /**
  337. * 处理放行角色
  338. */
  339. public handleCharacterPassed(): void {
  340. // 禁用按钮,防止连续点击
  341. this.disableButtons();
  342. // 获取当前NPC数据
  343. const npcData = this.getCurrentNpcData();
  344. // 记录放行统计
  345. if (this.summaryManager && npcData) {
  346. this.summaryManager.recordPassedNPC(npcData);
  347. }
  348. // 检查是否放行了假角色,如果是则扣除生命值
  349. if (npcData && npcData.type === 'fake') {
  350. console.log('错误:放行了伪装者');
  351. if (this.gameLifeManager) {
  352. this.gameLifeManager.decreaseLife(1);
  353. // 如果生命值为0,则不继续游戏流程,等待失败面板处理
  354. if (this.gameLifeManager.getCurrentLife() <= 0) {
  355. return;
  356. }
  357. }
  358. }
  359. // 让角色向右移动,动画完成后显示下一个NPC
  360. this.characterManager.moveCharacterRight(() => {
  361. this.showNextNpc();
  362. });
  363. }
  364. /**
  365. * 处理赶走角色
  366. */
  367. public handleCharacterDismissed(): void {
  368. // 禁用按钮,防止连续点击
  369. this.disableButtons();
  370. // 获取当前NPC数据
  371. const npcData = this.getCurrentNpcData();
  372. // 记录驱赶统计
  373. if (this.summaryManager && npcData) {
  374. this.summaryManager.recordDismissedNPC(npcData);
  375. }
  376. // 检查是否赶走了真角色,如果是则扣除生命值
  377. if (npcData && npcData.type === 'real') {
  378. console.log('错误:赶走了真实角色');
  379. if (this.gameLifeManager) {
  380. this.gameLifeManager.decreaseLife(1);
  381. // 如果生命值为0,则不继续游戏流程,等待失败面板处理
  382. if (this.gameLifeManager.getCurrentLife() <= 0) {
  383. return;
  384. }
  385. }
  386. }
  387. // 让角色向左移动,动画完成后显示下一个NPC
  388. this.characterManager.moveCharacterLeft(() => {
  389. this.showNextNpc();
  390. });
  391. }
  392. /**
  393. * 获取当前NPC数据
  394. * @returns 当前NPC数据,如果没有则返回null
  395. */
  396. public getCurrentNpcData(): any {
  397. if (this.currentNpcIndex < 0 || this.currentNpcIndex >= this.currentNpcs.length) {
  398. return null;
  399. }
  400. return this.currentNpcs[this.currentNpcIndex];
  401. }
  402. /**
  403. * 获取通行证管理器
  404. * @returns 通行证管理器实例
  405. */
  406. public getPassCardManager(): PassCardManager {
  407. return this.passCardManager;
  408. }
  409. /**
  410. * 获取电话管理器
  411. * @returns 电话管理器实例
  412. */
  413. public getPhoneManager(): PhoneManager {
  414. return this.phoneManager;
  415. }
  416. /**
  417. * 获取名单管理器
  418. * @returns 名单管理器实例
  419. */
  420. public getRosterManager(): RosterManager {
  421. return this.rosterManager;
  422. }
  423. /**
  424. * 获取个人资料管理器
  425. * @returns 个人资料管理器实例
  426. */
  427. public getPersonalInfoManager(): PersonalInfoManager {
  428. return this.personalInfoManager;
  429. }
  430. /**
  431. * 获取测谎仪管理器
  432. * @returns 测谎仪管理器实例
  433. */
  434. public getLieDetectorManager(): LieDetectorManager {
  435. return this.lieDetectorManager;
  436. }
  437. /**
  438. * 显示通行证
  439. * @param passData 通行证数据
  440. */
  441. public showPassCard(passData: any): void {
  442. if (this.passCardManager) {
  443. this.passCardManager.showPassCard(passData);
  444. } else {
  445. console.error('通行证管理器未设置,无法显示通行证');
  446. }
  447. }
  448. /**
  449. * 显示电话对话框
  450. */
  451. public showPhoneUI(): void {
  452. if (this.phoneManager) {
  453. this.phoneManager.showPhonePanel();
  454. } else {
  455. console.error('电话管理器未设置,无法显示电话UI');
  456. }
  457. }
  458. /**
  459. * 显示名单面板
  460. */
  461. public showRosterPanel(): void {
  462. if (this.rosterManager) {
  463. // 获取今日名单数据并传递给RosterManager
  464. const todayList = this.dataManager.getTodayList();
  465. this.rosterManager.setTodayList(todayList);
  466. this.rosterManager.showRosterPanel();
  467. } else {
  468. console.error('名单管理器未设置,无法显示名单面板');
  469. }
  470. }
  471. /**
  472. * 获取当前关卡名单数据并显示
  473. * 此方法已弃用,请直接使用showRosterPanel
  474. * @deprecated
  475. */
  476. public showCurrentLevelRoster(): void {
  477. this.showRosterPanel();
  478. }
  479. /**
  480. * 显示当前NPC的个人资料
  481. */
  482. public showCurrentNpcPersonalInfo(): void {
  483. // 获取当前NPC数据
  484. const npcData = this.getCurrentNpcData();
  485. if (!npcData) {
  486. console.error('无法获取当前NPC数据');
  487. return;
  488. }
  489. console.log(`显示当前NPC资料: ID=${npcData.characterId}, 名称=${npcData.characterName}`);
  490. // 确保PersonalInfoManager已设置DataManager引用
  491. if (this.personalInfoManager && this.dataManager) {
  492. // 设置DataManager引用
  493. this.personalInfoManager.dataManager = this.dataManager;
  494. // 显示个人资料
  495. this.personalInfoManager.displayCharacterInfo({
  496. characterId: npcData.characterId,
  497. info: npcData.personal?.info || "无个人资料",
  498. avatarPath: `avatars/${npcData.characterId}/avatar_${npcData.characterId}_5`
  499. });
  500. } else {
  501. console.error('个人资料管理器或数据管理器未设置');
  502. }
  503. }
  504. /**
  505. * 显示测谎仪面板
  506. */
  507. public showLieDetectorPanel(): void {
  508. // 获取当前NPC数据
  509. const npcData = this.getCurrentNpcData();
  510. if (!npcData) {
  511. console.error('无法获取当前NPC数据');
  512. return;
  513. }
  514. // 设置测谎仪状态并显示
  515. if (this.lieDetectorManager) {
  516. // 从NPC数据中获取是否为伪装者的状态
  517. const isFake = npcData.type === 'fake';
  518. // 设置当前角色状态
  519. this.lieDetectorManager.setCharacterStatus(isFake);
  520. // 显示测谎仪面板
  521. this.lieDetectorManager.showLieDetectorPanel();
  522. } else {
  523. console.error('测谎仪管理器未设置');
  524. }
  525. }
  526. /**
  527. * 组件销毁时清理事件监听
  528. */
  529. onDestroy() {
  530. // 移除按钮事件监听
  531. if (this.allowButton) {
  532. this.allowButton.node.off(Button.EventType.CLICK, this.handleCharacterPassed, this);
  533. }
  534. if (this.dismissButton) {
  535. this.dismissButton.node.off(Button.EventType.CLICK, this.handleCharacterDismissed, this);
  536. }
  537. }
  538. }