// Learn cc.Class: // - [Chinese] http://www.cocos.com/docs/creator/scripting/class.html // - [English] http://www.cocos2d-x.org/docs/editors_and_tools/creator-chapters/scripting/class/index.html // Learn Attribute: // - [Chinese] http://www.cocos.com/docs/creator/scripting/reference/attributes.html // - [English] http://www.cocos2d-x.org/docs/editors_and_tools/creator-chapters/scripting/reference/attributes/index.html // Learn life-cycle callbacks: // - [Chinese] http://www.cocos.com/docs/creator/scripting/life-cycle-callbacks.html // - [English] http://www.cocos2d-x.org/docs/editors_and_tools/creator-chapters/scripting/life-cycle-callbacks/index.html const OFFLINE_TIPS = 'data:image/png;base64,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'; const RECONNECT_BTN = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJYAAAAzCAMAAABCDgGNAAAAZlBMVEUAAAAAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOUAiOXHNmdXAAAAIXRSTlMACH8P7PjcBPG0YFYl4NXQyr6rd2lbQjkzGpTlIHr5jJUXB7SdAAABgUlEQVRYw8zVx27CUBCF4XOLKwaXuAKG/O//kpGFnEhAkp19v9XsRjqaolemt015SdlAeikb2xv9y3RZxMairDP6i7OeXXjr9KvWszh95sPktAE3Dfn5xMK3eq+oAI620MYKewSo3jY+pECcJ9pBksdAetCLDyCyRjsxNgI+9OQOxKN2NMbA/TWr2mlXrn7O6wBkRjszGXDQtyKCOtHukhrSQqsKYqcAuBiqNZ8WbqOCMN6glRbOg1UgLHinxQzx7uO+MjHMWgoPnYLRgTeP43AMYAtXyfFxJDKYFZAZMslEcFVArhAZ9XBSUE7Qy8JZQTmDVQO5gpJDoxIGBWWAUh4mBWWCi24QxJf+4SAVoMB8VWfHKAACMRBFw8KC1qYSm7n/Ja3E0k6fV1g2ycz/SdTXQv8WOono3kK3PHoT0QTB5a0tWd10imb5GlrzGXJPrE6m0qpn0jaDUIkNyreqBkkDVXaqkmaVy98W4/U8cVwW48H57B84n6X/ZshUn8jY1xND+YFI77v8MAAAAABJRU5ErkJggg=='; const PANEL = 'data:image/png;base64,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'; const BAR = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAcAAAAHCAYAAADEUlfTAAAAFklEQVQImWOcPHnyfwYcgAmXxKCUBAAm8ALGxCtPnQAAAABJRU5ErkJggg=='; const CIRCLE = 'data:image/png;base64,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'; const LINE = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEIAAAABAQMAAABQVuppAAAAA1BMVEXZ2dmK1ydDAAAACklEQVQI12OAAwAACgABaQY5MgAAAABJRU5ErkJggg=='; const BLACKARROW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABUAAAAlCAYAAACtbaI7AAACMklEQVRIS6XWT8gOURTH8c+bIjaSZGMjr6xkJUlKJAnlTyglRYpIQlFIYcFbSEKSiBD5F/K/XrGQpY0VZWFnQ2GhRKdm3sa488zM85zlnfv73nPm3HPO7dOb9eE03uBKjorFXuwEtuM3VuN2wHqBHsK+gke/sAyPuoXuxeFEiN/R3w00wo2wy/YHG3GhLTRE5yp+2zacavtP1+IihiW83IOjbbO/AjcqgAdxoHhQk/AX4Q6GJzw8jp3l9TroPDzAyATwLLYgEvSPdYLOwjOMSgAvYX0K2ClR0/EcoxPAm1iTVVGyGlOeTsUgxiYU97ESUT2VVoZOwWuMSyjC88V1wHL4k/ASExLAV1iIn026T+5pgEI4MSF6iwX41gSYezo+C3lyQvQOc/C1KTCHRlJCWLb32fqXNsAcGhf8RUL4EFGeHTOdOjD+6cwMmrrktXeyChrrkdl7FfXdsXo6QePbcoRnqdZ2BluryrIMLl/+KL/LFeBj2NUkaaky3YDzFd39v95ZF37xe4yGkxVe7cZAm9ov7g3xkQrx0Dxq42m+N8LdnxAOTc5uoKGJBO1IiONVEsPwel32qw6OK7WpAhz99W7xW92MyvfGvhjP6xLgKOOleFzc3OTqxZ4oimtYlRBEn40GHs2p9QMtxvQtLEmAf2B+PCubhl9kjMjGdgDKFo18bjfQAEVHe4LZCfBgt9Bgxfh+ihkF8Ic4qBdosMZkyZmGT5nnn3uFBjjG+VVsxsdY+At+xGFFRqHhqQAAAABJRU5ErkJggg=='; const GREYARROW = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABYAAAAlCAYAAABGWhk4AAABdElEQVRIS63WSU7DMBjF8X9BAgoLBiG6YbwCV2ASFPYcEwkobDgA92BBGfYMG/QkuzKRHftz4l2V6NeXZzvOgP9jCzgEnoDfxjXTz0Fw9wg4BxaAV+AR+DFpwc0eDlF/uRMuWAmvgaVIuinwUJPcJz4AjoC5vvCw4zb8DZhYkoewwu4Dx4nkJrwJ94bH4F7wFJzD34H7ts7bYOF7wEmi81Y8B1fjJbDwXeA0kfzD1fId7oFS2IxbYOE7wFlJcivscdUyH9n+s1pq4BJ8Ugvn8Jcu8CpwBSxHKrmphYVeAisRVKfObQ285tBYUqE6GKZWuAjVU1jgYtQC51CdLjoIZqMksRktSVyF5mChWqfDxJLSi17v5OhIVbHullQVmkrcGY3BOfQO0BssO8IqhKrT2KeWTgd1WoSGiTdcp72gHu4d9fAFsB0pzfz4zZ2nxxe+GVz4ch+BxZ02g/nJWwTGDheqifrMTn3LDeGqEK5v5OeuqP7vD69mZ6FJZpeeAAAAAElFTkSuQmCC'; const PORTRAIT_ITEM_WIDTH = 670, PORTRAIT_ITEM_HEIGHT = 202, PORTRAIT_ITEM_SPACE = 25, LANDSCAPE_ITEM_WIDTH = 272, LANDSCAPE_ITEM_HEIGHT = 440, LANDSCAPE_ITEM_SPACE = 30; class RecommendUI { constructor(appid = 'default') { this.appid = appid; this.touching = false; this.firstShow = true; this.loadSuccess = false; this.specPanels = []; let window = cc.Canvas.instance; //获取游戏的canvas对象作为游戏窗口,以作为大小适配的基准参考 if (window instanceof cc.Canvas) { this.window = window.node; this.initRoot(); this.createBackground(); this.initTitle(); this.getSession(); // 获取上报的session this.fetchData(); } else { cc.error('Can\'t find the canvas node in the current scene.'); } } getSession() { let session = window.localStorage.getItem('session'); if (!session) { this.request('POST', 'https://goplatform.minigame.qq.com/mplogin/getsessionid', { AppID: this.appid + '' }).then(res => { if (res.result === 0) { session = res.session; window.localStorage.setItem('session', session); this.session = session; } }); } else { this.session = session; } } fetchData(reconnect = false) { this.request('GET', 'https://goplatform.minigame.qq.com/3366game/getcurrentgame?appid=' + this.appid) .then((res) => { if (res.result == 0) { this.loadSuccess = true; if (this.offlineNode) { this.offlineNode.active = false; } if (reconnect) { this.firstReport(); } this.games = []; this.moreGames = []; for (let i = 0; i < res.data.Games.length; ++i) { this.games.push({ app_id: res.data.Games[i]['app_id'], name: res.data.Games[i]['app_name'], icon: res.data.Games[i]['app_icon'], desc: res.data.Games[i]['app_introduction'], qrcode: res.data.Games[i]['mini_program_code'] }); } for (let i = 0; i < res.data.More_games.length; ++i) { this.moreGames.push({ name: res.data.More_games[i]['app_name'], icon: res.data.More_games[i]['app_icon'], desc: res.data.More_games[i]['app_introduction'], qrcode: res.data.More_games[i]['mini_program_code'] }); } this.banner = this.choose(res.data.Banner, res.data.Banner_landscape); this.poster = res.data.App_poster; if (res.data.More_game_image) { this.moreGameQrcode = res.data.More_game_image; } else { this.moreGameQrcode = ''; } this.loadResource(); } else { this.loadOfflineResource(); } }).catch(e => { cc.error(e); this.loadOfflineResource(); }); } // 拉取图片资源 loadResource() { let promises = []; for (let i = 0; i < this.games.length; ++i) { promises.push(this.loadRemoteImage(this.games[i].icon)); // 游戏图标 } for (let i = 0; i < this.moreGames.length; ++i) { promises.push(this.loadRemoteImage(this.moreGames[i].icon)); //更多游戏图标 } promises.push(this.loadRemoteImage(this.banner)); promises.push(this.loadRemoteImage(BAR)); promises.push(this.loadRemoteImage(PANEL)); promises.push(this.loadRemoteImage(CIRCLE)); promises.push(this.loadRemoteImage(LINE)); promises.push(this.loadRemoteImage(GREYARROW)); Promise.all(promises).then((results) => { this.gameIcons = []; this.moreGameIcons = []; for (let i = 0; i < this.games.length; ++i) { this.gameIcons.push(results[i]); } for (let i = 0; i < this.moreGames.length; ++i) { this.moreGameIcons.push(results[i + this.games.length]); } this.bannerImg = results[this.games.length + this.moreGames.length]; this.bar = results[this.games.length + this.moreGames.length + 1]; this.panel = results[this.games.length + this.moreGames.length + 2]; this.circle = results[this.games.length + this.moreGames.length + 3]; this.line = results[this.games.length + this.moreGames.length + 4]; this.greyArrow = results[this.games.length + this.moreGames.length + 5]; this.createUI(); }).catch((e) => { cc.error(e); }); } // 拉取离线图片资源 loadOfflineResource() { if (this.offlineNode) { this.offlineNode.active = true; return; } let promises = []; promises.push(this.loadRemoteImage(OFFLINE_TIPS)); promises.push(this.loadRemoteImage(RECONNECT_BTN)); Promise.all(promises).then((results) => { this.offlineTips = results[0]; this.reconnectBtn = results[1]; this.createUI(); }).catch((e) => { cc.error(e); }); } createNode(options) { let node = new cc.Node(options.name); let customProps = ['x', 'y', 'width', 'height', 'anchorX', 'anchorY', 'active', 'scaleX', 'scaleY', 'color', 'rotation']; if (options.components) { for (let component of options.components) { this.addComponent(node, component, options); } } for (let prop of customProps) { node[prop] = options[prop] !== undefined ? options[prop] : node[prop]; if (prop == 'width' && options[prop] == 476) { window.line = node; } } if (options.children) { for (let child of options.children) { let childNode = this.createNode(child); node.addChild(childNode); } } return node; } addComponent(node, component, options) { let spriteFrames = this.uis; let props = { 'sprite': ['spriteFrame', 'type', 'sizeMode', 'trim'], 'mask': ['type', 'segements', 'alphaThreshold', 'spriteFrame'], 'richText': ['horizontalAlign', 'fontSize', 'maxWidth', 'lineHeight', 'string'], 'label': ['horizontalAlign', 'verticalAlign', 'fontSize', 'maxWidth', 'lineHeight', 'string', 'overflow'], 'widget': ['isAlignHorizontalCenter', 'isAlignVerticalCenter', 'isAlignTop', 'isAlignBottom', 'isAlignLeft', 'isAlignRight', 'top', 'bottom', 'left', 'right'], 'scrollview': ['vertical', 'horizonal', 'elastic'], 'layout': ['type', 'paddingTop', 'paddingBottom', 'paddingLeft', 'paddingRight', 'spacingX', 'spacingY'], 'graphics': [], 'scrollbar': ['direction', 'enableAutoHide'], 'blockInputEvents': [] }; let classes = { 'sprite': cc.Sprite, 'mask': cc.Mask, 'richText': cc.RichText, 'label': cc.Label, 'widget': cc.Widget, 'scrollview': cc.ScrollView, 'graphics': cc.Graphics, 'layout': cc.Layout, 'scrollbar': cc.Scrollbar, 'blockInputEvents': cc.BlockInputEvents }; let cp = node.addComponent(classes[component.name]); if (component.name == 'graphics' && component.drawFunc) { component.drawFunc(cp); } for (let prop of props[component.name]) { // if (prop == 'sizeMode') { // debugger; // } if (prop == 'spriteFrame') { let value = component[prop]; if (value != undefined) { if (typeof (value) == 'string') { cp[prop] = spriteFrames[value]; } if (value instanceof cc.SpriteFrame) { cp[prop] = value; } } } else { cp[prop] = component[prop] !== undefined ? component[prop] : cp[prop]; } } } request(method, url, data) { return new Promise((resolve, reject) => { let timeoutcb = setTimeout(() => { reject('timeout'); }, 3000); if (typeof (wx) != "undefined") { let xhr = new XMLHttpRequest(); xhr.onreadystatechange = () => { if (xhr.readyState == 4) { clearTimeout(timeoutcb); if ((xhr.status >= 200 && xhr.status < 400)) { let res = xhr.responseText; try { res = JSON.parse(res); } catch (e) { reject('json parse err'); } resolve(res); } else { reject('server error: ' + xhr.status); } } }; xhr.open(method, url, true); xhr.setRequestHeader('Content-Type', 'application/json'); if (typeof(wx) !== 'undefined') { xhr.send(data || {}); } else { xhr.send(JSON.stringify(data || {})); } } else { clearTimeout(timeoutcb); reject(); } }); } loadRemoteImage(url) { return new Promise((resolve, reject) => { if (url) { let image = new Image(); image.src = url; image.crossOrigin = "Anonymous"; image.onload = () => { let texture = new cc.Texture2D(); texture.initWithElement(image); texture.handleLoadedTexture(); resolve(texture); }; image.onerror = () => { resolve(new cc.Texture2D()); } } else { resolve(null); } }); } createUI() { if (this.loadSuccess) { this.scrollView = this.createScrollView(); this.root.addChild(this.scrollView); this.bindScrollEvents(this.scrollView); this.gameListContainer = this.createContainer(); this.scrollView.addChild(this.gameListContainer); this.scrollView.getComponent(cc.ScrollView).content = this.gameListContainer; this.gameListPanels = this.createGameListPanels(this.gameListContainer); this.moreGamePanel = this.createMoreGamePanel(this.gameListContainer); if (this.bannerImg) { this.gameBanner = this.createGameBanner(this.gameListContainer); } } else { this.createOffLineUI(); } } createOffLineUI() { let options = { name: 'offline-tips-container', width: this.choose(720, 1280), height: this.choose(1280, 720), scaleX: this.measureScale, scaleY: this.measureScale, children: [ { name: 'offline-tips', width: 219, height: 265, y: this.choose(171, 27), components: [{ name: 'sprite', spriteFrame: new cc.SpriteFrame(this.offlineTips) }] }, { name: 'offline-text', y: this.choose(17, -127), color: cc.hexToColor('#525252'), height: 23, components: [{ name: 'label', string: '您的网络貌似有问题,请刷新试试哦', fontSize: 22 }] }, { name: 'reconnect-btn', y: this.choose(-64, -208), components: [{ name: 'sprite', spriteFrame: new cc.SpriteFrame(this.reconnectBtn) }], children: [{ name: 'btn-text', color: cc.hexToColor('#3086de'), components: [{ name: 'label', string: '刷新', fontSize: 28, verticalAlign: cc.Label.VerticalAlign.CENTER }] }] } ] }; this.offlineNode = this.createNode(options); this.root.addChild(this.offlineNode); cc.find('reconnect-btn', this.offlineNode).on(cc.Node.EventType.TOUCH_START, (e) => { this.fetchData(true); }); } createScrollView() { let options = { name: '3666-game-scrollview', width: this.mode == 'portrait' ? 720 : 1280, height: this.mode == 'portrait' ? 1280 : 720, x: 0, y: 0, components: [ { name: 'scrollview', vertical: this.mode == 'portrait', horizonal: this.mode == 'landscape', elastic: false }, { name: 'mask', type: cc.Mask.Type.RECT } ] // children: [ // { // name: 'scroll-bar', // width: this.mode == 'portrait' ? 5 : 1120, // height: this.mode == 'portrait' ? 1120 : 5, // components: [ // { // name: 'scrollbar', // direction: this.mode == 'portrait' ? cc.Scrollbar.Direction.VERTICAL : cc.Scrollbar.Direction.HORIZONTAL, // enableAutoHide: true // }, // { // name: 'widget', // isAlignBottom: this.mode == 'portrait', // isAlignTop: this.mode == 'landscape', // top: 10, // bottom: 0, // isAlignRight: true, // right: this.mode == 'portrait' ? 10 : 0 // }, // { // name: 'graphics', // drawFunc: (graphics) => { // this.drawRect(graphics, this.mode == 'portrait' ? 5 : 1120, this.mode == 'portrait' ? 1120 : 5, cc.hexToColor('#cccccc')); // } // } // ], // children: [{ // name: 'bar', // width: this.mode == 'portrait' ? 7 : 30, // height: this.mode == 'portrait' ? 30 : 7, // components: [ // { // name: 'sprite', // spriteFrame: new cc.SpriteFrame(this.bar) // } // ] // }] // } // ] }; let node = this.createNode(options); // let scrollBar = cc.find('scroll-bar', node); // let bar = cc.find('scroll-bar/bar', node); // scrollBar.getComponent(cc.Scrollbar).handle = bar.getComponent(cc.Sprite); // node.getComponent(cc.ScrollView).verticalScrollBar = scrollBar.getComponent(cc.Scrollbar); node.scaleX = node.scaleY = this.measureScale; // 大小适配(等比例缩放) return node; } bindScrollEvents(node) { node.on('scroll-ended', () => { this.checkExposedGames(); }); } // 检查曝光的游戏并上报(曝光条件:在显示屏幕区域占一半以上) checkExposedGames(first = false) { let component = this.scrollView.getComponent(cc.ScrollView); let offset = component.getScrollOffset(); let gameOffset; let datas = []; if (this.mode == 'landscape') { gameOffset = -offset.x } else { gameOffset = offset.y; } if (first) gameOffset = 0; let extraNum = 2; if (!this.moreGameIcons || this.moreGameIcons.length == 0) { extraNum = 1; } // 检测游戏曝光 for (let i = 0; i < this.games.length + extraNum; ++i) { let x = this.choose(145 + i * 227, 51 + i * 302); if (x > gameOffset - this.choose(PORTRAIT_ITEM_HEIGHT, LANDSCAPE_ITEM_WIDTH) / 2 && x + this.choose(PORTRAIT_ITEM_HEIGHT, LANDSCAPE_ITEM_WIDTH) < gameOffset + 1280 + this.choose(PORTRAIT_ITEM_HEIGHT, LANDSCAPE_ITEM_WIDTH) / 2) { if (i < this.games.length && !this.games[i].exposed) { this.games[i].exposed = true; this.reportItem(datas, i, 100, 2); } if (i >= this.games.length) { let name = this.specPanels[i - this.games.length]; if (name == 'more-game' && !this.moreGameIsExposed) { this.reportItem(datas, null, 100, 3); this.moreGameIsExposed = true; } if (name == 'game-banner' && !this.bannerIsExposed) { this.reportItem(datas, null, 100, 4); this.bannerIsExposed = true; } } } else { if (i < this.games.length) { this.games[i].exposed = false; } else { var name = this.specPanels[i - this.games.length]; if (name == 'more-game') { this.moreGameIsExposed = false; } if (name == 'game-banner') { this.bannerIsExposed = false; } } } } if (datas.length > 0) { this.report(datas); // 统一批量上报 } } // 生成单个上报数据 reportItem(datas, i, actionId, slotId) { let data = { iSceneLevel1: 1000000, iSceneLevel2: slotId, iActionId: actionId, iResourceId2: this.appid, vV1: 1 }; if (i !== null) { data.iSceneLevel3 = i + 1; data.iResourceId1 = this.games[i].app_id; } else { data.iSceneLevel3 = 1; } datas.push(data); } createContainer() { let extraNum = 0; if (this.moreGameIcons && this.moreGameIcons.length > 0) { ++extraNum; } if (this.banner) { ++extraNum; } let landscapeWidth = (this.games.length + extraNum) * (LANDSCAPE_ITEM_WIDTH + LANDSCAPE_ITEM_SPACE) + 72; let portraitHeight = (this.games.length + extraNum) * (PORTRAIT_ITEM_HEIGHT + PORTRAIT_ITEM_SPACE) + 145; let options = { name: 'container', width: this.choose(720, landscapeWidth), height: this.choose(portraitHeight, 720), // x: this.choose(0, (this.games.length > 3 ? landscapeWidth / 2 - 640 : 0)), x: this.choose(0, (landscapeWidth / 2 - 640)), y: this.choose((this.games.length > 3 ? 640 - portraitHeight / 2 : 0), 0), components: [ { name: 'widget', isAlignHorizontalCenter: this.mode == 'portrait', isAlignVerticalCenter: this.mode == 'landscape' }, { name: 'layout', type: this.mode == 'portrait' ? cc.Layout.Type.VERTICAL : cc.Layout.Type.HORIZONTAL, paddingTop: this.choose(145 - 5, 100), // paddingBottom: this.choose(undefined, 70 - 18), paddingLeft: this.choose(0, 51 - 7), spacingY: this.choose(PORTRAIT_ITEM_SPACE - 20, 0), spacingX: this.choose(0, LANDSCAPE_ITEM_SPACE - 16) } ] }; let node = this.createNode(options); return node; } createGameListPanels(parent) { let panels = []; let panelFrame = new cc.SpriteFrame(this.panel); panelFrame.insetTop = 13; panelFrame.insetBottom = 23; panelFrame.insetLeft = 17; panelFrame.insetRight = 19; for (let i = 0; i < this.games.length; ++i) { let desc = this.games[i].desc; if (this.mode == 'portrait') { if (desc.length > 16) { desc = desc.substr(0, 15) + '...'; } } else { if (desc.length > 20) { desc = desc.substr(0, 19) + '...'; } } let realWidth = this.choose(PORTRAIT_ITEM_WIDTH + 16, LANDSCAPE_ITEM_WIDTH + 16); let realHeight = this.choose(PORTRAIT_ITEM_HEIGHT + 20, LANDSCAPE_ITEM_HEIGHT + 20); let options = { name: 'game-item', width: realWidth, x: 0, y: this.choose(0, -80), anchorX: 0.5 - 1 / (realWidth * 2), anchorY: 0.5 + 5 / realHeight, height: realHeight, components: [ { name: 'sprite', spriteFrame: panelFrame, type: cc.Sprite.Type.SLICED, sizeMode: cc.Sprite.SizeMode.CUSTOM, trim: false } ], children: [ { name: 'icon-bg', width: 130, height: 130, x: this.choose(-250, 0), y: this.choose(0, 200), components: [{ name: 'sprite', spriteFrame: new cc.SpriteFrame(this.circle) }], active: this.mode == 'landscape' }, { name: 'icon', x: this.choose(-250, 0), y: this.choose(0, 205), width: 122, height: 122, components: [ { name: 'sprite', sizeMode: cc.Sprite.SizeMode.CUSTOM, type: cc.Sprite.Type.SIMPLE, spriteFrame: new cc.SpriteFrame(this.gameIcons[i]) } ] }, { name: 'name', x: this.choose(-165, 0), y: this.choose(55, 78), width: this.choose(440, 205), height: this.choose(48, 72), color: cc.hexToColor('#000000'), anchorX: this.choose(0, 0.5), anchorY: this.choose(1, 1), components: [{ name: 'label', horizontalAlign: this.choose(cc.Label.HorizontalAlign.LEFT, cc.Label.HorizontalAlign.CENTER), overflow: cc.Label.Overflow.RESIZE_HEIGHT, fontSize: this.choose(40, 30), lineHeight: this.choose(48, 42), string: this.games[i].name.length > 12 ? this.games[i].name.substr(0, 11) + '...' : this.games[i].name }], }, { name: 'line', // width: this.choose(476, 200), scaleX: this.choose(476 / 66, 200 / 66), height: 1, x: this.choose(73, 0), y: this.choose(1, -40), active: this.mode == 'portrait', components: [ { name: 'sprite', spriteFrame: new cc.SpriteFrame(this.line), type: cc.Sprite.Type.SIMPLE, sizeMode: cc.Sprite.SizeMode.COSTOM // drawFunc: (graphics) => { // graphics.lineWidth = 1; // graphics.strokeColor = cc.hexToColor('#999999'); // graphics.moveTo(0, 0); // graphics.lineTo(476, 0); // graphics.stroke(); // } } ] }, { name: 'desc', x: this.choose(-165, 0), y: this.choose(-11, -26), width: this.choose(416, 220), height: this.choose(31, 36), anchorX: this.choose(0, 0.5), anchorY: this.choose(1, 1), color: cc.hexToColor('#999999'), components: [{ name: 'label', horizontalAlign: this.choose(cc.Label.HorizontalAlign.LEFT, cc.Label.HorizontalAlign.CENTER), verticalAlign: cc.Label.VerticalAlign.TOP, overflow: cc.Label.Overflow.RESIZE_HEIGHT, fontSize: this.choose(26, 22), lineHeight: this.choose(31, 36), string: desc }] } ], }; let node = this.createNode(options); this.bindTouchEvent(node, ((currentIndex) => { return () => { let datas = []; this.reportItem(datas, currentIndex, 101, 2); this.report(datas); this.showQrcode(this.games[currentIndex]); }; })(i)); panels.push(node); } for (let panel of panels) { parent.addChild(panel); } return panels; } bindTouchEvent(node, cb) { let distance, x1, y1, x2, y2; node.on(cc.Node.EventType.TOUCH_START, (e) => { let loc = e.getLocation(); x1 = loc.x; y1 = loc.y; }); node.on(cc.Node.EventType.TOUCH_END, (e) => { let loc = e.getLocation(); x2 = loc.x; y2 = loc.y; distance = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); if (distance < 25) { if (!this.touching) { this.touching = true; setTimeout(() => { this.touching = false; }, 10); cb(); } } }); } showQrcode(data) { if (typeof (wx) != 'undefined') { wx.previewImage({ urls: [data.qrcode] }); } } createTitle() { let options = { name: 'title', // x: -this.width / 2, // y: -this.height / 2, x: 0, y: this.root.height / 2 - 60 * this.measureScale, width: this.root.width, height: 120 * this.measureScale, components: [ // { // name: 'widget', // isAlignTop: true, // top: 0 // }, { name: 'blockInputEvents' }, { name: 'graphics', drawFunc: (graphics) => { this.drawRect(graphics, this.root.width, 120 * this.measureScale); } } ], children: [ { name: 'title-container', width: this.root.width, height: 120 * this.measureScale, children: [ { name: 'arrow_container', width: this.choose(21 * 0.8 + 60, 21 * 0.8 + 50), height: 120, scaleX: this.measureScale, scaleY: this.measureScale, children: [{ name: 'button_arrow', width: 21, height: 37, components: [ { name: 'sprite', type: cc.Sprite.Type.SIMPLE, sizeMode: cc.Sprite.SizeMode.CUSTOM, spriteFrame: new cc.SpriteFrame(this.blackArrow) } ] }], components: [{ name: 'widget', isAlignLeft: true, left: 0, isAlignVerticalCenter: true }] }, { name: 'title-text', color: cc.hexToColor('#000000'), height: 46, x: this.choose(0, -438), scaleX: this.measureScale, scaleY: this.measureScale, components: [ { name: 'richText', string: '精彩游戏推荐', horizontalAlign: cc.RichText.HorizontalAlign.CENTER, fontSize: 34, lineHeight: 36 }, { name: 'widget', isAlignHorizontalCenter: this.choose(true, false), isAlignVerticalCenter: true, isAlignLeft: this.mode == 'landscape', left: 90 * this.measureScale } ] } ] } ] }; let node = this.createNode(options); let backBtn = cc.find('title-container/arrow_container', node); backBtn.on(cc.Node.EventType.TOUCH_START, () => { this.hide(); }); return node; } createMoreGamePanel(parent) { if (!this.moreGameIcons || this.moreGameIcons.length == 0) { return null; } let panels = []; let panelFrame = new cc.SpriteFrame(this.panel); panelFrame.insetTop = 13; panelFrame.insetBottom = 23; panelFrame.insetLeft = 17; panelFrame.insetRight = 19; let realWidth = this.choose(PORTRAIT_ITEM_WIDTH + 16, LANDSCAPE_ITEM_WIDTH + 16); let realHeight = this.choose(PORTRAIT_ITEM_HEIGHT + 20, LANDSCAPE_ITEM_HEIGHT + 20); let options = { name: 'more-game-panel', width: realWidth, height: realHeight, anchorX: 0.5 - 1 / realWidth, anchorY: 0.5 + 5 / realHeight, y: this.choose(0, -80), components: [ // { // name: 'graphics', // drawFunc: (graphics) => { // this.drawRoundRect(graphics, this.choose(PORTRAIT_ITEM_WIDTH, 250), this.choose(PORTRAIT_ITEM_HEIGHT, 400)); // } // } { name: 'sprite', spriteFrame: panelFrame, type: cc.Sprite.Type.SLICED, sizeMode: cc.Sprite.SizeMode.CUSTOM, trim: false } ], children: [] }; for (let i = 0; i < 3; ++i) { if (this.moreGameIcons && this.moreGameIcons[i]) { options.children.push( { name: 'icon', width: this.choose(86 + 2 * 86 / 120, 70 + 2 * 70 / 120), height: this.choose(86 + 2 * 86 / 120, 70 + 2 * 70 / 120), x: this.choose(-267 + 106 * i, -76 + 76 * i), y: this.choose(0, 50), components: [ { name: 'sprite', sizeMode: cc.Sprite.SizeMode.CUSTOM, type: cc.Sprite.Type.SIMPLE, spriteFrame: new cc.SpriteFrame(this.moreGameIcons[i]) } ] } ); } } options.children.push({ name: 'more-game', color: cc.hexToColor('#000000'), width: 144, height: this.choose(42, 32), x: this.choose(150, -10), y: this.choose(0, -75), components: [ { name: 'label', string: '更多好玩', horizontalAlign: cc.Label.HorizontalAlign.CENTER, fontSize: this.choose(40, 30), lineHeight: this.choose(42, 32) } ] }); let btnWidth = 22 * 32 / 37; options.children.push({ name: 'button_arrow', width: btnWidth, height: 32, x: this.choose((PORTRAIT_ITEM_WIDTH / 2 - 50 - btnWidth / 2), (LANDSCAPE_ITEM_WIDTH / 2 - 45 - btnWidth / 2)), y: this.choose(-1, -76), components: [ { name: 'sprite', type: cc.Sprite.Type.SIMPLE, sizeMode: cc.Sprite.SizeMode.CUSTOM, spriteFrame: new cc.SpriteFrame(this.greyArrow) } ] }); let node = this.createNode(options); this.bindTouchEvent(node, () => { let datas = []; this.reportItem(datas, null, 101, 3); this.report(datas); if (typeof (wx) !== 'undefined') { wx.previewImage({ urls: [this.moreGameQrcode] }); } }); parent.addChild(node); this.specPanels.push('more-game'); return node; } drawArrow(ctx, w, h, lineWidth, color = '#999999') { ctx.lineWidth = lineWidth || 5; ctx.strokeColor = cc.hexToColor(color); ctx.moveTo(0, 0); ctx.lineTo(w, h / 2); ctx.lineTo(0, h); ctx.stroke(); } createGameBanner(parent) { let options = { name: 'game-banner', width: this.choose(PORTRAIT_ITEM_WIDTH, LANDSCAPE_ITEM_WIDTH), height: this.choose(PORTRAIT_ITEM_HEIGHT, LANDSCAPE_ITEM_HEIGHT), y: this.choose(0, -70), children: [{ name: 'game-banner-img', width: this.choose(PORTRAIT_ITEM_WIDTH, LANDSCAPE_ITEM_WIDTH), height: this.choose(PORTRAIT_ITEM_HEIGHT, LANDSCAPE_ITEM_HEIGHT), x: this.choose(2, 11), components: [{ name: 'sprite', sizeMode: cc.Sprite.SizeMode.CUSTOM, type: cc.Sprite.Type.SIMPLE, spriteFrame: new cc.SpriteFrame(this.bannerImg) }, { name: 'widget', isAlignTop: true, top: this.choose(5, 9) }] }] }; let node = this.createNode(options); this.bindTouchEvent(node, () => { let datas = []; this.reportItem(datas, null, 101, 4); this.report(datas); if (typeof (wx) !== 'undefined') { wx.previewImage({ urls: [this.poster] }); } }); parent.addChild(node); this.specPanels.push('game-banner'); return node; } initRoot() { this.root = new cc.Node('wx-game-cross'); this.calSize(); } initTitle() { this.loadRemoteImage(BLACKARROW).then((texture) => { this.blackArrow = texture; this.title = this.createTitle(); this.title.zIndex = 1; this.root.addChild(this.title); }); } calSize() { this.root.setPosition(0, 0); this.width = Math.ceil(this.window.width); this.height = Math.ceil(this.window.height); if (this.width > this.height) { this.mode = 'landscape'; if (this.width / this.height > 1280 / 720) { this.measureScale = this.height / 720; // 比例尺,根据实际游戏高度换算 this.root.width = this.width; this.root.height = 720 * this.measureScale; } else { this.measureScale = this.width / 1280; // 比例尺,根据实际游戏宽度换算 this.root.width = 1280 * this.measureScale; this.root.height = this.height; } } else { this.mode = 'portrait'; if (this.width / this.height > 720 / 1280) { this.measureScale = this.height / 1280; this.root.width = this.width; this.root.height = 1280 * this.measureScale; } else { this.measureScale = this.width / 720; // 比例尺,根据实际游戏宽度换算 this.root.width = 720 * this.measureScale; this.root.height = this.height; } } this.root.active = false; } createBackground() { this.background = this.createNode({ name: 'wx-cross-background', width: this.root.width, height: this.root.height, components: [ { name: 'graphics', drawFunc: (graphics) => { this.drawRect(graphics, this.root.width, this.root.height, cc.hexToColor('#f5f5f5'), 256); } } ] }); this.root.addChild(this.background); } drawRect(ctx, width, height, color = cc.Color.WHITE, opacity = 256) { let fillColor = color; // fillColor.a = opacity; ctx.fillColor = fillColor; ctx.rect(0, 0, width, height); ctx.fill(); } drawRoundRect(ctx, width, height, color = cc.Color.WHITE, opacity = 256) { ctx.fillColor = color; ctx.fillColor.opacity = opacity; ctx.roundRect(0, 0, width, height, 15); ctx.fill(); } hide() { this.root.active = false; for (let game of this.games) { game.exposed = false; } this.moreGameIsExposed = false; this.bannerIsExposed = false; } show() { if (this.scrollView) { this.firstReport(); } this.root.active = true; } firstReport() { let datas = []; this.reportItem(datas, null, 100, 1); this.report(datas); this.checkExposedGames(this.firstShow); this.firstShow = false; } report(datas) { let map = { dtLoginTime: -1, vQimei: -1, vAppVer: -1, PlatID: -1, vOsType: -1, osversion: -1, nettype: -1, model: -1, iActionId: -1, iSceneLevel1: -1, iSceneLevel2: -1, iSceneLevel3: -1, iResourceId1: -1, iResourceId2: -1, iResourceId3: -1, iResourceId4: -1, iResourceId5: -1, iRet: -1, vV1: -1, vV2: -1, vV3: -1, vV4: -1, vV5: -1, vV6: -1, vV7: -1, vV8: -1, vV9: -1, vV10: -1, }; return new Promise((resolve, reject) => { datas = datas.map(item => { let data = Object.assign({}, map, item); let content = (() => { let arr = []; Object.keys(data).forEach(key => arr.push(data[key])); return arr.join('|'); })(); return content; }); this.request('POST', 'https://goplatform.minigame.qq.com/mpreport/reportplugintlog', { data: datas, session: this.session }); }); } choose(portraitVal, landscapeVal) { return this.mode == 'portrait' ? portraitVal : landscapeVal; } } // 营销插件渠道进入上报 function enterReport(appid = '', userid = '') { let launchOptions = { query: '' }; if (typeof (wx) != "undefined") { launchOptions = wx.getLaunchOptionsSync(); } let plan = ''; let query = launchOptions.query; const getParam = (search, key) => { const reg = new RegExp(`(^|&)${key}=([^&]*)(&|$)`); const r = search.substr(1).match(reg); if (r !== null) return String(decodeURIComponent(r[2])); return ''; }; if (query.scene) { let scene = decodeURIComponent(query.scene); plan = getParam(scene, 'plan'); } else { if (query.path) { plan = getParam(query.path, 'plan'); } } if (plan !== '') { let url = 'https://goplatform.minigame.qq.com/mpreport/reportsource'; let xhr = new XMLHttpRequest(); xhr.open('POST', url, true); xhr.setRequestHeader('Content-Type', 'application/json'); if (typeof(wx) !== 'undefined') { xhr.send({ appid, userid, from: '', plan }); } else { xhr.send(JSON.stringify({ appid, userid, from: '', plan })); } } } export { RecommendUI, enterReport }