游戏开发总是有些特殊,一般的预制的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. SDUT OJ 数据结构实验之二叉树七:叶子问题

    数据结构实验之二叉树七:叶子问题 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Discuss Problem Descri ...

  2. 2B - Amy

    数据范围是18位,把每一位加起来的和最多9*18 = 162 所以只需考虑n-162 - n的数即可,暴力解决 #include <iostream> using namespace st ...

  3. LeetCode936. Stamping The Sequence

    一.题面 You want to form a target string of lowercase letters. At the beginning, your sequence is targe ...

  4. hdu6183 Color it 线段树动态开点+查询减枝

    题目传送门 题目大意: 有多次操作.操作0是清空二维平面的点,操作1是往二维平面(x,y)上放一个颜色为c的点,操作2是查询一个贴着y轴的矩形内有几种颜色的点,操作3退出程序. 思路: 由于查询的矩形 ...

  5. 欧拉图 欧拉回路 欧拉通路 Euler的认识 (转)

    转:https://www.cnblogs.com/Ash-ly/p/5397702.html 定义: 欧拉回路:图G的一个回路,如果恰通过图G的每一条边,则该回路称为欧拉回路,具有欧拉回路的图称为欧 ...

  6. mysql 5.7.20 server status 是stopped的解决办法

    mysql 5.7.20 server status 是stopped的解决办法 在安装mysql 5.7.20的过程中,前几个过程都没什么问题,但是最后一个步骤就出问题了.当check一直提示con ...

  7. Flask学习目录

    目录 Flask学习初识 Flask学习二

  8. 如何添加网页QQ在线组件

    免费开通QQ推广服务 复制代码到你想要展示的位置 粘贴,完成.

  9. web安全——文件上传

    文件上传本身不是漏洞,但如果文件上传功能的限制出现纰漏,允许了不合法且影响网站安全的文件的上传    可以将不合法且影响网站安全稳定性的文件等内容上传的均为“文件上传漏洞”        黑方将文件上 ...

  10. Java基础19-封装、方法重载、构造方法(构造函数)

    1.封装 封装就是把不想或者不该告诉别人的东西隐藏起来,把可以告诉别人的公开 做法:修改属性的访问权限来限制对属性的访问.并为每一个属性创建一对取值方法和赋值方法,用于对这些属性的访问 class D ...