QQ玩一玩广告与音效使用总结

QQ玩一玩广告与音效使用总结

1、经常遇到的问题

  • 观看视频广告时背景音乐没有关闭
  • 视频广告看完背景音乐重叠
  • 游戏回到后台再回到前台时背景音乐重叠

开发环境

  • CocosCreator V2.0.5
  • 手Q版本 V7.9.0.3820(目前市场中最新版本)
  • qqPlayCore.js buildTime:'Fri Nov 09 2018 13:20:45 GMT+0800 (GMT+08:00)'上出现,此版本的qqPlayCore.js也是最新能正常使用的版本。

顺便提一下,最新版本的qqPlayCore.js buildTime:'Wed Nov 21 2018 15:26:39 GMT+0800 (GMT+08:00)' 使用时会出现 “Canvas fillStyle 传入不合法数据”的警告弹窗但不影响其他接口的使用。

解决方案:

1、qqPlayCore.js 回退到之前最新版本 buildTime:'Fri Nov 09 2018 13:20:45 GMT+0800 (GMT+08:00)’
2、如果非要使用新版本可以设置不显示错误弹框,默认显示错误弹框。 BK.Script.errorAlertOpen = false

2、音频使用封装

游戏启动页(Home场景下)设置GlobalAudio 为常驻节点并挂载音效脚本组件

全局音效常驻节点

音效脚本组件 AudioClip.js

这里播放音效直接使用的是CocosCreator引擎提供的 AudioEngine 组件

/**
 * @author Javen 
 * @copyright 2018-10-31 16:24:42 javendev@126.com 
 * @description  音效与背景音乐组件
 */
var Global = require("./Global");
cc.Class({
  extends: cc.Component,
  properties: {

    onClickAudio: {
      default: null,
      tooltip: "按钮点击音效",
      type: cc.AudioClip,
    },

    bgmAudio: {
      default: null,
      tooltip: "背景音效",
      type: cc.AudioClip
    },

  },

  playClickAudio() {
    if (Global.isAudio) {
      cc.audioEngine.play(this.onClickAudio, false, 1);
    }

  },

  playBgmAudio() {
    if (Global.isAudio && (!this.bgmAudioId || this.getState(this.bgmAudioId) != cc.audioEngine.AudioState.PLAYING)) {
      cc.audioEngine.play(this.bgmAudio, true, 1);
    }
  },

  //暂停现在正在播放的所有音频
  pauseAll() {
    cc.audioEngine.pauseAll();
  },
  //恢复播放所有之前暂停的所有音频
  resumeAll() {
    cc.audioEngine.resumeAll();
  },
  stopAll() {
    cc.audioEngine.stopAll();
  },
  getState(id) {
    return cc.audioEngine.getState(id);
  },
  // onLoad() {},
  // start () {},

  // update (dt) {},
});

那么问题来了,全局如何使用?

我们来自定义一个组件CustomComponent.js,其他的组件如果要使用到音效就继承此组件。具体实现如下

/**
 * @author Javen 
 * @copyright 2018-10-26 16:13:11 javendev@126.com 
 * @description 自定义组件
 */

cc.Class({
    extends: cc.Component,
    start() {
        try {
            //查询WebSocket节点并获取音效组件WebSocket
            this._webSocket = cc.find("WebSocket").getComponent("WebSocket");
            //查询GlobalAudio节点并获取音效组件AudioClip
            this._audioClip = cc.find("GlobalAudio").getComponent("AudioClip");
        } catch (error) {}
    },
    //下面的方法可要可无,只是为了方便在其他组件中调用,不用写重复的代码。
    playClickAudio: function () {
        if (this._audioClip) {
            this._audioClip.playClickAudio();
        }
    },
    playBgmAudio: function () {
        if (this._audioClip) {
            this._audioClip.playBgmAudio();
        }
    },
});

使用案例

/**
 * @author Javen 
 * @copyright 2018-12-07 15:51:19 javendev@126.com 
 * @description QQ玩一玩示例 
 */

let customComponent = require("./common/CustomComponent");

cc.Class({
    extends: customComponent,//继承至自定义的组件 customComponent

    properties: {},
    
    btnClick(event, data) {
        this.playClickAudio(); //CustomComponent 父类中的方法
    }

    // onLoad () {},

    start() {
        this._super();//切忌不要忘记 否者playBgmAudio、playClickAudio 这些父类的方法执行时会提示没有定义
        this.playBgmAudio();//CustomComponent 父类中的方法
    },

    // update (dt) {},
});

3、视频广告以及banner广告封装

注意看注释,上面提到的前两个问题可以完美的解决

封装的代码已开源-封装源码地址-使用案例源码地址

