This commit is contained in:
2025-07-17 17:18:21 +08:00
commit 1ffc1b5cf0
5309 changed files with 1150310 additions and 0 deletions
@@ -0,0 +1,410 @@
import { _decorator, AudioSource, EditBox, isValid, Label, Node, Sprite, tween, utils, Vec3 } from 'cc';
import { GButton } from '../../Main/Common/GButton';
import Utils from '../../Main/Common/Utils';
import { ViewManager } from '../../Main/Manager/ViewManager';
import { InnerMsgCode } from '../../Main/Config/InnerMsgCode';
import li_BaseView from '../../Main/Common/li_BaseView';
import SubManager from '../SubManager';
import GameManager from '../../Main/Manager/GameManager';
import { I_LevelConfig, I_NpcTalkBack } from '../../Main/Config/CommonConfig';
import HttpUnit from '../../Main/Common/HttpUnit';
import { SDKManager } from '../../Main/Channel/SDKManager';
import ResManager from '../../Main/Manager/ResManager';
const { ccclass, property } = _decorator;
/**对话阶段 */
const enum TalkStage {
/**开场白 */
prologue,
/**我的对话 */
myTalk,
/**等待NPC回复 */
waitNpcTalk,
/**NPC对话 */
npcTalk,
}
//聊天界面
@ccclass('Talk_UI')
export class Talk_UI extends li_BaseView {
private _nodeTab: any = {};
private _data;
private dazijiInfo = {stage: 0, idx: 0, str: "", tm:0, ts:0.05, lab:null}; //打字机信息 stage:0-未开始,1-正在打字,2-打字结束
private npcTalkInfo = {stage: 0, str:"", dotStr:"...", dotIdx:0, tm:0, ts:0.3}; //等待npc回复 stage:0-未开始,1-获取中,2-获取完成
private ebTalk: EditBox;
private labNpcTalk: Label;
private AIAudioSource: AudioSource; //AI语音组件
private curStage: TalkStage = TalkStage.prologue; //当前对话阶段
private lvCfg: I_LevelConfig = null; //当前关卡配置
private lastRandTalkIdx: number = -1; //上一次随机对话的索引
private srouceCnt: number = 0; //已用对话轮次
//----重写父类接口---------------------------------------
onLoadCT() {
this.registerListenner();
Utils.parseNode(this.node, this._nodeTab)
this.ebTalk = this._nodeTab.ebTalk.getComponent(EditBox);
this.labNpcTalk = this._nodeTab.npcTalk.getComponent(Label);
this.ebTalk.node.on('editing-did-began', this.onEditingBegan, this);
this.ebTalk.node.on('editing-did-ended', this.onEditingEnded, this);
this.ebTalk.node.on('editing-return', this.onEditingReturn, this);
this.AIAudioSource = this._nodeTab.videoNode.getComponent(AudioSource);
this._nodeTab.arrowNode.active = false;
let npcNextArrow:Node = this._nodeTab.npcNextArrow
tween(npcNextArrow)
.to(0.5, {position: new Vec3(15, 0, 0)})
.to(0.5, {position: new Vec3(-15, 0, 0)})
.union()
.repeatForever()
.start()
}
openUIDataCT(data: any): void {
this._data = data
}
registerListenner() {
Utils.addInnerEL(InnerMsgCode.Data_NpcTalkBack, this, this.resiveNpcTalkBack)
}
start() {
GButton.BandClick(this._nodeTab.btnBack, this.onBackClick, this);
GButton.BandClick(this._nodeTab.btnSend, this.onSendClick, this);
GButton.BandClick(this._nodeTab.btnSuiji, this.onSuijiClick, this);
GButton.BandClick(this._nodeTab.npcTalkFrame, ()=>{
this.onNpcFramClick();
}, this, 0, null, null, false);
GButton.BandClick(this._nodeTab.btnRecord, ()=>{
ViewManager.I.openBundlesView("UI/StartUI/Record_UI")
}, this);
GButton.BandClick(this._nodeTab.btnTishi, ()=>{
ViewManager.I.openBundlesView("UI/StartUI/Tips_UI")
}, this);
GButton.BandClick(this._nodeTab.btnAD, ()=>{
console.log("观看广告")
ViewManager.I.openBundlesView("UI/StartUI/TalkAdDialog", {
adCallback: ()=>{
SDKManager.show_reward_video_ad(this.node.uuid, 1)
},
shareCallback: ()=>{
SDKManager.show_reward_share(this.node.uuid, 1)
}
})
}, this);
//ai语音开关
GButton.BandClick(this._nodeTab.btnYuyin, ()=>{
GameManager.AIVoiceSwt = !GameManager.AIVoiceSwt;
this.refreshAIVoiceState()
}, this);
this.refreshAIVoiceState()
SDKManager.register_video_reward(this.node.uuid, (tag:number)=>{
console.log("视频广告回调", tag)
if (tag == 1) {
// 加次数
SubManager.ShowPrompt("观看视频成功,获得聊天次数")
this.doAddLevelCnt(1)
}
})
SDKManager.register_share_reward(this.node.uuid, (tag:number)=>{
console.log("分享回调", tag)
if (tag == 1) {
// 加次数
SubManager.ShowPrompt("分享成功,获得聊天次数")
this.doAddLevelCnt(1)
}
})
this.lvCfg = GameManager.getLevelCfg(GameManager.CurLevelId)
//以npc开场白
this.showNpcPrologue()
//刷新状态显示
this.srouceCnt = 0
this.refreshTalkStepData()
}
onDestroy () {
if (isValid(this.ebTalk)) {
this.ebTalk.node.off('editing-did-began', this.onEditingBegan, this);
this.ebTalk.node.off('editing-did-ended', this.onEditingEnded, this);
this.ebTalk.node.off('editing-return', this.onEditingReturn, this);
}
}
update(deltaTime: number) {
//region 打字机效果逻辑
if (this.dazijiInfo.stage == 1) {
this.dazijiInfo.tm += deltaTime
if (this.dazijiInfo.tm >= this.dazijiInfo.ts) {
this.dazijiInfo.tm = 0
this.dazijiInfo.lab.string = this.dazijiInfo.str.substring(0, this.dazijiInfo.idx)
this.dazijiInfo.idx += 1
if (this.dazijiInfo.idx > this.dazijiInfo.str.length) {
this.dazijiInfo.stage = 2
}
}
} else if (this.dazijiInfo.stage == 2) {
console.log("文本打字机效果结束")
this.dazijiInfo.stage = 0
this.dazijiInfo.lab.string = this.dazijiInfo.str
this._nodeTab.arrowNode.active = true;
// if (this.curStage == TalkStage.prologue || this.curStage == TalkStage.npcTalk) {
// this.scheduleOnce(() => {
// this.turnToMyTalk()
// }, 2)
// }
}
//接收npc回复逻辑
if (this.npcTalkInfo.stage == 1) {
this.npcTalkInfo.tm += deltaTime
if (this.npcTalkInfo.tm >= this.npcTalkInfo.ts) {
this.npcTalkInfo.tm = 0
GameManager.I.getNpcTalkBack({})
this.labNpcTalk.string = this.npcTalkInfo.dotStr.substring(0, this.npcTalkInfo.dotIdx)
this.npcTalkInfo.dotIdx += 1
if (this.npcTalkInfo.dotIdx > this.npcTalkInfo.dotStr.length) {
this.npcTalkInfo.dotIdx = 0
}
}
}
}
//接收到npc回复数据流
resiveNpcTalkBack(data:I_NpcTalkBack) {
if (this.curStage != TalkStage.waitNpcTalk) return
if (data.isFinished) {
this.npcTalkInfo.stage = 0
console.log("npc回复:", data)
this.turnToNpcTalk(data)
}
}
//输入框开始编辑事件
onEditingBegan(param1:any, param2:any) {
console.log("聊天界面1 onEditingBegan", param1, param2)
}
//输入框回车事件
onEditingReturn(param1:any, param2:any) {
console.log("聊天界面2 onEditingReturn", param1, param2)
}
//输入框结束编辑事件
onEditingEnded(param1:any, param2:any) {
console.log("聊天界面3 onEditingEnded", param1, param2)
}
//刷新AI语音状态
private refreshAIVoiceState() {
let voicePath = GameManager.AIVoiceSwt ? "lv_4" : "lv_5"
let sptYuyin = this._nodeTab.sptYuyin.getComponent(Sprite)
ResManager.I.changeBundleSpriteFrame(sptYuyin, voicePath, "Zhujiemian")
}
//播放AI语音
private playAIVoice(str:string) {
if (!GameManager.AIVoiceSwt) {
return
}
HttpUnit.ins.getAIVoice({record_id: GameManager.RecordId, text:str}, (data) => {
if (data) {
console.log("播放AI语音11", data)
SDKManager.playBase64Audio(data.url, false)
// let qianzhui = "data:audio/x-wav;base64,"
// let substring = data.url.substring(qianzhui.length, data.url.length)
// this.base64ToAudio(substring, (localUrl)=>{
// console.log("播放AI语音22", localUrl)
// // 创建音频元素并播放
// const audio = new Audio(localUrl);
// audio.play();
// // ResManager.I.loadRemoteAudio(localUrl, (audio) => {
// // this.AIAudioSource.clip = audio
// // this.AIAudioSource.play()
// // this.AIAudioSource.volume = 1
// // // this.AIAudioSource.playOneShot(audio, 1)
// // })
// })
}
})
}
//显示NPC开场白
private showNpcPrologue() {
this.curStage = TalkStage.prologue
this._nodeTab.NpcTalkNode.active = true
this._nodeTab.MyTalkNode.active = false
this._nodeTab.arrowNode.active = false;
//名称
Utils.setString(this._nodeTab.npcName, this.lvCfg.name)
//开场白
this.dazijiInfo.stage = 1
this.dazijiInfo.idx = 0
this.dazijiInfo.lab = this.labNpcTalk
this.dazijiInfo.str = this.lvCfg.prologueMessage
this.dazijiInfo.tm = this.dazijiInfo.ts
GameManager.AddTalkRecord({talk:this.lvCfg.prologueMessage, isMe:false})
this.playAIVoice(this.lvCfg.prologueMessage)
}
/**切换到玩家说话状态 */
private turnToMyTalk() {
if (this.curStage == TalkStage.myTalk) return
this.curStage = TalkStage.myTalk
this._nodeTab.NpcTalkNode.active = false
this._nodeTab.MyTalkNode.active = true
this.ebTalk.string = ""
}
/**切换到等待NPC说话状态 */
private turnToWaitNpcTalk() {
if (this.curStage == TalkStage.waitNpcTalk) return
this.curStage = TalkStage.waitNpcTalk
this._nodeTab.NpcTalkNode.active = true
this._nodeTab.MyTalkNode.active = false
this._nodeTab.arrowNode.active = false;
this.labNpcTalk.string = ""
}
/**切换到NPC说话状态 */
private turnToNpcTalk(data:I_NpcTalkBack) {
if (this.curStage == TalkStage.npcTalk) return
this.curStage = TalkStage.npcTalk
this._nodeTab.NpcTalkNode.active = true
this._nodeTab.MyTalkNode.active = false
this._nodeTab.arrowNode.active = false;
GameManager.AddStepScore(data.aiScore) //记录本次分数
//npc回复
// this.labNpcTalk.string = data.aiResponse
this.dazijiInfo.stage = 1
this.dazijiInfo.idx = 0
this.dazijiInfo.lab = this.labNpcTalk
this.dazijiInfo.str = data.aiResponse
this.dazijiInfo.tm = this.dazijiInfo.ts
GameManager.AddTalkRecord({talk:data.aiResponse, isMe:false})
this.playAIVoice(data.aiResponse)
//npc表情
//分数
//对话轮次
this.srouceCnt = data.sourceCnt
this.refreshTalkStepData()
}
/**刷新当前状态显示 */
private refreshTalkStepData() {
let stepData = GameManager.CurLevelData
Utils.setString(this._nodeTab.lunciNum, `${this.srouceCnt}/${stepData.total_cnt}`)
}
//检查对话轮次是否用完
private checkIsFinish() {
// //测试代码
// if (true) {
// return this.srouceCnt >= 1
// }
let stepData = GameManager.CurLevelData
return this.srouceCnt >= stepData.total_cnt
}
//增加聊天次数
private doAddLevelCnt(add:number = 1) {
HttpUnit.ins.addTalkCnt({record_id: GameManager.RecordId, add_cnt:add}, (data) => {
if (data) {
GameManager.CurLevelData = data.level
this.refreshTalkStepData()
}
})
}
//结算
private doJiesuan() {
let [score, score_all] = GameManager.getGameScore()
HttpUnit.ins.sendLevelFinish({record_id: GameManager.RecordId, score:score, score_all:score_all}, (data) => {
if (data && data.level) {
//成功
ViewManager.I.openBundlesView("UI/StartUI/Finish_UI", data.level)
} else {
//失败
this.doClose();
Utils.sendInnerMsg(InnerMsgCode.UI_Talk_Back, {})
}
})
}
//退出聊天
onBackClick() {
SubManager.ShowConfirm({
content: "确定退出吗?",
yesCallback: () => {
this.doJiesuan();
}
})
}
//发送消息
onSendClick() {
let str = this.ebTalk.string;
if (str.length == 0) {
SubManager.ShowPrompt("请先输入内容")
return
}
this.turnToWaitNpcTalk()
this.ebTalk.string = ""
HttpUnit.ins.sendUserTalk({record_id: GameManager.RecordId, user_input: str}, (data) => {
if (data) {
GameManager.AddTalkRecord({talk:str, isMe:true})
//开始接收npc回复
this.npcTalkInfo.stage = 1
this.npcTalkInfo.str = ""
this.npcTalkInfo.tm = this.npcTalkInfo.ts
this.npcTalkInfo.dotIdx = 0
}
})
}
//随机回复对话
onSuijiClick() {
let sjLen = this.lvCfg.randomInputPool.length
let randIdx = Utils.getRandomInt(0, sjLen-1)
console.log("随机回复对话:", randIdx, sjLen)
if (randIdx == this.lastRandTalkIdx) {
randIdx++
if (randIdx >= sjLen) randIdx = 0
}
this.lastRandTalkIdx = randIdx
this.ebTalk.string = this.lvCfg.randomInputPool[randIdx]
}
//点击npc对话背景
onNpcFramClick() {
if (this.dazijiInfo.stage == 1) {
this.dazijiInfo.stage = 2
} else {
if (this.curStage == TalkStage.prologue || this.curStage == TalkStage.npcTalk) {
if (this.checkIsFinish()) {
this.doJiesuan()
} else {
this.turnToMyTalk()
}
}
}
}
}