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

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

  

整体键盘:

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

 

一般来说按钮各个状态的各个大小都是一样的,一般可以直接使用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;

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

 

你可能感兴趣的:(cocos2d-js)