package org.andengine.engine.camera.hud.controls; import static org.andengine.util.Constants.VERTEX_INDEX_X; import static org.andengine.util.Constants.VERTEX_INDEX_Y; import org.andengine.engine.camera.Camera; import org.andengine.engine.camera.hud.HUD; import org.andengine.engine.handler.timer.ITimerCallback; import org.andengine.engine.handler.timer.TimerHandler; import org.andengine.entity.scene.IOnSceneTouchListener; import org.andengine.entity.scene.Scene; import org.andengine.entity.sprite.Sprite; import org.andengine.input.touch.TouchEvent; import org.andengine.opengl.texture.region.ITextureRegion; import org.andengine.opengl.vbo.VertexBufferObjectManager; import org.andengine.util.math.MathUtils; import android.view.MotionEvent; /** * (c) 2010 Nicolas Gramlich * (c) 2011 Zynga Inc. * * @author Nicolas Gramlich * @since 10:43:09 - 11.07.2010 */ public abstract class BaseOnScreenControl extends HUD implements IOnSceneTouchListener { // =========================================================== // Constants // =========================================================== private static final int INVALID_POINTER_ID = -1; // =========================================================== // Fields // =========================================================== private final Sprite mControlBase; private final Sprite mControlKnob; private float mControlValueX; private float mControlValueY; private final IOnScreenControlListener mOnScreenControlListener; private int mActivePointerID = INVALID_POINTER_ID; // =========================================================== // Constructors // =========================================================== public BaseOnScreenControl(final float pX, final float pY, final Camera pCamera, final ITextureRegion pControlBaseTextureRegion, final ITextureRegion pControlKnobTextureRegion, final float pTimeBetweenUpdates, final VertexBufferObjectManager pVertexBufferObjectManager, final IOnScreenControlListener pOnScreenControlListener) { this.setCamera(pCamera); this.mOnScreenControlListener = pOnScreenControlListener; /* Create the control base. */ this.mControlBase = new Sprite(pX, pY, pControlBaseTextureRegion, pVertexBufferObjectManager) { @Override public boolean onAreaTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) { return BaseOnScreenControl.this.onHandleControlBaseTouched(pSceneTouchEvent, pTouchAreaLocalX, pTouchAreaLocalY); } }; /* Create the control knob. */ this.mControlKnob = new Sprite(0, 0, pControlKnobTextureRegion, pVertexBufferObjectManager); this.onHandleControlKnobReleased(); /* Register listeners and add objects to this HUD. */ this.setOnSceneTouchListener(this); this.registerTouchArea(this.mControlBase); this.registerUpdateHandler(new TimerHandler(pTimeBetweenUpdates, true, new ITimerCallback() { @Override public void onTimePassed(final TimerHandler pTimerHandler) { BaseOnScreenControl.this.mOnScreenControlListener.onControlChange(BaseOnScreenControl.this, BaseOnScreenControl.this.mControlValueX, BaseOnScreenControl.this.mControlValueY); } })); this.attachChild(this.mControlBase); this.attachChild(this.mControlKnob); this.setTouchAreaBindingOnActionDownEnabled(true); } // =========================================================== // Getter & Setter // =========================================================== public Sprite getControlBase() { return this.mControlBase; } public Sprite getControlKnob() { return this.mControlKnob; } public IOnScreenControlListener getOnScreenControlListener() { return this.mOnScreenControlListener; } // =========================================================== // Methods for/from SuperClass/Interfaces // =========================================================== @Override public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) { final int pointerID = pSceneTouchEvent.getPointerID(); if(pointerID == this.mActivePointerID) { this.onHandleControlBaseLeft(); switch(pSceneTouchEvent.getAction()) { case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: this.mActivePointerID = INVALID_POINTER_ID; } } return false; } // =========================================================== // Methods // =========================================================== public void refreshControlKnobPosition() { this.onUpdateControlKnob(this.mControlValueX * 0.5f, this.mControlValueY * 0.5f); } /** * When the touch happened outside of the bounds of this OnScreenControl. * */ protected void onHandleControlBaseLeft() { this.onUpdateControlKnob(0, 0); } /** * When the OnScreenControl was released. */ protected void onHandleControlKnobReleased() { this.onUpdateControlKnob(0, 0); } protected boolean onHandleControlBaseTouched(final TouchEvent pSceneTouchEvent, final float pTouchAreaLocalX, final float pTouchAreaLocalY) { final int pointerID = pSceneTouchEvent.getPointerID(); switch(pSceneTouchEvent.getAction()) { case MotionEvent.ACTION_DOWN: if(this.mActivePointerID == INVALID_POINTER_ID) { this.mActivePointerID = pointerID; this.updateControlKnob(pTouchAreaLocalX, pTouchAreaLocalY); return true; } break; case MotionEvent.ACTION_UP: case MotionEvent.ACTION_CANCEL: if(this.mActivePointerID == pointerID) { this.mActivePointerID = INVALID_POINTER_ID; this.onHandleControlKnobReleased(); return true; } break; default: if(this.mActivePointerID == pointerID) { this.updateControlKnob(pTouchAreaLocalX, pTouchAreaLocalY); return true; } break; } return true; } private void updateControlKnob(final float pTouchAreaLocalX, final float pTouchAreaLocalY) { final Sprite controlBase = this.mControlBase; final float relativeX = MathUtils.bringToBounds(0, controlBase.getWidth(), pTouchAreaLocalX) / controlBase.getWidth() - 0.5f; final float relativeY = MathUtils.bringToBounds(0, controlBase.getHeight(), pTouchAreaLocalY) / controlBase.getHeight() - 0.5f; this.onUpdateControlKnob(relativeX, relativeY); } /** * @param pRelativeX from <code>-0.5</code> (left) to <code>0.5</code> (right). * @param pRelativeY from <code>-0.5</code> (top) to <code>0.5</code> (bottom). */ protected void onUpdateControlKnob(final float pRelativeX, final float pRelativeY) { final Sprite controlBase = this.mControlBase; final Sprite controlKnob = this.mControlKnob; this.mControlValueX = 2 * pRelativeX; this.mControlValueY = 2 * pRelativeY; final float[] controlBaseSceneCenterCoordinates = controlBase.getSceneCenterCoordinates(); final float x = controlBaseSceneCenterCoordinates[VERTEX_INDEX_X] - controlKnob.getWidth() * 0.5f + pRelativeX * controlBase.getWidthScaled(); final float y = controlBaseSceneCenterCoordinates[VERTEX_INDEX_Y] - controlKnob.getHeight() * 0.5f + pRelativeY * controlBase.getHeightScaled(); controlKnob.setPosition(x, y); } // =========================================================== // Inner and Anonymous Classes // =========================================================== public static interface IOnScreenControlListener { // =========================================================== // Constants // =========================================================== // =========================================================== // Methods // =========================================================== /** * @param pBaseOnScreenControl * @param pValueX between <code>-1</code> (left) to <code>1</code> (right). * @param pValueY between <code>-1</code> (up) to <code>1</code> (down). */ public void onControlChange(final BaseOnScreenControl pBaseOnScreenControl, final float pValueX, final float pValueY); } }