QuestionAnswerManager.ts 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381
  1. import { _decorator, Component, Node, Button, Label } from 'cc';
  2. import { DialogueManager } from './DialogueManager';
  3. import { PassCardManager } from './PassCardManager';
  4. import { GameFlowManager } from './GameFlowManager';
  5. const { ccclass, property } = _decorator;
  6. /**
  7. * 问答对接口,添加表情支持
  8. */
  9. interface QuestionAnswer {
  10. question: string; // 问题文本
  11. answers: string[]; // 回答文本数组
  12. showPassCard?: boolean; // 是否显示通行证
  13. }
  14. // 将固定问题的索引定义为常量
  15. const ASK_PASS_QUESTION_INDEX = 1; // 询问通行证的问题固定为第二个问题
  16. @ccclass('QuestionAnswerManager')
  17. export class QuestionAnswerManager extends Component {
  18. @property({
  19. type: DialogueManager,
  20. tooltip: '对话管理器引用'
  21. })
  22. dialogueManager: DialogueManager = null;
  23. @property({
  24. type: [Button],
  25. tooltip: '问题按钮数组',
  26. readonly: true
  27. })
  28. questionButtons: Button[] = [];
  29. @property({
  30. type: [Node],
  31. tooltip: '问题文本节点数组(Label组件所在的节点)',
  32. readonly: true
  33. })
  34. questionLabels: Node[] = [];
  35. @property({
  36. type: PassCardManager,
  37. tooltip: '通行证管理器引用'
  38. })
  39. passCardManager: PassCardManager = null;
  40. @property({
  41. type: Node,
  42. tooltip: '游戏流程管理器所在的节点'
  43. })
  44. gameFlowManagerNode: Node = null;
  45. // 游戏流程管理器引用
  46. private gameFlowManager: GameFlowManager = null;
  47. // 问答对数组
  48. private questionAnswerPairs: QuestionAnswer[] = [];
  49. // 当前显示的问题索引
  50. private currentQuestionIndices: number[] = [0, 1, 2];
  51. start() {
  52. // 初始化默认问答对
  53. // this.initDefaultQuestionAnswers();
  54. // 注册按钮事件
  55. this.registerButtons();
  56. // 更新问题按钮文本
  57. this.updateQuestionButtonTexts();
  58. // 从节点获取GameFlowManager组件
  59. if (this.gameFlowManagerNode) {
  60. this.gameFlowManager = this.gameFlowManagerNode.getComponent(GameFlowManager);
  61. if (!this.gameFlowManager) {
  62. console.error('游戏流程管理器节点上没有GameFlowManager组件');
  63. } else {
  64. console.log('成功获取GameFlowManager组件');
  65. }
  66. } else {
  67. console.error('游戏流程管理器节点未设置');
  68. // 尝试在场景中查找
  69. this.gameFlowManager = this.node.scene.getComponentInChildren(GameFlowManager);
  70. if (this.gameFlowManager) {
  71. console.log('在场景中找到GameFlowManager组件');
  72. } else {
  73. console.error('无法在场景中找到GameFlowManager组件');
  74. }
  75. }
  76. }
  77. /**
  78. * 初始化默认问答对
  79. */
  80. private initDefaultQuestionAnswers(): void {
  81. // 添加一些默认的问答对
  82. this.questionAnswerPairs = [
  83. {
  84. question: "询问为何不在名单内?",
  85. answers: ["我没见过你的资料。你确定你应该在这个区域吗?"]
  86. },
  87. {
  88. question: "询问通行证?",
  89. answers: ["这是我的通行证,请过目。"],
  90. showPassCard: true // 这个问题会显示通行证
  91. },
  92. {
  93. question: "询问外貌?",
  94. answers: ["我对你的外貌没有任何评价。我只负责确认身份。"]
  95. },
  96. {
  97. question: "你是谁?",
  98. answers: ["我是这个区域的安全管理员,负责身份验证和访问控制。"]
  99. },
  100. {
  101. question: "这是什么地方?",
  102. answers: ["这是一个受限制的区域,需要特殊许可才能进入。"]
  103. },
  104. {
  105. question: "我可以离开吗?",
  106. answers: ["如果你没有通行证,建议你尽快离开,否则可能会有麻烦。"]
  107. }
  108. ];
  109. }
  110. /**
  111. * 注册按钮事件
  112. */
  113. private registerButtons(): void {
  114. for (let i = 0; i < this.questionButtons.length; i++) {
  115. const button = this.questionButtons[i];
  116. const index = i; // 保存当前索引
  117. if (button) {
  118. // 注册点击事件
  119. button.node.on(Button.EventType.CLICK, () => {
  120. this.onQuestionButtonClicked(index);
  121. }, this);
  122. }
  123. }
  124. }
  125. /**
  126. * 更新问题按钮文本
  127. */
  128. private updateQuestionButtonTexts(): void {
  129. console.log('updateQuestionButtonTexts');
  130. // 为每个按钮设置对应的问题文本
  131. for (let i = 0; i < Math.min(this.questionLabels.length, this.currentQuestionIndices.length); i++) {
  132. const questionIndex = this.currentQuestionIndices[i];
  133. const labelNode = this.questionLabels[i];
  134. if (labelNode && questionIndex >= 0 && questionIndex < this.questionAnswerPairs.length) {
  135. // 获取Label组件并设置文本
  136. const label = labelNode.getComponent(Label);
  137. if (label) {
  138. label.string = this.questionAnswerPairs[questionIndex].question;
  139. }
  140. }
  141. }
  142. }
  143. /**
  144. * 问题按钮点击回调
  145. * @param buttonIndex 按钮索引
  146. */
  147. private onQuestionButtonClicked(buttonIndex: number): void {
  148. console.log(`问题按钮点击: index=${buttonIndex}`);
  149. if (buttonIndex < 0 || buttonIndex >= this.currentQuestionIndices.length) {
  150. console.error(`无效的按钮索引: ${buttonIndex}`);
  151. return;
  152. }
  153. const questionIndex = this.currentQuestionIndices[buttonIndex];
  154. console.log(`对应问题索引: ${questionIndex}`);
  155. if (questionIndex < 0 || questionIndex >= this.questionAnswerPairs.length) {
  156. console.error(`无效的问题索引: ${questionIndex}`);
  157. return;
  158. }
  159. // 获取问答对
  160. const qa = this.questionAnswerPairs[questionIndex];
  161. // 从回答数组中随机选择一个回答
  162. let selectedAnswer = "";
  163. if (qa.answers && qa.answers.length > 0) {
  164. const randomIndex = Math.floor(Math.random() * qa.answers.length);
  165. selectedAnswer = qa.answers[randomIndex];
  166. } else {
  167. selectedAnswer = "无法回答这个问题。";
  168. }
  169. console.log(`问题: "${qa.question}", 选择的回答: "${selectedAnswer}", 显示通行证: ${qa.showPassCard}`);
  170. // 检查是否需要显示通行证
  171. if (qa.showPassCard && this.passCardManager) {
  172. console.log('准备显示通行证');
  173. // 获取当前NPC数据
  174. const npcData = this.gameFlowManager ? this.gameFlowManager.getCurrentNpcData() : null;
  175. console.log('当前NPC数据:', npcData);
  176. if (npcData) {
  177. // 显示通行证,使用NPC数据
  178. try {
  179. this.passCardManager.showPassCard({
  180. name: npcData.characterName || '未知',
  181. room: `${Math.floor(Math.random() * 900) + 100}`, // 随机房间号,可以替换为实际数据
  182. id: `ID-${npcData.characterId}-${Math.floor(Math.random() * 1000)}`, // 随机ID,可以替换为实际数据
  183. reason: npcData.type === 'real' ? '合法居民' : '访客',
  184. characterId: npcData.characterId
  185. });
  186. console.log('通行证显示成功');
  187. } catch (error) {
  188. console.error('显示通行证时出错:', error);
  189. }
  190. } else {
  191. console.error('无法获取NPC数据');
  192. // 尝试使用默认数据显示通行证
  193. if (this.passCardManager) {
  194. try {
  195. this.passCardManager.showPassCard({
  196. name: '测试角色',
  197. room: '101',
  198. id: 'ID-TEST-001',
  199. reason: '测试',
  200. characterId: 1
  201. });
  202. console.log('使用默认数据显示通行证');
  203. } catch (error) {
  204. console.error('使用默认数据显示通行证时出错:', error);
  205. }
  206. }
  207. }
  208. } else {
  209. console.log(`不显示通行证,原因: showPassCard=${qa.showPassCard}, passCardManager=${!!this.passCardManager}`);
  210. }
  211. // 使用对话管理器显示回答,包含表情
  212. if (this.dialogueManager && selectedAnswer) {
  213. this.dialogueManager.showDialogue(selectedAnswer);
  214. }
  215. }
  216. /**
  217. * 添加新的问答对
  218. * @param questionAnswers 要添加的问答对数组
  219. */
  220. public addQuestionAnswers(questionAnswers: QuestionAnswer[]): void {
  221. if (!questionAnswers || questionAnswers.length === 0) {
  222. return;
  223. }
  224. // 添加新的问答对
  225. this.questionAnswerPairs = [...this.questionAnswerPairs, ...questionAnswers];
  226. // 更新按钮文本(如果需要)
  227. this.updateQuestionButtonTexts();
  228. }
  229. /**
  230. * 设置问题按钮显示的问题索引
  231. * @param indices 问题索引数组,长度应与按钮数量相同
  232. */
  233. public setQuestionIndices(indices: number[]): void {
  234. // 验证索引有效性
  235. const validIndices = indices.filter(index =>
  236. index >= 0 && index < this.questionAnswerPairs.length
  237. );
  238. // 更新当前显示的问题索引
  239. this.currentQuestionIndices = validIndices.slice(0, this.questionButtons.length);
  240. // 如果索引数量少于按钮数量,使用默认索引填充
  241. while (this.currentQuestionIndices.length < this.questionButtons.length) {
  242. const defaultIndex = this.currentQuestionIndices.length % this.questionAnswerPairs.length;
  243. this.currentQuestionIndices.push(defaultIndex);
  244. }
  245. // 更新按钮文本
  246. this.updateQuestionButtonTexts();
  247. }
  248. /**
  249. * 获取当前所有问答对
  250. * @returns 所有问答对数组
  251. */
  252. public getAllQuestionAnswers(): QuestionAnswer[] {
  253. return [...this.questionAnswerPairs];
  254. }
  255. /**
  256. * 清除所有问答对并重置为默认值
  257. */
  258. public resetToDefault(): void {
  259. this.initDefaultQuestionAnswers();
  260. this.currentQuestionIndices = [0, 1, 2];
  261. this.updateQuestionButtonTexts();
  262. }
  263. /**
  264. * 更新特定索引的问答对
  265. * @param index 要更新的问答对索引
  266. * @param newQA 新的问答对
  267. */
  268. public updateQuestionAnswer(index: number, newQA: QuestionAnswer): void {
  269. if (index >= 0 && index < this.questionAnswerPairs.length && newQA) {
  270. this.questionAnswerPairs[index] = newQA;
  271. this.updateQuestionButtonTexts();
  272. }
  273. }
  274. /**
  275. * 替换所有问答对
  276. * @param newQAPairs 新的问答对数组
  277. */
  278. public replaceAllQuestionAnswers(newQAPairs: QuestionAnswer[]): void {
  279. console.log('替换问答对:', newQAPairs);
  280. // 清空现有问答对
  281. this.questionAnswerPairs = [];
  282. // 添加固定的"询问通行证"问题
  283. const passCardQuestion = {
  284. question: "询问通行证?",
  285. answers: ["这是我的通行证,请过目。"],
  286. showPassCard: true
  287. };
  288. console.log('添加通行证问题:', passCardQuestion);
  289. // 添加新的问答对
  290. for (let i = 0; i < newQAPairs.length; i++) {
  291. if (i === ASK_PASS_QUESTION_INDEX) {
  292. // 在第二个位置插入通行证问题
  293. this.questionAnswerPairs.push(passCardQuestion);
  294. console.log(`在位置${i}添加通行证问题`);
  295. } else {
  296. this.questionAnswerPairs.push(newQAPairs[i]);
  297. console.log(`在位置${i}添加问题:`, newQAPairs[i]);
  298. }
  299. // 确保不超过三个问题
  300. if (this.questionAnswerPairs.length >= 3) break;
  301. }
  302. // 如果问题不足三个,补充通行证问题
  303. if (this.questionAnswerPairs.length < 3) {
  304. // 如果还没有添加通行证问题,则添加
  305. const hasPassQuestion = this.questionAnswerPairs.some(qa => qa.showPassCard);
  306. if (!hasPassQuestion) {
  307. this.questionAnswerPairs.push(passCardQuestion);
  308. console.log('添加缺失的通行证问题');
  309. }
  310. // 依然不足三个,可以使用默认问题补充
  311. while (this.questionAnswerPairs.length < 3) {
  312. const backupQuestion = {
  313. question: `备用问题${this.questionAnswerPairs.length + 1}`,
  314. answers: ["这是一个标准回答。"]
  315. };
  316. this.questionAnswerPairs.push(backupQuestion);
  317. console.log('添加备用问题:', backupQuestion);
  318. }
  319. }
  320. // 确保第二个问题是通行证问题
  321. if (this.questionAnswerPairs.length >= 2 && !this.questionAnswerPairs[1].showPassCard) {
  322. console.log('强制第二个问题为通行证问题');
  323. this.questionAnswerPairs[1] = passCardQuestion;
  324. }
  325. console.log('最终问答对:', this.questionAnswerPairs);
  326. // 重置当前显示的问题索引
  327. this.currentQuestionIndices = [0, 1, 2];
  328. // 更新问题按钮文本
  329. this.updateQuestionButtonTexts();
  330. }
  331. }