现在的位置: 首页 > 综合 > 正文

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

2013年10月08日 ⁄ 综合 ⁄ 共 5322字 ⁄ 字号 评论关闭

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的显示状态

@Override
	public 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 width							Button宽度 
	 * @param height						Button高度
	 * @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 stub
		bgButtonSprite = 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
	// ===========================================================
	@Override
	public boolean onAreaTouched(TouchEvent pSceneTouchEvent, float pTouchAreaLocalX, float pTouchAreaLocalY)
	{
		// TODO Auto-generated method stub
		bgButtonSprite.onAreaTouched(pSceneTouchEvent, pTouchAreaLocalX, pTouchAreaLocalY);

		// TODO 如果文字也要发生变化,则在这里处理,比如换个颜色之类的
		
		
		return super.onAreaTouched(pSceneTouchEvent, pTouchAreaLocalX, pTouchAreaLocalY);
	}

}

粗糙的效果图:

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

抱歉!评论已关闭.