• 心动女友框架分析


     文档结构

    一 游戏入口

    二 游戏统计

    三 视频播放、音频播放

    四 支付

    五 http通讯

    六 游戏配置文件

    七 关键字屏蔽

    八 新手指引

     

    文档结构

    cocos2d-js-min.js    cocos引擎

    egreth5sdk.js           白鹭SDK

    exif.js                       ???

    gameApi.js              游戏API(充值、分享统计等)

    gameCenterSA.js    ???

    main.js                    充值、统计、发送桌面

    project.js                 游戏主文件

    settings.js               ???

    zm_engine_v2.js     ???

     

    代码:

    Global.js              全局支付、请求指引

    data.js                 对话配置、关键词屏蔽

    gconst.js              全局常量 (字体名、商品类型等游戏变量)

    gevent.js              事件名

    glang.js                全局语言(所有动态文本的固定文字)

    gplayer.js             游戏主类

    grpc.js                  http通讯

    gsdk.js                 原生交互、cordova视频、支付

    gutils.js                数组、字符串等数据处理

     

    guideUI.js            新手指引

    createRole.js       创建角色(昵称)

    gwnd.js                升级会话框

    homeUI.js            主页

    loginUI.js             登录

    main.js                将游戏内函数存入window,供外部调用

    paymentUI.js       支付UI

    videoPlayerUI.js  视频播放

     

     

     

    一 游戏入口

    1 从白鹭平台获取egretID、用户信息等,然后进入游戏正式链接

    <div id="gameIframeBox" style="display:block;margin:0 auto;100%;height:0px;background-color:#000">
           <iframe id="gameIframe" name="gameIframe" src="http://api.egret-labs.org/v2/game/20409/91822?chanId=20409&channelId=20409&showLoginPanel=no&time=1509974135&egretstartfrom=gamece
    nter&egretSdkDomain=https://api.egret-labs.org/v3&egretServerDomain=https://api.egret-labs.org/v3&egretOauthUser=1&egretId=3d66bcad0342d9c2b838810445fc166a&userId=D02F30FBF9C4E6C3F2F7B9738D11772F__qq
    &userName=危险的画本&userImg=http://q.qlogo.cn/qqapp/101237728/D02F30FBF9C4E6C3F2F7B9738D11772F/100&userSex=1&sign=118620d8e41c0ccfc78406b0c24c84e4&egretwt=mobile&isEgretLogin=1
    "
    frameborder="no" border="0" marginwidth="0" marginheight="0" scrolling="no" width="100%" height="100%"></iframe> </div>

     

    2 正式游戏网页,加载cocos-js代码,运行游戏

    <script src="src/settings.js" charset="utf-8"></script>
    <script src="main.js" charset="utf-8"></script>

     

    二 游戏统计

    百度统计

    TalkingData

     

    三 视频播放、音频播放

    新用户进入游戏的视频单独申请播放,和游戏中升级后播放的视频申请步骤不一样。

    游戏中levelup后的视频,在升级后根据等级level请求服务器获取相应视频链接。

    PC端播放视频

    请求加载视频

                login_preload: function() {
                    gaudio.loadBgSound(),
                    gevent.emit(gevent.EVENT_LOAD_VIDEO, 1101)
                }
                    gevent.on(gevent.EVENT_LOAD_VIDEO,
                    function(e) {
                        var t = e.detail;
                        1 != gsdk.videoType() && this.loadVideo(this.getVideoURL(t))
                    }

     

    cocos自带的video播放html视频

                loadVideo: function(e) {
                    if (1 != gsdk.videoType()) {
                        var t = new cc.Node("VideoPlayer");
                        t.setAnchorPoint(cc.p(0, 0));
                        var n = t.addComponent(cc.Widget);
                        n.isAlignTop = !0,
                        n.isAlignBottom = !0,
                        n.isAlignLeft = !0,
                        n.isAlignRight = !0,
                        n.top = 0,
                        n.bottom = 0,
                        n.left = 0,
                        n.right = 0,
                        this.videoPlayer = t.addComponent(cc.VideoPlayer),
                        this.videoPlayer.keepAspectRatio = !0,
                        this.node.addChild(t),
                        this.videoPlayer.remoteURL = e;
                        var i = document.getElementsByClassName("cocosVideo")[0];
                        i.setAttribute("x5-video-player-type", "h5"),
                        i.setAttribute("webkit-playsinline", "true");
                        var o = function() {
                            this._onVideoEnded()
                        };
                        this.videoPlayer.node.on("completed", o, this),
                        this.videoPlayer.node.on("stopped", o, this),
                        this.videoPlayer.play(),
                        this.videoPlayer.pause(),
                        this.videoPlayer.node.active = !1
                    }
                }

     

    App播放视频

    一种是进入游戏时播放固定视频

      enterGmae: function() {
                    var e = this.editBox.string;
                    if (e.length <= 0) gwnd.showPrompt(glang.NameEmpty);
                    else if (this._checkName(e)) gwnd.showPrompt(glang.ContainsIllegalCharacters);
                    else {
                        gevent.emit(gevent.EVENT_LOAD_VIDEO, 1102);
                        var t = this;
                        grpc.CreateRole(function(n) {
                            0 === n && (gsdk.analytics(gconst.TD_EVENT.CREATE_ROLE, {
                                roleName: e
                            }), gsdk.reportUserProgress(1), t.playVideo())
                        },
                        e)
                    }
                }

     

    第二种是角色升级时,播放视频

                _tryShowLevelUpAction: function() {
                    this._tryShowComingTelphone() || this.tryShowStoryVideo()
                },
                tryShowStoryVideo: function() {
                    var e = gplayer.level;
                    if (gplayer.max_story_video_level >= e) return ! 1;
                    var t = gsheet.Level.find({
                        Level: e
                    });
                    if (t.StoryVideoId <= 0) return ! 1;
                    grpc.WatchStoryVideo(function(t) {
                        0 == t && (gplayer.max_story_video_level = e)
                    }),
                    gaudio.pauseBgSound();
                    var n = cc.instantiate(this.levelupAnim);
                    this.node.addChild(n);
                    return n.once("anim-complete",
                    function(e) {
                        n.removeFromParent(),
                        gwnd.openVideo(t.StoryVideoId, gconst.VIDEO_TYPE.STORY)
                    },
                    this),
                    !0
                }

     

     

    需要播放视频时,根据视频ID和视频类型,请求播放视频。

     gwnd.openVideo(1101, gconst.VIDEO_TYPE.STORY);
    VIDEO_TYPE: {
        STORY: 1,
        FACE_TIME: 2,
        LIBRARY: 3,
        SEVENLOGIN: 4
    },
    VIDEO_PLAY_STATE: {
        NONE: 0,
        PLAYING: 1,
        PAUSED: 2,
        COMPLETED: 3
    }

     

    发送请求视频事件

     openVideo: function(e, t, n) {
          gevent.emit(gevent.EVENT_OPEN_VIDEO, {
           videoId: e,
           callBack: n,
           videoType: t
            })
    }

     

    处理播放视频事件,关闭背景音乐,并尝试播放视频

    gevent.on(gevent.EVENT_OPEN_VIDEO,
        function(e) {
              this._isOpenVideo = !0,
              this.bgSoundState("video", !0),
              this.windowLayer.getChildren().length <= 0 && this.anim.play("Exit")
    }
    gevent.on(gevent.EVENT_OPEN_VIDEO,
         function(e) {
               var t = e.detail;
               1103 == t.videoId && (this.food = !0),
               this._quondamVideoId = t.videoId,
               this._videoId = gutils.getmapVideoID(t.videoId),
               this._videoType = t.videoType,
               this._callBack = t.callBack,
               Global.home.active = !1,
               1 == gsdk.videoType() && (document.body.style.backgroundColor = "transparent", cc.director.setClearColor(cc.color(0, 0, 0, 0)), this.touchLayer.active = !0),
               this._tryPlay()
          },
    this)

     

    判断是否需要加载小标题再播放视频,或是直接播放视频

                _tryPlay: function() {
                    this._playState = gconst.VIDEO_PLAY_STATE.NONE,
                    this._lastSubtitle = null,
                    this._subtitles = new Array;
                    var e = !1;
                    gconst.VIDEO_TYPE.STORY != this._videoType && gconst.VIDEO_TYPE.INTERIM != this._videoType || (e = !0),
                    e && 1 == gsdk.videoType() ? this._loadSubtitle() : this._play()
                }

     

    获取并拼接视频正式Url,并使用cordova播放视频,监听播放进度和播放完成事件

                _play: function() {
                    var e = this;
                    if (1 == gsdk.videoType()) {
                        this.maskLayer.active = !0,
                        gsdk.videoStop();
                        var t = 0,
                        n = 0;
                        gplayer.hasOwnProperty("account_id") && (t = gplayer.account_id),
                        gplayer.hasOwnProperty("level") && (n = gplayer.level),
                        this.setloadingView(!0),
                        gsdk.getVideoURL(this._videoId, t, n,
                        function(t) {
                            gsdk.videoPlay(t),
                            e._onVideoPlaying(),
                            gsdk.watchProgress(function(t) {
                                e._onVideoProgress(t)
                            },
                            function() {
                                e._onVideoEnded()
                            })
                        },
                        function(e, t) {})
                    } else this.onClicked();
                    gaudio.pauseBgSound()
                }

     

    使用插件cordova播放视频

    videoPlay: function(e) {
              cordova.plugins.videobackground.play(e, !1)
    }

     

    播放视频结束,可能是多段视频组成的场景。第一段播放,中间有两个选项,根据用户选择,再播放第二段视频。

                _onVideoEnded: function() {
                    var e = !0;
                    if (this.removeVideo(), this.food) this.food = !1,
                    e = !1,
                    this.nodeSelectFood.getChildByName("txtSelect").getComponent(cc.Label).string = glang.SelectFood,
                    this.nodeSelectFood.active = !0;
                    else {
                        var t = gsheet.Video.find({
                            ID: this._quondamVideoId
                        });
                        if (t) {
                            this.btnPlay.active = !1,
                            e = !1,
                            this.options.active = !0;
                            var n = this.options.getChildByName("op1"),
                            i = this.options.getChildByName("op2");
                            n.getComponent(cc.Label).string = t.NextOption1,
                            i.getComponent(cc.Label).string = t.NextOption2,
                            n.once(cc.Node.EventType.TOUCH_END,
                            function() {
                                this.options.active = !1,
                                this._quondamVideoId = t.NextVideoId1,
                                this._videoId = gutils.getmapVideoID(t.NextVideoId1),
                                this.loadVideo(this.getVideoURL(this._videoId)),
                                this._tryPlay()
                            },
                            this),
                            i.once(cc.Node.EventType.TOUCH_END,
                            function() {
                                this.options.active = !1,
                                this._quondamVideoId = t.NextVideoId2,
                                this._videoId = gutils.getmapVideoID(t.NextVideoId2),
                                this.loadVideo(this.getVideoURL(this._videoId)),
                                this._tryPlay()
                            },
                            this)
                        }
                    }
                    e && this.closeVideoPlayer()
                }

     

     

    四 支付接入

     

     

    点击商品,提示购买

                clickEvent: function() {
                    var e = gsheet.ShopGoods.find({
                        ID: this._sheet.GoodsId
                    });
                    if (gplayer.isHaveShopGoods(e)) gwnd.showPrompt(e.HaveTip);
                    else if (e.OpenFuncId > 0 && !gplayer.isFuncOpend(e.OpenFuncId)) {
                        var t = gsheet.FuncOpening.find({
                            ID: e.OpenFuncId
                        }),
                        n = gsheet.Level.find({
                            Level: t.OpenLevel
                        }),
                        i = gutils.substitute(glang.BuyUnopenedGoodsTip, e.Name, n.Day);
                        gwnd.showPrompt(i)
                    } else Global.sdk_payment_pay(e.ID)
                }

     

     弹出购买商品的提示框

                payment_pay: function(e) {
                    var t = this;
                    lobby.purchaseConfirm ? gwnd.confirmPrompt(function() {
                        t.payment_resume()
                    },
                    "商品购买", "请为您选购的商品进行支付", gconst.PROMPT_WND_TYPE.ONE, "关闭") : gwnd.loading(!0);
                    var n = {
                        ID: e.ID,
                        Price: 100 * e.Price,
                        Label: e.Name,
                        level: gplayer.level,
                        Name: gplayer.name,
                        accountId: gplayer.account_id
                    };
                    lobby.purchase(n, e.ID,
                    function(e) {
                        e ? t.payment_OnRecipt(e) : (gwnd.closeConfirmPrompt(), t.payment_resume()),
                        gwnd.loading(!1)
                    },
                    function(e, t) {
                        if (gwnd.closeConfirmPrompt(), gwnd.loading(!1), e || t) {
                            var n = "";
                            t && t.length > 0 && (n += t),
                            e && e.length > 0 && (n += "错误码:" + e),
                            gwnd.showPrompt(n)
                        } else gwnd.showPrompt("充值失败!")
                    },
                    function(e, t, n, i, o) {
                        gwnd.loading(!1),
                        e >= n.Price ? gwnd.open("common_wnd", [n, i, o]) : gwnd.open("common_nomoney_wnd", [e, t, n, i, o])
                    })
                }

     

     确认购买。获取商品ID、价格、名字等信息,发起购买请求。

    project.js

                payment_resume: function() {
                    window.lobby && lobby.processPendingPurchases(this.payment_OnRecipt)
                }
      "商品购买", "请为您选购的商品进行支付", gconst.PROMPT_WND_TYPE.ONE, "关闭") : gwnd.loading(!0);
                    var n = {
                        ID: e.ID,
                        Price: 100 * e.Price,
                        Label: e.Name,
                        level: gplayer.level,
                        Name: gplayer.name,
                        accountId: gplayer.account_id
                    };
                    lobby.purchase(n, e.ID,
                    function(e) {
                        e ? t.payment_OnRecipt(e) : (gwnd.closeConfirmPrompt(), t.payment_resume()),
                        gwnd.loading(!1)
                    },

     

    生成商品订单

    gameApi.js

        //充值补单
        this.processPendingPurchases = function(payment_OnRecipt_callback){
            self.rpc.request(function(code, errmsg, rcptArr){
                if(200 === code && rcptArr){
                    for(var i=0;i<rcptArr.length;i++){
                        payment_OnRecipt_callback(rcptArr[i]);
                    }
                }
            },self.sdkHash.loveportalurl + "pendingpurchase.php",{gameid:self.appId,account:self.lovechaccount,channel:self.CHANNEL_PLATFORM});
        }
    //充值 cData : {ID: 道具ID,Price: 价格 (分)   ,Label: (商品名or描述) }
        this.purchase = function(cData, dialysis, succeedCallback, failedCallback){
            if(!self.sdkJs){
                failedCallback(0, "登录失败请重试");
                return;
            }
            var _attachs = {
                itemname:cData.Label,
                playerlevel:cData.level,
                playername:cData.Name,
                accountid:cData.accountId,
                channelattachs:self.sdkHash.attachs
            }
            var createOrderData = {
                gameid:self.appId,
                account:self.lovechaccount,
                sdkname:self.CHANNEL_SDKNAME,
                channel:self.CHANNEL_PLATFORM,
                itemid:cData.ID,
                attachs:_attachs
            }
            self.sdkJs.purchase(cData, createOrderData, succeedCallback, failedCallback);
        }

     

    发起http请求购买。ZmSDK是啥...

    main.js

        //充值
        this.purchase = function (cData, createOrderData, succeedCallback, failedCallback) {
            //创建订单
            self.rpc.request(function(code, errmsg, sData){
                if(200 === code){
                    self.purchaseStart(cData, sData, succeedCallback, failedCallback);
                }else{
                    failedCallback(code, errmsg);
                }
            },self.sdkHash.loveportalurl + "requestpay.php",createOrderData);
        }
    
        this.purchaseStart = function (cData, sData, succeedCallback, failedCallback) {
            var payinfojson = {
                check: sData.attachs.check,
                feeid: cData.ID+"",
                fee: sData.price+"",
                feename: cData.Label,
                extradata: sData.gameorderid,
                serverid: 1+"",
                rolename: cData.Name,
                roleid: cData.accountId+"",
                servername: ""
            };
            ZmSdk.getInstance().pay(payinfojson, function(data){
                //跳转到了支付页面
                if(data.retcode == 3)
                    return;
                if(data.retcode == 1){
                    failedCallback(0,data.msg);
                    return;
                }
                if(data.retcode == 2){
                    failedCallback(0,"您取消了支付");
                    return;
                }
                if(data.retcode == 0)
                    succeedCallback();
            });
        }

     

    支付成功回调

    project.js

                payment_OnRecipt: function(e) {
                    grpc.SdkPaymentPay(function(t, n, i, o, s, a, c, l, r) {
                        1 !== t ? 0 === t && (lobby.finishPurchase(e), gplayer.buyShopGoodsSuccess(n, i, o, s, a, c, l, r), gwnd.showPrompt(glang.PaySuccess), gevent.emit(gevent.PAY_SUCCESS)) : lobby.finishPurchase(e)
                    },
                    e)
                }

     

    发起http请求,告知服务端支付完成

    gameApi.js

        //完成一笔订单
        this.finishPurchase = function(rcpt){
            self.rpc.request(function(){},self.sdkHash.loveportalurl + "finishpurchase.php",{gameid:self.appId,receipt:rcpt});
        }

    游戏内更新界面

     gevent.on(gevent.PAY_SUCCESS, this._paySuccessHandler, this)
    _paySuccessHandler: function() {
         this.updateView()
    }

     

    五 Http通讯协议

    post模式。

    http包含token,且所有请求都写在Http类里面,留出回调接口

        grpc: [function(e, t, n) {
            "use strict";
            cc._RF.push(t, "e1dd3ZUONZBW4caM364h+q8", "grpc");
            var i = {
                token: "",
                request: function(e, t, n) {
                    gwnd.loading(!0);
                    var i = new XMLHttpRequest;
                    i.onreadystatechange = function() {
                        if (cc.log("xhr.readyState:" + i.readyState + "--xhr.status:" + i.status + "--xhr.responseText:" + i.responseText), i.readyState == XMLHttpRequest.DONE) if (200 == i.status) {
                            var e = i.responseText;
                            cc.log("rpc:|" + e);
                            var n = JSON.parse(e);
                            if ("err10001" == n[0]) return gwnd.confirmPrompt(function() {
                                gsdk.isExitLobby() ? gsdk.exitToLobby() : cc.director.loadScene("logoCanvas")
                            },
                            " 重复登录提醒", "检测到您的账号在其他设备登录游戏,请重新登录验证。", gconst.PROMPT_WND_TYPE.ONE),
                            void gwnd.loading(!1);
                            t.apply(this, n.rpc),
                            "mail" in n && gplayer.addNewMails(n.mail),
                            "activity" in n && gplayer.addNewActivitys(n.activity),
                            "activity_target" in n && gplayer.updateActivityTargets(n.activity_target),
                            gwnd.loading(!1)
                        } else gwnd.loading(!1)
                    },
                    i.open("POST", gsdk.serverURL(), !0);
                    var o = "A=" + encodeURIComponent(e);
                    if ("" !== this.token && (o = o + "&T=" + encodeURIComponent(this.token)), void 0 !== n) {
                        o += "&G=";
                        var s = JSON.stringify(n);
                        o += encodeURIComponent(s)
                    }
                    cc.log("rpcName:" + e + "--send:" + o),
                    i.setRequestHeader("Content-type", "application/x-www-form-urlencoded"),
                    i.send(o)
                },
                getSDKGiftReward: function(e, t) {
                    this.request("getSDKGiftReward", e, [t])
                },
                getSendToDesktopReward: function(e) {
                    this.request("getSendToDesktopReward", e, [])
                },
                BindAccount: function(e, t, n, i, o) {
                    this.request("BindAccount", e, [t, n, i, o])
                },

     

     

     

    六 游戏配置文件

     所有标题、随机姓名、对话全部都写在代码里

     

    七 关键字屏蔽

    取名时,从服务器下载name_forbit.txt,里面有被屏蔽的关键字。

     cc.loader.loadRes("forbid/name_forbid.txt",
         function(t, n) {
             t || (e._forbidNames = n.split("
    "))
     })

     

    八 新手指引做法

    每次进入某界面(有新手指引的界面)时,检查该界面是否需要显示新手指引,如果有,则显示新手指引。

    这个检查会每次进入某界面都会检查一次,新手指引完成后,会向服务器发送保存当前指引步骤。

    点击新手指引按钮时,会执行bind的处理函数handler,来继续指引操作。

    下一步新的指引

                newbieGuide: function(e, t, n, i) {
                    gevent.emit(gevent.EVENT_GUIDE_START_STEP, {
                        step: e,
                        btnView: t,
                        callback: n,
                        isEnable: i
                    })
                }

     

    处理下一步新手指引

                onLoad: function() {
                    gevent.on(gevent.EVENT_GUIDE_START_STEP, this.guideStartHander, this)
                },
                guideStartHander: function(e) {
                    this.step = e.detail.step,
                    this.btnView = e.detail.btnView,
                    this.callback = e.detail.callback,
                    this.isEnable = e.detail.isEnable,
                    this._data = gsheet.GuideStep.find({
                        ID: this.step
                    }),
                    gsdk.analytics(gconst.TD_EVENT.BEGIN_MISSION, {
                        guideStep: this.step
                    }),
                    this.newbieGuide()
                }

     

    显示Dog新手指引

                newbieGuide: function() {
                    if (this.node.on(cc.Node.EventType.TOUCH_END, this.touchNodeEnd, this), this.createDog(), void 0 != this.btnView) {
                        var e = this.btnView.getComponent(cc.Button);
                        void 0 != e && void 0 == this.isEnable && (e.interactable = !1),
                        this.perch = cc.instantiate(this.perchPf),
                        this.node.addChild(this.perch),
                        this.schedule(this.updateDisplay, .2),
                        this.perch.on(cc.Node.EventType.TOUCH_END, this.touchBtnEnd, this),
                        this.arrow = cc.instantiate(this.arrows),
                        this.arrow.rotation = this._data.Rotation,
                        this.node.addChild(this.arrow),
                        this.perch.active = !1,
                        this.arrow.active = !1,
                        this.updateDisplay()
                    }
                },
                updateDisplay: function() {
                    var e = this.btnView.getNodeToWorldTransform();
                    if (void 0 != this.worldTransform) if (this.worldTransform.tx == e.tx && this.worldTransform.ty == e.ty) {
                        this.perch.active = !0,
                        this.arrow.active = !0,
                        this.perch.x = e.tx,
                        this.perch.y = e.ty;
                        var t = this.btnView.getContentSize();
                        this.perch.setContentSize(t),
                        this.arrow.x = e.tx + t.width / 2,
                        this.arrow.y = e.ty + t.height / 2
                    } else this.worldTransform = e;
                    else this.worldTransform = e
                }

     

  • 相关阅读:
    大项目之网上书城(五)——主页(End)
    # 大项目之网上书城(四)——主页(下中)
    大项目之网上书城(三)——主页(中)
    大项目之网上书城(二)——主页(上)
    大项目之网上书城(一)——注册页面
    Mycat
    centos7 bash: netstat: 未找到命令
    docker 推送镜像到Harbor错误修改
    Jenkins插件下载镜像加速
    docker镜像加速器
  • 原文地址:https://www.cnblogs.com/gamedaybyday/p/7795570.html
Copyright © 2020-2023  润新知