CocosCreator游戏弹窗实现

【原创博文,转载请注明出处!】
(文末有新方案,请耐心看完)昨天参考了麒麟子的CocosCreator开源项目,然后自己也封装了一个游戏弹窗的小模块,做了点记录,方便使用CocosCreato开发游戏的小伙伴们参考。

本篇将会带你手把手写一个CocosCreator游戏弹窗,下面请看游戏弹窗效果图(请自行忽略被拉伸的弹窗背景,毕竟图片是随意找的,但是功能才是我们想要的,对不?)
弹窗效果图.png

方案一

看完了效果图,让我们一起开始今天的任务。首先在CocosCreator开发工具中,我们在Canvas的safe_area目录层级下面新建一个alert节点作为这个弹窗的父节点,这样方便我们代码控制alert的显示与隐藏。

针对现今主流设备越来越多的异形屏就会涉及到“安全区域”这个概念,从而设计的时候,需要考虑所有能响应事件的控件都避开这个“安全区域”)

这里列举一下弹窗涉及到的控件:一个背景视图,两个Label和两个Button。其中一个Label用于显示主题,一个Label用于显示提示文字。两个Button给用户提供选择选择入口(当然我们后面通过代码控制“取消”按钮是否显示)下面是这个弹窗UI的层级结构:


creator层次结构.png

那么开始我们今天的代码吧,Let Go!!!
新建一个脚本Alert.js并定义如下属性:
properties: {
_alert:null, //提示框
_btnOK:null, //提示框确定按钮
_btnCancel:null, //提示框取消按钮
_title:null, //提示框标题
_content:null, //提示框内容
_btnOKCallback:null, //点击确定按钮的回调事件
},
然后我们在Alert.js的onLoad()方法里获取上面定义的属性:

    onLoad () {

        //配置AppStart.js以后才可以判断
        // if(cc.vv == null){
        //     return;
        // }
        cc.log('Alert.js onLoad');

        
        this._alert = cc.find("Canvas/safe_area/alert");
        this._title = cc.find("Canvas/safe_area/alert/background/title").getComponent(cc.Label);
        this._content = cc.find("Canvas/safe_area/alert/background/content").getComponent(cc.Label);
        this._btnOK = cc.find("Canvas/safe_area/alert/background/btn_ok").getComponent(cc.Button);
        this._btnCancel = cc.find("Canvas/safe_area/alert/background/btn_cancel").getComponent(cc.Button);

        if (this._btnCancel instanceof cc.Button) {
            console.log('是个Button ');
        }else{
            console.log('是个鬼');
        }

        this._btnOK.active = false;

        //下面这段代码开启是否显示
        // this._alert.active = false;
        cc.vv.alert = this;
        
    },

下面我们需要额外提供3个API,分别作用为:

a:_btnOK按钮的点击回调;
b:_btnCancel按钮的点击回调;
c:弹出的显示功能show;
    onBtnClicked:function(event){
        if(event.target.name == "btn_ok"){
            if(this._btnOKCallback){
                this._btnOKCallback();
            }
        }
        this._alert.active = false;
        this._btnOKCallback = null;

        console.log("这是全新定义的clicked!!");
    },

    cancelBtnClicked:function(){
        cc.log('我被点中了'); 
        this._alert.active = false; 
      },
 
    /** 
     * title:弹框标题
     * content:弹框显示内容
     * callback:点击“确定”按钮的回调事件
     * needCancel:是否需要显示“取消”按钮
    */
    show:function(title,content,callback,needCancel){
        console.log('paras -----> : ',title,content,callback,needCancel);
        this._alert.active = true;
        this._btnOKCallback = callback;
        this._title.string = title;
        this._content.string = content;
        if(needCancel){
          
            // "确定" 和 "取消"都显示
            //注意:这里面都是对节点node 操作,this._btnCancel.active(或者.x)什么的操作都是无效的☹️
            console.log("needCancel ? true");
            this._btnCancel.node.active = true;
            this._btnOK.node.x = -239.5;
            this._btnCancel.node.x = 239.5;
            if(this._btnOK){
                cc.log('也是存在的啊!');
            }
        }
        else{
           //不需要显示“取消”按钮
            console.log("needCancel ? false");
            this._btnCancel.node.active = false;
            this._btnOK.node.x = 0;
        }
    },

OK,有了上面这些核心部分我们就已经完成今天的任务了。

