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;
级联不透明度,可以使得对按钮设置透明度时整体透明度也一起变化
Cocos2d-js 开发记录:自定义按钮的更多相关文章
- wordpress优化之结合prism.js为编辑器自定义按钮转化代码
原文链接 http://ymblog.net/2016/07/24/wordpress-prism/ 继昨天花了一天一夜的时间匆匆写了主题Jiameil3.0之后,心中一直在想着优化加速,体验更好,插 ...
- JS开发中自定义调试信息开关
在开发过程中,可能随处留下几个console.log,或者alert语句,这些语句在开发过程中是很有价值的.但是项目一旦进入生产环境,过多的console.log可能影响到浏览器的运行效率,过多的al ...
- Dynamics CRM 客户端程序开发:自定义系统标准按钮的可用性
关注本人微信和易信公众号: 微软动态CRM专家罗勇 ,回复125或者20140414可方便获取本文,同时可以在第一时间得到我发布的最新的博文信息,follow me! 一般是新建一个解决方案用于客制化 ...
- iOS开发——UI进阶篇(十八)核心动画小例子,转盘(裁剪图片、自定义按钮、旋转)图片折叠、音量震动条、倒影、粒子效果
一.转盘(裁剪图片.自定义按钮.旋转) 1.裁剪图片 将一张大图片裁剪为多张 // CGImageCreateWithImageInRect:用来裁剪图片 // image:需要裁剪的图片 // re ...
- FineReport中JS如何自定义按钮导出
FineReport支持多种不同的导出方式,直接使用FineReport内置导出按钮可以非常快捷方便的来对各种格式的输出,但是我们在web页面集成中的时候,往往只想将报表内容嵌入到iframe中,而工 ...
- Dynamics CRM使用JS隐藏自定义按钮
在我们平时客制化开发的时候会经常遇到要制作自定义按钮的情况,而这个自定义按钮的功能又经常会有一些隐藏逻辑需要实现,所以每次通过获取控件查找这个按钮再隐藏比较麻烦,而且偶尔会出现代码没起作用的效果.下面 ...
- iOS开发之自定义导航栏返回按钮右滑返回手势失效的解决
我相信针对每一个iOS开发者来说~除了根视图控制器外~所有的界面通过导航栏push过去的界面都是可以通过右滑来返回上一个界面~其实~在很多应用和APP中~用户已经习惯了这个功能~然而~作为开发者的我们 ...
- Dynamics CRM2011中通过JS脚本方式显示和隐藏ribbon中的自定义按钮
首先该方法不能写在页面的onload中,因为当从子网格返回常规表单的时候ribbon区域会重新加载而常规表单所在的iframe区域是不会被刷新的,所以如果写在onload中的话就控制的不那么完全了,我 ...
- 【翻译】十大要避免的Ext JS开发方法
原文地址:http://www.sencha.com/blog/top-10-ext-js-development-practices-to-avoid/ 作者:Sean Lanktree Sean ...
随机推荐
- Qt 学习之路 2(51):布尔表达式树模型
Qt 学习之路 2(51):布尔表达式树模型 豆子 2013年5月15日 Qt 学习之路 2 17条评论 本章将会是自定义模型的最后一部分.原本打算结束这部分内容,不过实在不忍心放弃这个示例.来自于 ...
- 解压与压缩(把dataset转为string、、 )
/// <summary> /// 压缩 解压 /// </summary> public class ZipHelper { #region 压缩解缩 /// <sum ...
- C++ STL之Vector
向量 vector 是一种对象实体, 能够容纳许多其他类型相同的元素, 因此又被称为容器. vector 属于STL(Standard Template Library, 标准模板库)中的一种自定义的 ...
- 在python3.5中pip安装scrapy,遇到 error: Microsoft Visual C++ 14.0 is required
本来在python3.5中安装scrapy一路顺畅(pip install scrapy),中间遇到一个 error: Microsoft Visual C++ 14.0 is required. x ...
- 从源码角度深入分析 ant
[转自] http://www.tuicool.com/articles/eQvIRbA Ant的基本概念 首先是ant的基本概念: Project,Target,Tasks,Properties,P ...
- 论文笔记 | Self-organized Text Detection with Minimal Post-processing via Border Learning
论文链接:http://openaccess.thecvf.com/content_ICCV_2017/papers/Wu_Self-Organized_Text_Detection_ICCV_201 ...
- PIE SDK临时元素的绘制
1. 功能简介 在数据的处理中会用到临时元素的绘制,用于当前显示:临时元素包括点.线.面.文本.图片五种元素:目前PIE SDK支持这五种元素的绘制,下面对五种临时元素的绘制功能进行介绍. 2. 功能 ...
- PIE SDK存储格式转换
1.算法功能简介 影像存储格式转换可以实现栅格数据存储格式的自由转换,其中存储格式可以是 BSQ. BIP. BIL 三种格式. 遥感数字图像数据的存储与分发,通常采用以下三种数据格式: BSQ( ...
- nginx 代理服务指令详解
nginx 正向代理与反向代理说明图 超级形象说明. 正向代理指令: 1, resolver 这个用于DNS服务器的ip . DNS服务器的主要工作是进行域名解析,将域名映射为对应IP地址 resol ...
- Flask中的的SQLAlchemy2
昨天更新了博客不知对各位职场的大佬有没有帮助,如果没有看到的请用小手狠狠地戳这里 Flask中的的SQLAlchemy 今天呢,我们来说一下多对多表的关系,知道不?开始之前我先说一个事,昨晚更新了博客 ...