游戏开发总是有些特殊,一般的预制的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. 'javac' 不是内部或外部命令,也不是可运行的程序

    win10 系统下'javac' 不是内部或外部命令,也不是可运行的程序 1.在系统变量下面配置 JAVA_HOME:你自己的jdk的路径 CLASSPATH= .;%JAVA_HOME%libdt. ...

  2. docker 安装 redis

    docker拉去镜像以及配置生成容器的步骤几乎和之前的nginx安装一样,直接写下面的命令了 1. docker pull redis 2. docker run -p 6379:6379 -v /U ...

  3. libcaffe.so.1.0.0: cannot open shared object file: No such file or directory 运行时报错

    caffe安装好后lib没有配置到/usr/lib或/usr/local/lib中,需手动配置: sudo vim ~/.bashrc export LD_LIBRARY_PATH=your_path ...

  4. 二分答案 & 洛谷 P2678 跳石头

    首先让我们先学一下二分答案这个东西...   二分答案,肯定与二分有关,还与可能是答案的东西有关... 二分答案的准确定义: 二分答案是指在答案具有单调性的前提下,利用二分的思想枚举答案,将求解问题转 ...

  5. php中magic_quotes_gpc的作用 解决日文数据提交后多出来反斜杠的问题

    magic_quotes_gpc发生作用是在传递$_GET,$_POST,$_COOKIE时 1.条件: magic_quotes_gpc=off写入数据库的字符串未经过任何过滤处理.从数据库读出的字 ...

  6. R语言常用包汇总

    转载于:https://blog.csdn.net/sinat_26917383/article/details/50651464?locationNum=2&fps=1 一.一些函数包大汇总 ...

  7. C++_新特性1-类型转换运算符

    C++的创始人认为C语言的类型转换运算符太过于松散.他采取了更加严格的限制允许的类型转换.并添加了4个类型转换运算符. 这部分特性比较高阶,我把它归于奇技淫巧的范畴.这里简单介绍一下,以后实际有用到再 ...

  8. 【算法笔记】B1001 害死人不偿命的(3n+1)猜想

    1001 害死人不偿命的(3n+1)猜想 (15 分)卡拉兹(Callatz)猜想: 对任何一个正整数 n,如果它是偶数,那么把它砍掉一半:如果它是奇数,那么把 (3n+1) 砍掉一半.这样一直反复砍 ...

  9. ASP.NET中MD5的加密方式很简单

    在ASP.NET中MD5的加密方式很简单,代码如下: FormsAuthentication.HashPasswordForStoringInConfigFile(str, "MD5&quo ...

  10. HDU 3783

    读入一个字符串,字符串中包含ZOJ三个字符,个数不一定相等,按ZOJ的顺序输出,当某个字符用完时,剩下的仍然按照ZOJ的顺序输出. MY:(OUTPUT LIMIT EXCEED) #include& ...