需要注意的是:我们在onLoad()方法里已经获取到对应的控件,但是设置该控件的显示与隐藏并不像原生平台API那样直接设置Button.hidden = YES or NO 这么简单了。在CocosCreator里,设置控件的显示与隐藏都是在节点的基础上操作的,所以需要类似于“xxx.node.active = true or false; ”

下面我们来看看Alert.js的应用:

cc.vv = {};
cc.vv.alert =  require("Alert");
cc.vv.alert.show("提示啦", "钻石不足,创建房间失败!",this.clickCallback,true);


clickCallback(){
    cc.log("do clickCallback task.");
},

第一句“cc.vv = {};”,可以理解为给cc添加了一个“vv”的对象。由于cc是全局的,所以cc.vv也可以在全局使用,我们定义了cc.vv对象,当然可以继续给vv这个对象增加其子对象如cc.vv.alert。。。,这样就可以在全局使用cc.vv.alert对象。还记得在Alert.js的onLoad()方法里,我们进行了“cc.vv.alert = this;”的操作,这样我们就给这个全局的alert对象赋值了,后面就可以放肆地使用这个cc.vv.alert对象了。嗯,不知道这样理解对不对,如果您有其他的理解,请留言指教,我将不甚感激/(ㄒoㄒ)/

图片发自简书App

好啦,今天的记录到此为止O(∩_∩)O

方案二(强烈推荐)

2018-05-24日更新。
昨天发现了一个问题:上面这个游戏弹窗功能上没问题。但是实际使用中存在不足之处。一般游戏中很多个场景都会有弹窗显示的,那按照我们之前的做法不就得每个场景下都拖一个这样的弹窗视图集吗?游戏那么多场景,想起来就挺麻烦的。所以对于复杂游戏场景,需要换个思路彻底解决这个问题。
参考了网上其他方案并与部分游戏开发者讨论之后,经过实践我觉得接下来这个方案很棒👍,这也是我投入到项目中的方案。

新方案弹窗样式.jpg

也就是:
①:在CocosCreator场景编辑器中设置好弹窗的UI布局
②:然后将整个弹窗拖到CocosCreator资源管理器中生成一个prefab文件。
③:将prefab文件放到资源管理器assets目录的resources目录下。
④:将弹窗所需要用到的资源文件也放入资源管理器assets目录的resources目录下。
⑤:写一个脚本动态控制弹窗的控件。便于在项目需要用到的地方显示弹窗。
我新改写的prefab弹窗代码如下:

import { ENFILE } from "constants";

/*
 * @Author: RephontilZhou 
 * @Date: 2018-05-18 17:39:48 
 * @Last Modified by: Damo
 * @Last Modified time: 2018-05-23 19:57:35
 */

var Alert = {
    _alert: null,           // prefab
    _detailLabel:   null,   // 内容
    _cancelButton:  null,   // 确定按钮
    _enterButton:   null,   // 取消按钮
    _enterCallBack: null,   // 回调事件
    _animSpeed:     0.3,    // 动画速度
    _sprite:        null,   //人物
};