/**
 * 展示广告 Global.videoAd.show();
 * 预加载视频广告
 */
function loadVideoAd() {
    if (!Global.videoAd && cc.sys.platform == cc.sys.QQ_PLAY) { //如果没有广告资源就加载新的视频广告
        let videoAd = BK.Advertisement.createVideoAd();
        videoAd.onError(function (err) {
            //加载失败
            log("BKTools onError code:" + err.code + " msg:" + err.msg);
            Global.viewAdLoadCount += 1;
            if (Global.viewAdLoadCount < 4) {
                loadVideoAd();
            }
        });

        videoAd.onPlayFinish(function () {
            //播放结束
            log("BKTools onPlayFinish...");
            Global.videoAd = undefined;
        });
        videoAd.onClose(function () {
            //播放结束
            log("BKTools onClose...");
            Global.videoAd = undefined;
        });

        videoAd.onLoad(function () {
            //加载成功
            log("BKTools onLoad");
            Global.videoAd = videoAd;
            Global.videoAdLoadCount = 0;
        });
    } else {
        log("BKTools 已存在广告资源 或者 非QQ玩一玩平台....");
    }
}

/**
 * 展示广告 Global.bannerAd.show();
 * 预加载banner广告
 */
function loadBannerAd(viewId) {
    if (!viewId) {
        viewId = 1001;
    }
    if (!Global.bannerAd && cc.sys.platform == cc.sys.QQ_PLAY) { //如果没有广告资源就加载新的视频广告
        let bannerAd = BK.Advertisement.createBannerAd({
            viewId: viewId,
        });
        bannerAd.onError(function (err) {
            //加载失败
            log("BKTools onError code:" + err.code + " msg:" + err.msg);
            Global.bannerAdLoadCount += 1;
            if (Global.bannerAdLoadCount < 4) {
                loadBannerAd(viewId);
            }
        });
        bannerAd.onLoad(function () {
            //加载成功
            log("BKTools onLoad");
            Global.bannerAd = bannerAd;
            Global.viewAdLoadCount = 0;
        });
    } else {
        log("BKTools 已存在banner资源 或者 非QQ玩一玩平台....");
    }
}

function showBannerAd() {
    if (Global.bannerAd) {
        Global.bannerAd.show();
    } else {
        log("BKTools 不存在banner资源....");
        loadBannerAd();
    }
}

function hideBannerAd() {
    if (Global.bannerAd) {
        Global.bannerAd.hide();
        Global.bannerAd = undefined;
        loadBannerAd();
    } else {
        log("BKTools 不存在banner资源无法关闭....");
    }
}

使用案例

case "adVideo":
    let videoAd = Global.videoAd;
    if (videoAd) {
        videoAd.show();//展示视频广告
        videoAd.onPlayStart(function () {
            BKTools.log("video ad onPlayStart...");
            //QQ玩一玩或者是引擎的bug 播放广告时没有关闭背景音效需要手动处理
            if (Global.isAudio) {
                //this._audioClip.pauseAll();
                this._audioClip.stopAll();
            }
        }.bind(this));
        videoAd.onPlayFinish(function () {
            //播放结束
            BKTools.log("video ad onPlayFinish...");
            //业务逻辑处理.....
        }.bind(this));
        videoAd.onClose(function () {
            BKTools.log("video ad  onClose...");
            if (Global.isAudio) {
                //this._audioClip.resumeAll();
                this._audioClip.playBgmAudio();//恢复背景音效
            }
        }.bind(this));
    } else {
        BKTools.log("暂无广告资源.....");
        BKTools.loadVideoAd();//加载视频广告
    }
    break;
case "banner":
    BKTools.showBannerAd(1002);//显示banner广告
    break;
case "hideBanner":
    BKTools.hideBannerAd();//隐藏banner广告
    break;

好了,到此已解决了前两个问题。游戏回到后台再回到前台时背景音乐重叠的问题如何解决呢? 此时你可能会想到游戏是否有提供游戏生命周期的回调呢?

翻翻文档不难发现是有提供的 —— 最新版本的生命周期函数文档

4、QQ玩一玩生命周期函数事件监听

在CocosCreator中如何实现QQ玩一玩生命周期函数事件监听?最后一个问题的解决方案注意看注释

这里可以使用常驻节点来实现,具体实现如下

生命周期函数事件监听常驻节点设置
/**
 * @author Javen 
 * @copyright 2018-10-22 15:04:24 javendev@126.com 
 * @description QQPlay 事件监听
 */

