• Cocos2d-js 开发记录:自定义按钮


    游戏开发总是有些特殊,一般的预制的UI无法满足要求。其实对于不复杂的功能,与其看文档还不如自己写一个。比如游戏中一个虚拟键盘,其中的按键在按下时会增长,变为原来的两倍高度,在原来高度上方显示按键的字如:

      

    整体键盘:

    一般来说按钮各个状态的各个大小都是一样的,一般可以直接使用cocos中的cc.MenuItemSprite或者cc.MenuItemImage来实现。而上述这个键盘按钮却是大小不同的。那么在两个状态的图片大小不同的时候,cc.MenuItemImage会怎么对齐呢?试了一下采取的是底端对齐,按钮的点击范围有正常状态下的图片大小确定,这两个情况其实和我们要实现的键盘按钮的要求是一致的。但是cc.MenuItemImage不能加入Label,更没有可用根据点击情况变化这个label位置的功能。

     这些cc.MenuItemXxxx系列的类都直接或间接继承自cc.MenuItem,而cc.MenuItem继承自cc.Node(framework/cocos2d-html5/cocos2d/core/menus/CCMenuItem.js),来看下cc.MenuItem的源码:

    /**
     * Subclass cc.MenuItem (or any subclass) to create your custom cc.MenuItem objects.
     * @class
     * @extends cc.Node
     * @param {function|String} callback
     * @param  {cc.Node} target
     */
    cc.MenuItem = cc.Node.extend(/** @lends cc.MenuItem# */{
        _enabled: false,
        _target: null,
        _callback: null,
        _isSelected: false,
        _className: "MenuItem",
    
        /**
         * Constructor of cc.MenuItem
         * @param {function|String} callback
         * @param {cc.Node} target
         */
        ctor: function (callback, target) {
            var nodeP = cc.Node.prototype;
            nodeP.ctor.call(this);
            this._target = null;
            this._callback = null;
            this._isSelected = false;
            this._enabled = false;
    
            nodeP.setAnchorPoint.call(this, 0.5, 0.5);
            this._target = target || null;
            this._callback = callback || null;
            if (this._callback) {
                this._enabled = true;
            }
        },
    
        /**
         * return whether MenuItem is selected
         * @return {Boolean}
         */
        isSelected: function () {
            return this._isSelected;
        },
        /**
         * only use for jsbinding
         * @param value
         */
        setOpacityModifyRGB: function (value) {
        },
        /**
         * only use for jsbinding
         * @returns {boolean}
         */
        isOpacityModifyRGB: function () {
            return false;
        },
    
        /**
         * set the target/selector of the menu item
         * @param {function|String} selector
         * @param {cc.Node} rec
         * @deprecated since v3.0
         */
        setTarget: function (selector, rec) {
            this._target = rec;
            this._callback = selector;
        },
    
        /**
         * return whether MenuItem is Enabled
         * @return {Boolean}
         */
        isEnabled: function () {
            return this._enabled;
        },
    
        /**
         * set enable value of MenuItem
         * @param {Boolean} enable
         */
        setEnabled: function (enable) {
            this._enabled = enable;
        },
    
        /**
         * initializes a cc.MenuItem with callback
         * @param {function|String} callback
         * @param {cc.Node} target
         * @return {Boolean}
         */
        initWithCallback: function (callback, target) {
            this.anchorX = 0.5;
            this.anchorY = 0.5;
            this._target = target;
            this._callback = callback;
            this._enabled = true;
            this._isSelected = false;
            return true;
        },
    
        /**
         * return rect value of cc.MenuItem
         * @return {cc.Rect}
         */
        rect: function () {
            var locPosition = this._position, locContentSize = this._contentSize, locAnchorPoint = this._anchorPoint;
            return cc.rect(locPosition.x - locContentSize.width * locAnchorPoint.x,
                locPosition.y - locContentSize.height * locAnchorPoint.y,
                locContentSize.width, locContentSize.height);
        },
    
        /**
         * set the cc.MenuItem selected same as setIsSelected(true)
         */
        selected: function () {
            this._isSelected = true;
        },
    
        /**
         * set the cc.MenuItem unselected same as setIsSelected(false)
         */
        unselected: function () {
            this._isSelected = false;
        },
    
        /**
         * set the callback to the menu item
         * @param {function|String} callback
         * @param {cc.Node} target
         */
        setCallback: function (callback, target) {
            this._target = target;
            this._callback = callback;
        },
    
        /**
         * call the selector with target
         */
        activate: function () {
            if (this._enabled) {
                var locTarget = this._target, locCallback = this._callback;
                if (!locCallback)
                    return;
                if (locTarget && cc.isString(locCallback)) {
                    locTarget[locCallback](this);
                } else if (locTarget && cc.isFunction(locCallback)) {
                    locCallback.call(locTarget, this);
                } else
                    locCallback(this);
            }
        }
    });

    cc.MenuItem对Node的selected,unselected, activate方法进行了重新,提供了回调函数设置设置,修改按钮锚点等功能,自定义的按钮从cc.MenuItem继承即可。根据需要复写一下方法:

    • selected,被按下时调用(相当于pressed)
    • unselected,按下后松开时调用(相当于released)
    • activate,按下松开完成后调用(相当于click)

    将要显示的内容元素如cc.Sprite通过this.addChild加入即可显示,在上述方法中通过控制这些元素的visible和位置属性可以实现自定义按钮的各种效果,还可以runAction。

     下面给出自己的一个按钮示例:

    /* implementation element(key button) used by keyboard */
    var KeyMenuItem = cc.MenuItem.extend({
        _label: null,
        _normal_sprite: null,
        _press_sprite: null,
        FONT_EXTENDED_BOTTOM_PADDING_FACTOR: 0.75,
        FONT_BOTTOM_PADDING_FACTOR: 0,
        FONT_SIZE_FACTOR: 0.4,
    
        ctor: function(normal_img, press_img, text, callback, target) {
            cc.MenuItem.prototype.ctor.call(this);
            this.initWithCallback(callback, target);
    
            var normal_sprite = new cc.Sprite(normal_img);
            var press_sprite = new cc.Sprite(press_img);
    
            this._normal_sprite = normal_sprite;
            this._press_sprite = press_sprite;
    
            this.width = normal_sprite.width;
            this.height= normal_sprite.height;var label = new cc.LabelTTF(text, "Arial", Math.ceil(normal_sprite.width * this.FONT_SIZE_FACTOR));
            label.setColor(cc.color(0, 0, 0, 255));
            this._label = label;
            this.setNormal();
    
            this.addChild(label, 2);
            this.addChild(press_sprite, 0);
            this.addChild(normal_sprite, 1);
    
            this.cascadeColor = true;
            this.cascadeOpacity = true;
        },
    
        selected: function() {
            cc.MenuItem.prototype.selected.call(this);
            if (this._enabled) {
                this.setPress();
                cc.log("custom button selected");
            }
            cc.audioEngine.playMusic(res.button_press_mp3, false);
        },
    
        unselected: function() {
            cc.MenuItem.prototype.unselected.call(this);
            if (this._enabled) {
                this.setNormal();
                cc.log("custom button unselected");
            }
        },
    
        setNormal: function() {
            this.setLabelNormal();
            this.setSpriteNormal();
        },
    
        setPress: function() {
            this.setLabelPressed();
            this.setSpritePressed();
        },
    
        setLabelNormal: function () {
            var label = this._label;
            var nsprite = this._normal_sprite;
            label.setPosition(nsprite.width / 2.0, this.height * (0.5 + this.FONT_BOTTOM_PADDING_FACTOR));
        },
    
        setLabelPressed: function() {
            var label = this._label;
            var psprite = this._press_sprite;
            var factor = this.FONT_EXTENDED_BOTTOM_PADDING_FACTOR;
            label.setPosition(psprite.width / 2.0, psprite.height * factor);
        },
    
        setSpriteNormal: function () {
            var nsprite = this._normal_sprite;
            var psprite = this._press_sprite;
    
            psprite.visible = false;
            nsprite.visible = true;
    
            nsprite.setPosition(this.width / 2.0, this.height / 2.0);
            psprite.setPosition(psprite.width / 2.0, psprite.height / 2.0);
        },
    
        setSpritePressed: function() {
            var nsprite = this._normal_sprite;
            var psprite = this._press_sprite;
    
            psprite.visible = true;
            nsprite.visible = false;
    
            psprite.setPosition(psprite.width / 2.0, psprite.height / 2.0);
            nsprite.setPosition(this.width / 2.0, this.height / 2.0);
        },
    
        setEnabled: function(enabled) {
            var nsprite = this._normal_sprite;
            var psprite = this._press_sprite;
            var label = this._label;
            if (this._enabled != enabled) {
                if (enabled == false) {
                    this.setOpacity(0);
                } else {
                    this.setOpacity(255);
                }
            }
            cc.MenuItem.prototype.setEnabled.call(this, enabled);
        },
    
        getString: function () {
            return this._label.getString();
        }
    });

     其中:

    this.cascadeOpacity = true;

    级联不透明度,可以使得对按钮设置透明度时整体透明度也一起变化

  • 相关阅读:
    YL杯超级篮球赛 (Standard IO)
    Window (Standard IO)
    toj1026 Network 双连通分量
    poj3177 Redundant Paths 双连通分量
    poj1144 Network 双连通分量
    bzoj1269
    bzoj1800
    CF911D
    CF910C
    CF910B
  • 原文地址:https://www.cnblogs.com/lailailai/p/4020317.html
Copyright © 2020-2023  润新知