游戏开发总是有些特殊,一般的预制的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;

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

Cocos2d-js 开发记录:自定义按钮的更多相关文章

  1. wordpress优化之结合prism.js为编辑器自定义按钮转化代码

    原文链接 http://ymblog.net/2016/07/24/wordpress-prism/ 继昨天花了一天一夜的时间匆匆写了主题Jiameil3.0之后,心中一直在想着优化加速,体验更好,插 ...

  2. JS开发中自定义调试信息开关

    在开发过程中,可能随处留下几个console.log,或者alert语句,这些语句在开发过程中是很有价值的.但是项目一旦进入生产环境,过多的console.log可能影响到浏览器的运行效率,过多的al ...

  3. Dynamics CRM 客户端程序开发:自定义系统标准按钮的可用性

    关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复125或者20140414可方便获取本文,同时可以在第一时间得到我发布的最新的博文信息,follow me! 一般是新建一个解决方案用于客制化 ...

  4. iOS开发——UI进阶篇(十八)核心动画小例子,转盘(裁剪图片、自定义按钮、旋转)图片折叠、音量震动条、倒影、粒子效果

    一.转盘(裁剪图片.自定义按钮.旋转) 1.裁剪图片 将一张大图片裁剪为多张 // CGImageCreateWithImageInRect:用来裁剪图片 // image:需要裁剪的图片 // re ...

  5. FineReport中JS如何自定义按钮导出

    FineReport支持多种不同的导出方式,直接使用FineReport内置导出按钮可以非常快捷方便的来对各种格式的输出,但是我们在web页面集成中的时候,往往只想将报表内容嵌入到iframe中,而工 ...

  6. Dynamics CRM使用JS隐藏自定义按钮

    在我们平时客制化开发的时候会经常遇到要制作自定义按钮的情况,而这个自定义按钮的功能又经常会有一些隐藏逻辑需要实现,所以每次通过获取控件查找这个按钮再隐藏比较麻烦,而且偶尔会出现代码没起作用的效果.下面 ...

  7. iOS开发之自定义导航栏返回按钮右滑返回手势失效的解决

    我相信针对每一个iOS开发者来说~除了根视图控制器外~所有的界面通过导航栏push过去的界面都是可以通过右滑来返回上一个界面~其实~在很多应用和APP中~用户已经习惯了这个功能~然而~作为开发者的我们 ...

  8. Dynamics CRM2011中通过JS脚本方式显示和隐藏ribbon中的自定义按钮

    首先该方法不能写在页面的onload中,因为当从子网格返回常规表单的时候ribbon区域会重新加载而常规表单所在的iframe区域是不会被刷新的,所以如果写在onload中的话就控制的不那么完全了,我 ...

  9. 【翻译】十大要避免的Ext JS开发方法

    原文地址:http://www.sencha.com/blog/top-10-ext-js-development-practices-to-avoid/ 作者:Sean Lanktree Sean ...

随机推荐

  1. centos6.3安装 jdk-8u131-linux-x64.gz

    解压指令为:tar -zxvf jdk-8u131-linux-x64.gz 设置环境变量,首先是打开设置环境变量的文件夹,指令为:vi /etc/profile     然后在英文输入法下切换到“插 ...

  2. 老男孩Day18作业:后台用户管理

    一.作业需求: 1.用户组的增删改查 2.用户增删该查 - 添加必须是对话框 - 删除必须是对话框 - 修改,必须显示默认值 3.比较好看的页面 二.博客地址:https://www.cnblogs. ...

  3. javascript中类数组转成真正的数组

    function list() { return Array.prototype.slice.call(arguments); } var list1 = list(1, 2, 3); // [1, ...

  4. sql 语句设置主键

    创建表时候 SQL code? 1 2 3 4 CREATE TABLE tb ( id INT IDENTITY(1,1) PRIMARY KEY, ) 添加时候 SQL code? 1 2 ALT ...

  5. COCO2018 stuff分割

    stuff何许人也,相对于目标而言的环境信息,一般是图像中的草地,墙面或者天空,因为往往在一张图像中这些背景占据着大部分像素,对于场景理解必不可少,所以引入了这一任务. 不过目前这个任务还没有发布te ...

  6. ProgressBar(进度条)、SeekBar(拖动条)与星级评分条(RatingBar)

    1.ProgressBar(进度条) (1)介绍 (2)常用属性 (3)xml代码 <ProgressBar android:id="@+id/progressBar2" s ...

  7. DP小小结

    入门题 : [Luogu1441]砝码称重 , [NOIP2015]子串 [AHOI2009]中国象棋 , 详见代码 [HNOI2007]梦幻岛宝珠 , 详见代码 [NOIP2012]开车旅行 , 没 ...

  8. bzoj3261: 最大异或和 (可持久化trie树)

    题目链接 题解 看到异或和最大就应该想到01 trie树 我们记\(S_i\)为前i项的异或和 那么我们的目的是最大化\(S_n\)^\(x\)^\(S_{j-1}\) \((l <= j &l ...

  9. 最大比例(贪心+思维+gcd)

    X星球的某个大奖赛设了M级奖励.每个级别的奖金是一个正整数. 并且,相邻的两个级别间的比例是个固定值. 也就是说:所有级别的奖金数构成了一个等比数列.比如: 16,24,36,54 其等比值为:3/2 ...

  10. bzoj4034 树上操作 树链剖分+线段树

    题目传送门 题目大意: 有一棵点数为 N 的树,以点 1 为根,且树点有权.然后有 M 个操作,分为三种: 操作 1 :把某个节点 x 的点权增加 a . 操作 2 :把某个节点 x 为根的子树中所有 ...