let BKTools = require("./BKTools");
let Utils = require("./Utils");
let Global = require("./Global");
let CustomComponent = require("./CustomComponent");
cc.Class({
    extends: CustomComponent,

    // properties: {},

    // onLoad () {},

    start() {
        this._super();
        if (cc.sys.platform == cc.sys.QQ_PLAY) {
            BKTools.log('QQPlayerEvent QQ玩一玩平台');
            this._onQQPlayEvent();
        } else {
            BKTools.log('QQPlayerEvent 非QQ玩一玩平台');
        }
    },
    _enterForegroundListener() {
        BKTools.log('进入前台');
        this._audioClip.playBgmAudio();//重新播放音效
    },
    _enterBackgroundListener() {
        BKTools.log('退出前台');
        //this._audioClip.pauseAll();
        this._audioClip.stopAll();//测试发现有时候背景音效不会重叠,为了彻底解决此问题就停止所有音效。缺点是在恢复播放时需要单独处理播放进度问题 可以通过 getCurrentTime 获取当前的播放时间, 在恢复时setCurrentTime再调用play
    },
    _gameCloseListener() {

        //上报操作
        let score = Utils.getRandomInt(0, 100);
        BKTools.log('关闭游戏:' + score);
        BKTools.uploadScore(score, function (errorCode) {
            if (errorCode == 0) {
                BKTools.log("数据上报成功......");
            } else {
                BKTools.log("数据上报失败......");
            }
        });
    },
    _maximizeListener() {
        BKTools.log('最大化');
    },
    _minimizeListener() {
        BKTools.log('最小化');
    },
    _onNetworkChangeListener(data) {
        BKTools.log(data);
        if (data.state == BK.NetworkState.NoneToMobileNetwork) {
            BKTools.log('从无网络到移动网络');
        } else if (data.state == BK.NetworkState.NoneToWifi) {
            BKTools.log('无网络到WiFi网络');
        } else if (data.state == BK.NetworkState.MobileNetworkToWifi) {
            BKTools.log('移动网络到WiFi网络');
        } else if (data.state == BK.NetworkState.MobileNetworkToNone) {
            BKTools.log('移动网络到无网络');
        } else if (data.state == BK.NetworkState.WifiToNone) {
            BKTools.log('WiFi到无网络');
        } else if (data.state == BK.NetworkState.WifiToMobileNetwork) {
            BKTools.log('WiFi到移动网络');
        }
    },
    _onShareCompleteListener(data) {
        //shareDest 0为QQ 1为QZone 2为微信 3为朋友圈  isFirstShare永远为true
        BKTools.log("分享完成: retCode:" + data.retCode + ',isFirstShare:' + data.isFirstShare + ',dest:' + data.shareDest);
    },
    _onShareListener() {
        BKTools.log("调用分享接口时回调,分享了...");
        //无法自定义分享
    },
    _onQQPlayEvent() {
        BK.onEnterForeground(this._enterForegroundListener.bind(this));
        BK.onEnterBackground(this._enterBackgroundListener.bind(this));
        BK.onGameClose(this._gameCloseListener.bind(this));
        BK.onMaximize(this._maximizeListener.bind(this));
        BK.onMinimize(this._minimizeListener.bind(this));
        BK.onNetworkChange(this._onNetworkChangeListener.bind(this));
        BK.onGameShareComplete(this._onShareCompleteListener.bind(this));
        BK.onGameShare(this._onShareListener.bind(this));
    },


    // update (dt) {},
});

5、 源码

CocosCreator开发小游戏示例: Brickengine_Guide

  • QQPlay为旧版本QQ玩一玩示例
  • QQPlay_New为新版本QQ玩一玩示例

到这里就介绍完了,个人能力有限如有错误欢迎指正,如有遗漏欢迎补充。如有疑问欢迎留言一起交流讨论。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 116,204评论 1 233
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 50,160评论 1 197
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 71,039评论 0 162
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 34,934评论 0 124
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 41,701评论 1 204
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 34,560评论 1 124
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 26,540评论 2 204
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 25,717评论 0 117
  • 想象着我的养父在大火中拼命挣扎,窒息,最后皮肤化为焦炭。我心中就已经是抑制不住地欢快,这就叫做以其人之道,还治其人...
    爱写小说的胖达阅读 24,668评论 5 169
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 28,718评论 0 176
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 25,985评论 1 166
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 27,220评论 1 173
  • 白月光回国,霸总把我这个替身辞退。还一脸阴沉的警告我。[不要出现在思思面前, 不然我有一百种方法让你生不如死。]我...
    爱写小说的胖达阅读 21,590评论 0 24
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 24,192评论 2 162
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 27,945评论 3 170
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 22,948评论 0 4
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 23,087评论 0 112
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 29,152评论 2 183
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 29,596评论 2 186

推荐阅读更多精彩内容