游戏引擎AndEngine总结(八):自定义Button

来源:互联网 发布:住房维修基金软件 编辑:程序博客网 时间:2024/04/29 23:52

UI中最基础也是最重要的就是Button了,不论是应用还是游戏,Button以及like Button的控件都随处可见!

在AndEngine中也是支持Button的,并且在AndEngineExample中也有相应的例子,不过我下载的那个版本作者是写错了的,稍微需要一下改动,如果你的也有问题(点击没有效果),点击察看。


对于使用AndEngine的一般Button,ButtonSprite这个类基本上就可以实现了,本文会先介绍一下ButtonSprite的实现原理,然后再简单的扩展一下ButtonSprite,(使其带上相应的文字)。这个是很简单的,但是对于理解Button的切换原理是有帮助的!


一.ButtonSprite解析

ButtonSprite的实现原理很简单,首先ButtonSprite是一个Sprit,并且是一个TiledSprite的子类,(AnimatedSprite也是TiledSprite的子类),也许看到这就会明白了,其实ButtonSprite就是类似于带有动画的精灵,只是AnimatedSprite是根据时间或者其他因素来触发更换图片资源的,而ButtonSprite是根据用户点击触发!

1.ButtonSprite支持的状态:

ButtonSprite支持3种状态:未点击(正常状态),点击状态,禁止状态(禁止用户点击状态),它定义在ButtonSprite的内部枚举

private static enum State{// ===========================================================// Elements// ===========================================================NORMAL(0), PRESSED(1), DISABLED(2);// ===========================================================// Fields// ===========================================================private final int mTiledTextureRegionIndex;// ===========================================================// Constructors// ===========================================================private State(final int pTiledTextureRegionIndex){this.mTiledTextureRegionIndex = pTiledTextureRegionIndex;}// ===========================================================// Getter & Setter// ===========================================================public int getTiledTextureRegionIndex(){return this.mTiledTextureRegionIndex;}}
ButtonSprite根据为其分配的图片资源TiledTextureRegion的Tiled个数来对应其不同状态下的显示,规则为TileTextureRegion[0]是正常状态,TileTextureRegion[1]是选中状态,TileTextureRegion[2]是禁止状态,当然,你可以设置一种或者两种状态,看需求了!


2.ButtonSprite的构造方法

先是实现父类(TiledSprite)的构造,然后计算提供的状态,最后设置初始状态,很简单

public ButtonSprite(final float pX, final float pY, final ITiledTextureRegion pTiledTextureRegion,final VertexBufferObjectManager pVertexBufferObjectManager, final OnClickListener pOnClickListener){super(pX, pY, pTiledTextureRegion, pVertexBufferObjectManager);this.mOnClickListener = pOnClickListener;this.mStateCount = pTiledTextureRegion.getTileCount();switch (this.mStateCount){case 1:Debug.w("No " + ITextureRegion.class.getSimpleName() + " supplied for "+ State.class.getSimpleName() + "." + State.PRESSED + ".");case 2:Debug.w("No " + ITextureRegion.class.getSimpleName() + " supplied for "+ State.class.getSimpleName() + "." + State.DISABLED + ".");break;case 3:break;default:throw new IllegalArgumentException("The supplied "+ ITiledTextureRegion.class.getSimpleName()+ " has an unexpected amount of states: '" + this.mStateCount + "'.");}this.changeState(State.NORMAL);}

3.最重要的也许就是点击的部分了,当见听到用户点击的事件,改变ButtonSprite的显示状态

@Overridepublic boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX,final float pTouchAreaLocalY){if (!this.isEnabled()){this.changeState(State.DISABLED);}else if (pSceneTouchEvent.isActionDown()){this.changeState(State.PRESSED);}else if (pSceneTouchEvent.isActionCancel()|| !this.contains(pSceneTouchEvent.getX(), pSceneTouchEvent.getY())){this.changeState(State.NORMAL);}else if (pSceneTouchEvent.isActionUp() && this.mState == State.PRESSED){this.changeState(State.NORMAL);if (this.mOnClickListener != null){this.mOnClickListener.onClick(this, pTouchAreaLocalX, pTouchAreaLocalY);}}return true;}

4.最后就是一些零散的东东,比如设置禁止状态之类的,不再赘述!


二.弱弱的扩展一下ButtonSprite

ButtonSprite已经基本可以实现我们想要的功能了,但是如果我们想在其上面加上文字,该如何做呢?(好吧,也许这是一个无理的需求,没有几款游戏的按钮上还需要画上丑陋的文字,但是有些情况还是需要的,比如问答形式的,需要用户点击的问题选项。。。)

1.实现方案一:

先绘制ButtonSprite,然后在在Button上面绘制一个Text,完全可以实现,只是每次设置一个问题选项的时候要初始化两次,再attach两次,如果工作量少的话,还可以,如果多的话呢?那就是x2的工作量啊,会不会太傻了!

2.实现方案二:

a.继承于ButtonSprite

在其中添加一个Text的变量,这是一般最先想到的方法,确实也可以做到,但是要考虑ButtonSprite是不是为我们提供了很好的继承,我觉得作者也许并不希望我们这么做,不然为什么内部类State是私有的呢(瞎猜而已,源码在手,作者能做的只是提供思路,我们完全可以直接修改他的代码)。。。但是,这不是最简单的方法!

b.组合ButtonSprite和Text

几乎所有的面向语言的书里都会说继承和组合是最重要的两个特性,还好,没忘掉!其实想到这,我们要做的就很简单了,随便继承一个定义过onAreaTouch()方法的类,(只是为了简单),然后包含ButtonSprite和Text的对象就可以了。当点击事件发生的时候,背景的改变就交给ButtonSprite对象去做吧!如果有需要,我们只需要处理Text的点击变化!这几行的代码就足够了!

public class CustomButton extends Rectangle{private final static String TAG = "onerain";// 背景private ButtonSprite bgButtonSprite;// 显示文字private Text text;/** * 构造方法 * @param pX左上角x坐标 * @param pY左上角y坐标 * @param widthButton宽度  * @param heightButton高度 * @param pTiledTextureRegion在不同状态下背景图片资源 * @param pFont显示字体 * @param pText显示文字 * @param pVertexBufferObjectManager顶点管理器 */public CustomButton(float pX, float pY, TiledTextureRegion pTiledTextureRegion, Font pFont, String pText, VertexBufferObjectManager pVertexBufferObjectManager){super(pX, pY, pTiledTextureRegion.getWidth(), pTiledTextureRegion.getHeight(), pVertexBufferObjectManager);// TODO Auto-generated constructor stubbgButtonSprite = new ButtonSprite(0, 0, pTiledTextureRegion, pVertexBufferObjectManager);text = new Text(0, 0, pFont, pText, pVertexBufferObjectManager);// 计算一下居中的位置float textX = (bgButtonSprite.getWidth() - text.getWidth()) / 2;float textY = (bgButtonSprite.getHeight() - text.getHeight()) / 2;text.setPosition(textX, textY);attachChild(bgButtonSprite);attachChild(text);}// ===========================================================// ===========================================================// Methods for/from SuperClass/Interfaces// ===========================================================@Overridepublic boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY){// TODO Auto-generated method stubbgButtonSprite.onAreaTouched(pSceneTouchEvent, pTouchAreaLocalX, pTouchAreaLocalY);// TODO 如果文字也要发生变化,则在这里处理,比如换个颜色之类的return super.onAreaTouched(pSceneTouchEvent, pTouchAreaLocalX, pTouchAreaLocalY);}}

粗糙的效果图:



好了,老规矩,提供源码,点击下载