import { DataEventId } from "../../data/GameData"; import GuideVO from "./GuideVO"; /** * @description 新手引导 * @author 邹勇 */ const { ccclass, property } = cc._decorator; @ccclass export default class Guide extends cc.Component { @property({ type: cc.Node, displayName: "显示区域" }) node_display: cc.Node = null; @property({ type: cc.Node, displayName: "点击区域" }) node_click: cc.Node = null; @property({ type: cc.Node, displayName: "背景" }) node_bg: cc.Node = null; @property({ type: cc.Node, displayName: "对话框" }) node_dialog: cc.Node = null; @property({ type: cc.Node, displayName: "手指" }) node_finger: cc.Node = null; @property({ type: cc.Sprite, displayName: "头像" }) node_head: cc.Sprite = null; @property({ type: sp.Skeleton, displayName: "形象" }) node_person: sp.Skeleton = null; @property({ type: cc.RichText, displayName: "对话内容" }) rich_dialog: cc.RichText = null; private guides: GuideVO[]; private crtStep: number; private crtGuide: GuideVO; private targetNode: cc.Node; private event_data: string; /** 对话框对齐方式 上下左右中 */ private widgets: string[] = ['top', 'bottom', 'left', 'right', 'verticalCenter', 'horizontalCenter']; onLoad() { // this.initTouch(); } start() { if (gData.guideData.crtID == null) { this.node.destroy(); return; } this.reset(); this.guides = gData.guideData.getGuidesByID(gData.guideData.crtID); this.crtStep = -1; this.nextStep(); } private nextStep() { this.crtStep++; this.crtGuide = this.guides[this.crtStep]; mk.data.sendDataEvent(DataEventId.guide, `新手引导第${gData.guideData.crtID}_${this.crtStep}步完成`); this.updateGuide(); } private updateGuide() { if (this.crtGuide == null) { this.close(); } else { this.node_display.getComponent(cc.Mask).type = this.crtGuide.display_type == 0 ? cc.Mask.Type.RECT : cc.Mask.Type.ELLIPSE; this.node_bg.opacity = 180; this.node_finger.opacity = 255; this.node_dialog.opacity = 255; this.targetNode = null; this.event_data = null; this.ifThrough = true; let [x, y, w, h] = [null, null, null, null]; //点击全屏下一步,显示区域不显示 || 点击区域下一步,并发送事件,显示区域读配置 if (this.crtGuide.click_rect == "all" || this.crtGuide.click_rect.indexOf("event") != -1) { //显示区域: display_rect为""表示全屏 if (this.crtGuide.display_rect.length == 0) { this.node_display.width = this.node_display.height = 0; } else { let arr = this.crtGuide.display_rect.split(":"); x = parseInt(arr[0]); y = parseInt(arr[1]); w = parseInt(arr[2]); h = parseInt(arr[3]); } if (this.crtGuide.click_rect == "all") { this.node_click.x = 0; this.node_click.y = 0; this.node_click.width = this.node.width; this.node_click.height = this.node.height; this.ifThrough = false; } else { this.event_data = this.crtGuide.id + "_" + (this.crtStep + 1); this.node_click.x = x; this.node_click.y = y; this.node_click.width = w; this.node_click.height = h; } } else {//点击按钮下一步,显示区域为配置的node,点击区域=显示区域 this.targetNode = cc.find("Canvas/" + this.crtGuide.click_rect); w = this.targetNode.width; h = this.targetNode.height; let pos = mk.game.getWorldPos(this.targetNode); x = pos.x; y = pos.y; //lastStruggle if (this.crtGuide && this.crtGuide.id == 2 && this.crtStep == 1) { w = this.targetNode.parent.width; h = this.targetNode.parent.height; let pos1 = mk.game.getWorldPos(this.targetNode.parent); x = pos1.x; y = pos1.y - h / 2; } //穿透点击目标节点时增加一个事件触发下一步,触发后移除 this.node_click.width = this.node_click.height = 0; let eventHandler = new cc.Component.EventHandler(); eventHandler.target = this.node; eventHandler.component = "Guide"; eventHandler.handler = "clickNodeClick"; this.targetNode.getComponent(cc.Button).clickEvents.push(eventHandler); } //显示区域由大到小动画 if (x != null && y != null && w != null && h != null) { if (this.crtGuide.display_type == 0) {//矩形选中框 //先重置 this.node_bg.x = this.node_bg.y = this.node_display.x = this.node_display.y = 0; this.node_display.width = this.node.width; this.node_display.height = this.node.height; //动画 cc.tween(this.node_display) .to(0.2, { x: x, y: y, width: w, height: h }, { onUpdate: () => { this.node_bg.x = -this.node_display.x; this.node_bg.y = -this.node_display.y; } }) .start(); } else { //先重置 this.node_bg.x = this.node_display.x = x; this.node_bg.y = this.node_display.y = y; this.node_display.width = this.node_display.height = this.node_bg.width = this.node_bg.height = this.node.height * 2; //动画 let radius = this.crtGuide.display_type; cc.tween(this.node_display) .to(0.2, { width: radius, height: radius }) .start(); } } //对话框位置 //全屏对齐 if (this.crtGuide.dialog_pos != null && this.crtGuide.dialog_pos.length > 0) { let arr = this.crtGuide.dialog_pos.split(":"); let wedgit = this.node_dialog.getComponent(cc.Widget); wedgit.enabled = true; for (let i = 0; i < this.widgets.length; i++) { wedgit[this.widgets[i]] = arr[i] == "" ? null : parseInt(arr[i]); } } else {//显示区域偏移 let arr = this.crtGuide.dialog_pos1.split(","); let wedgit = this.node_dialog.getComponent(cc.Widget); wedgit.enabled = false; this.node_dialog.x = x + parseInt(arr[0]); this.node_dialog.y = y + parseInt(arr[1]); } //对话文字对齐方式 let a = this.crtGuide.dialog_alignment; this.rich_dialog.horizontalAlign = a == '0' ? cc.macro.TextAlignment.LEFT : (a == '1' ? cc.macro.TextAlignment.CENTER : cc.macro.TextAlignment.RIGHT); if (this.crtGuide.finger == "") { this.node_finger.active = false; } else { this.node_finger.active = true; let arr = this.crtGuide.finger.split(":"); this.node_finger.x = x + parseInt(arr[0]); this.node_finger.y = y + parseInt(arr[1]); } if (this.crtGuide.tr_form == 1) { this.node_head.node.active = true; this.node_person.node.active = false; } else { this.node_head.node.active = false; this.node_person.node.active = true; } this.rich_dialog.string = this.crtGuide.dialog; } } async clickNodeClick() { mk.audio.playEffect("button"); cc.Tween.stopAllByTarget(this.node_display); console.log("clickNodeClick"); if (this.targetNode) { this.targetNode.getComponent(cc.Button).clickEvents.pop(); } if (this.event_data) { //event_guide data:1_2 (1_2为新手引导的id) mk.event.emit("event_guide", this.event_data); } this.reset(); if (this.crtGuide.lag_next > 0) { await mk.time.WaitForSeconds(this.crtGuide.lag_next); } this.nextStep(); } /** 等待状态 透明不可点击 */ private reset() { this.node_display.width = 0; this.node_display.height = 0; this.node_bg.width = this.node.width; this.node_bg.height = this.node.height; this.node_bg.x = -this.node_display.x; this.node_bg.y = -this.node_display.y; this.node_bg.opacity = 0; this.node_click.width = 0 this.node_click.height = 0; this.node_finger.opacity = 0; this.node_dialog.opacity = 0; } private close() { mk.guide.close(); this.node.destroy(); } ///////////////// 自定义触摸监听 ///////////////// private _eventManager = cc["internal"]["eventManager"]; private _touchListener: any; private ifThrough: boolean; private initTouch() { const EventListener = cc["EventListener"]; this._touchListener = EventListener.create({ event: EventListener.TOUCH_ONE_BY_ONE, swallowTouches: false,//是否吞噬touch事件 owner: this.node_click, mask: null, onTouchBegan: this.onTouchStart.bind(this), onTouchMoved: null, onTouchEnded: this.onTouchEnded.bind(this), onTouchCancelled: null, }); this._eventManager.addListener(this._touchListener, this.node_click); } private onTouchStart(touch: cc.Touch, event: cc.Event.EventTouch): boolean { // cc.log("touch start"); //此处必须返回true(表示接触到了节点),否则TOUCH_MOVE,TOUCH_END,TOUCH_CANCEL不触发。 if (this.ifThrough) { const point_world_pos = touch.getLocation(); let localPoint = this.node.parent.convertToNodeSpaceAR(new cc.Vec2(point_world_pos.x, point_world_pos.y)); // let localPoint = mk.game.localConvertWorldPointARCenter() let result = this.pointInPoly(localPoint, this.node_click); return result; } else { return false; } } /** * 点是否在节点宽高范围内 * @param point 点击的点 * @param node * @returns */ private pointInPoly(point: cc.Vec2 | cc.Vec3, node: cc.Node) { const self_node_pos = node.getPosition(); if (point.x >= (self_node_pos.x - (this.node_click.width / 2)) && point.x <= (self_node_pos.x + (this.node_click.width / 2)) && point.y >= (self_node_pos.y - (this.node_click.height / 2)) && point.y <= (self_node_pos.y + (this.node_click.height / 2))) { return true; } return false; } private onTouchEnded(touch: cc.Touch, event: cc.Event.EventTouch): void { // cc.log("touch end"); this.clickNodeClick(); } protected onDestroy(): void { // super.onDestroy(); this._eventManager.removeListener(this._touchListener, this.node_click); } }