cc.Class({
    extends: cc.Component,

    properties: {


    },


    statics:{

        /**
         * detailString :   内容 string 类型.
         * enterCallBack:   确定点击事件回调  function 类型.
         * neeCancel:       是否展示取消按钮 bool 类型 default YES.
         * spritePath:      动态加载弹框中精灵图片的resources路径
         * duration:        动画速度 default = 0.3.
        */
        show(detailString, enterCallBack, needCancel, spritePath, animSpeed) {

            var self = this;
        
            // 判断
            if (Alert._alert != undefined) return;
        
            Alert._animSpeed = animSpeed ? animSpeed : Alert._animSpeed;
            cc.loader.loadRes("prefabs/Alert", cc.Prefab, function (error, prefab) {
        
                if (error) {
                    cc.error(error);
                    return;
                }
        
                var alert = cc.instantiate(prefab);
                Alert._alert = alert;
        
                // 动画 
                var cbFadeOut = cc.callFunc(self.onFadeOutFinish, self);
                var cbFadeIn = cc.callFunc(self.onFadeInFinish, self);
                self.actionFadeIn = cc.sequence(cc.spawn(cc.fadeTo(Alert._animSpeed, 255), cc.scaleTo(Alert._animSpeed, 1.0)), cbFadeIn);
                self.actionFadeOut = cc.sequence(cc.spawn(cc.fadeTo(Alert._animSpeed, 0), cc.scaleTo(Alert._animSpeed, 2.0)), cbFadeOut);
        
                
                Alert._detailLabel = cc.find("alertBackground/detailLabel", alert).getComponent(cc.Label);
                Alert._cancelButton = cc.find("alertBackground/cancelButton", alert);
                Alert._enterButton = cc.find("alertBackground/enterButton", alert);
                Alert._sprite = cc.find("alertBackground/sprite", alert).getComponent(cc.Sprite);

                
                if (Alert._sprite.spriteFrame) {
                    console.log("Alert._sprite");
                }else{
                    console.log("找不到");
                }
                
                // 添加点击事件
                Alert._enterButton.on('click', self.onButtonClicked, self);
                Alert._cancelButton.on('click', self.onButtonClicked, self);
    
                // 父视图
                Alert._alert.parent = cc.find("Canvas");
        
                // 展现 alert
                self.startFadeIn();
        
                self.configAlert(detailString, enterCallBack, needCancel, spritePath,animSpeed);
                
            });
        
            // 参数
            self.configAlert = function (detailString, enterCallBack, needCancel, spritePath, animSpeed) {
        
                // 回调
                Alert._enterCallBack = enterCallBack;
        
                // 内容
                Alert._detailLabel.string = detailString;
                // 是否需要取消按钮
                if (needCancel || needCancel == undefined) { // 显示
                    Alert._cancelButton.active = true;
                } else {  // 隐藏
                    Alert._cancelButton.active = false;
                    Alert._enterButton.x = 0;
                }

                if (spritePath == null || spritePath == undefined) {
                    spritePath = "Alert/alert_baby";
                }

                cc.loader.loadRes(spritePath, cc.SpriteFrame, function (err, spriteFrame){
                    console.log(spritePath);
                    if (spriteFrame) {
                        console.log("恭喜发财");
                        if (Alert._sprite) {
                            Alert._sprite.spriteFrame = spriteFrame;
                        }
                    }

                });

            };
        
            // 执行弹进动画
            self.startFadeIn = function () {
                cc.eventManager.pauseTarget(Alert._alert, true);
                Alert._alert.position = cc.p(0, 0);
                Alert._alert.setScale(2);
                Alert._alert.opacity = 0;
                Alert._alert.runAction(self.actionFadeIn);
            };
        
            // 执行弹出动画
            self.startFadeOut = function () {
                cc.eventManager.pauseTarget(Alert._alert, true);
                Alert._alert.runAction(self.actionFadeOut);
            };
        
            // 弹进动画完成回调
            self.onFadeInFinish = function () {
                cc.eventManager.resumeTarget(Alert._alert, true);
            };
        
            // 弹出动画完成回调
            self.onFadeOutFinish = function () {
                self.onDestory();
            };
        
            // 按钮点击事件
            self.onButtonClicked = function(event){
                if(event.target.name == "enterButton"){
                    console.log("确认按钮");
                    if(self._enterCallBack){
                        self._enterCallBack();
                    }
                }else{
                    console.log("取消按钮");
                }
                self.startFadeOut();
            };
        
            // 销毁 alert 
            self.onDestory = function () {
                Alert._alert.destroy();
                Alert._enterCallBack = null;
                Alert._alert = null;
                Alert._detailLabel = null;
                Alert._cancelButton = null;
                Alert._enterButton = null;
                Alert._animSpeed = 0.3;
                Alert._sprite = null;

            };
        }


    },

    start () {

    },

   
});

praise.jpeg
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,132评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,802评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,566评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,858评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,867评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,695评论 1 282
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,064评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,705评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,915评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,677评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,796评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,432评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,041评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,992评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,223评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,185评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,535评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,475评论 25 707
  • 练习2-1的要求如下: 像下面那样读取两个整数,然后显示前者是后者的百分之几。 我最终输入的代码如下 按理说,这份...
    莫一是阅读 486评论 0 0
  • 日本滨松医科大学教授藤本大三郎在《人类为什么老化》中指出:生命的一切活动都是在酵素的作用下停止的,没有酵素人就不能...
    陈喜志阅读 367评论 0 0
  • 终于在晚上翻译完了洗了澡,洗了1h衣服助教国际象棋知道了棋外的很多事情还有费米科技游戏化教学好有趣喔
    dq920813阅读 172评论 0 0