I want to learn how to handle the image and gesture function in android.
So I read the sample "InteractiveChart" under "Animating a Scroll Gesture" section in Android developer website.
While I read about "onDoubleTap" method in InteractiveLineGraphView.java.
#Override
public boolean onDoubleTap(MotionEvent e) {
mZoomer.forceFinished(true);
if (hitTest(e.getX(), e.getY(), mZoomFocalPoint)) {
mZoomer.startZoom(ZOOM_AMOUNT);
}
ViewCompat.postInvalidateOnAnimation(InteractiveLineGraphView.this);
return true;
}
I checked the code of Zoomer.
It mainly calls DecelerateInterpolator method and set some variables.
I wonder how can "Zoomer" achieve the double tap zoom function.
Does "DecelerateInterpolator" do the work? Or I just missed something?
public class Zoomer {
/**
* The interpolator, used for making zooms animate 'naturally.'
*/
private Interpolator mInterpolator;
/**
* The total animation duration for a zoom.
*/
private int mAnimationDurationMillis;
/**
* Whether or not the current zoom has finished.
*/
private boolean mFinished = true;
/**
* The current zoom value; computed by {#link #computeZoom()}.
*/
private float mCurrentZoom;
/**
* The time the zoom started, computed using {#link android.os.SystemClock#elapsedRealtime()}.
*/
private long mStartRTC;
/**
* The destination zoom factor.
*/
private float mEndZoom;
public Zoomer(Context context) {
mInterpolator = new DecelerateInterpolator();
mAnimationDurationMillis = context.getResources().getInteger(
android.R.integer.config_shortAnimTime);
}
/**
* Forces the zoom finished state to the given value. Unlike {#link #abortAnimation()}, the
* current zoom value isn't set to the ending value.
*
* #see android.widget.Scroller#forceFinished(boolean)
*/
public void forceFinished(boolean finished) {
mFinished = finished;
}
/**
* Aborts the animation, setting the current zoom value to the ending value.
*
* #see android.widget.Scroller#abortAnimation()
*/
public void abortAnimation() {
mFinished = true;
mCurrentZoom = mEndZoom;
}
/**
* Starts a zoom from 1.0 to (1.0 + endZoom). That is, to zoom from 100% to 125%, endZoom should
* by 0.25f.
*
* #see android.widget.Scroller#startScroll(int, int, int, int)
*/
public void startZoom(float endZoom) {
mStartRTC = SystemClock.elapsedRealtime();
mEndZoom = endZoom;
mFinished = false;
mCurrentZoom = 1f;
}
/**
* Computes the current zoom level, returning true if the zoom is still active and false if the
* zoom has finished.
*
* #see android.widget.Scroller#computeScrollOffset()
*/
public boolean computeZoom() {
if (mFinished) {
return false;
}
long tRTC = SystemClock.elapsedRealtime() - mStartRTC;
if (tRTC >= mAnimationDurationMillis) {
mFinished = true;
mCurrentZoom = mEndZoom;
return false;
}
float t = tRTC * 1f / mAnimationDurationMillis;
mCurrentZoom = mEndZoom * mInterpolator.getInterpolation(t);
return true;
}
/**
* Returns the current zoom level.
*
* #see android.widget.Scroller#getCurrX()
*/
public float getCurrZoom() {
return mCurrentZoom;
}
}
Can someone also recommend some great sample about image and gesture handling? From basic to advanced.....Thanks a lot.
The double tap is actually done in InteractiveLineGraphView view itself
#Override
public boolean onDoubleTap(MotionEvent e) {
mZoomer.forceFinished(true);
if (hitTest(e.getX(), e.getY(), mZoomFocalPoint)) {
mZoomer.startZoom(ZOOM_AMOUNT);
}
ViewCompat.postInvalidateOnAnimation(InteractiveLineGraphView.this);
return true;
}
Zoomer is just a helper class holding current zoom level
Related
I am investigating Android ViewPager animation in my current project.
I would like to give my users an affordance in relation to my ViewPager.
The effect I am looking for it to "shake" the ViewPager from left to right to partially show the neighbouring pages to the selected page.
When the user selects the first page (F), I would "Shake" between F and F + 1.
When the user selects the last page (L), I would "Shake" between L and L - 1.
Otherwise, when the user selects any other page (X), I would "Shake" between X - 1, X and X + 1.
I have tried the following approaches which have all given unsatisfactory results.
Fake drag using screen density to calculate shake distance and valueAnimator and ObjectAnimator.
Animating ViewPager.PageTransformer.
I am unable to get a satisfactory "Shake" effect.
I would like to achieve a Spring Dampening style of animation.
The FakeDrag was closest, although the effect was not reliable, it seemed to never work correctly the first time I started the animation.
Even the FakeDrag would not give the desired smooth shake between page swipes.
I would like to employ the physics-based animations on my view pager but couldn't see how.
Is it possible to achieve my desired animation?
UPDATE
I have developed this code which gives the desired effect, however its JANKY!
#Override
protected void onResume() {
super.onResume();
final Handler handler = new Handler();
handler.postDelayed(() -> animateViewPager(ANIMATION_OFFSET, ANIMATION_DURATION), ANIMATION_DELAY);
}
/**
* #param offset
* #param duration
*/
private void animateViewPager(final int offset, final int duration) {
if (animator.isRunning()) {
return;
}
animator.removeAllUpdateListeners();
animator.removeAllListeners();
animator.setIntValues(0, -offset);
animator.setDuration(duration);
animator.setRepeatCount(getRepeatCount());
animator.setRepeatMode(ValueAnimator.RESTART);
animator.addUpdateListener(constructUpdateListener());
animator.addListener(constructAnimatorListener());
animator.start();
}
/**
*
* #return
*/
private Animator.AnimatorListener constructAnimatorListener() {
return new AnimatorListenerAdapter() {
#Override
public void onAnimationStart(final Animator animation) {
animFactor = 1;
}
#Override
public void onAnimationEnd(final Animator animation) {
viewPager.endFakeDrag();
if (xAnimation == null) {
xAnimation = createSpringAnimation(viewPager, SpringAnimation.X, 0, SpringForce.STIFFNESS_LOW, SpringForce.DAMPING_RATIO_HIGH_BOUNCY);
} else {
xAnimation.cancel();
}
viewPager.animate().x(viewPager.getWidth() * 0.1f).setDuration(0).start();
xAnimation.start();
}
#Override
public void onAnimationRepeat(final Animator animation) {
animFactor = -1;
}
};
}
/**
* #return
*/
private int getRepeatCount() {
if (isOnlyPage()) {
return 0;
}
if (isFirstListItem()) {
return REPEAT_ONCE;
}
if (isLastListItem()) {
return REPEAT_ONCE;
}
return REPEAT_TWICE;
}
#SuppressWarnings("StatementWithEmptyBody")
private ValueAnimator.AnimatorUpdateListener constructUpdateListener() {
return animation -> {
final Integer value = animFactor * (Integer) animation.getAnimatedValue();
if (viewPager.isFakeDragging()) {
} else {
viewPager.beginFakeDrag();
}
viewPager.fakeDragBy(value);
};
}
/**
* #param view
* #param property
* #param finalPosition
* #param stiffness
* #param dampingRatio
* #return
*/
private SpringAnimation createSpringAnimation(final View view, final DynamicAnimation.ViewProperty property, final float finalPosition, final float stiffness, final float dampingRatio) {
final SpringAnimation animation = new SpringAnimation(view, property);
final SpringForce springForce = new SpringForce(finalPosition);
springForce.setStiffness(stiffness);
springForce.setDampingRatio(dampingRatio);
animation.setSpring(springForce);
return animation;
}
Hi i am using https://github.com/limccn/Android-Charts library for showing stock live data on chart in my android app. i am using CandleStick Chart of this library. everything is working fine except one thing is that i am not able to show tool tip when mouse over on any candle stick inside chart for display data. i am using below code for initializing chart. does any one know how to show tool tip or how we can attached any view when user mouse over on any stick of chart.
private void initChart() {
for (int i = 0; i < chartData.size(); i++) {
//OHLCEntity(double open, double high, double low, double close, int date)
ChartData chartdata = chartData.get(i);
String dateString = chartdata.getT_Time().substring(0, chartdata.getT_Time().lastIndexOf("T"));
String timeString = chartdata.getT_Time().substring(chartdata.getT_Time().lastIndexOf("T") + 1, chartdata.getT_Time().toString().length());
Pattern p = Pattern.compile(":");
String[] times = p.split(timeString);
String dateValue = "";
if (times.length >= 3) {
dateValue = dateString.replaceAll("-", "").trim().toString() + times[0].trim().toString() + "" + times[1].toString().trim();
} else {
dateValue = dateString.replaceAll("-", "").trim().toString();
}
ohlc.add(new OHLCEntity(chartdata.getT_Open(), chartdata.getHigh(), chartdata.getLow(), chartdata.getT_Close(), Integer.valueOf(dateValue)));
}
ChartData maxds = Collections.max(chartData, new ChartComparator());
candlestickchart.setAxisXColor(Color.LTGRAY);
candlestickchart.setAxisYColor(Color.LTGRAY);
candlestickchart.setLatitudeColor(Color.GRAY);
candlestickchart.setLongitudeColor(Color.GRAY);
candlestickchart.setBorderColor(Color.LTGRAY);
candlestickchart.setLongitudeFontColor(Color.WHITE);
candlestickchart.setLatitudeFontColor(Color.WHITE);
// 最大显示足数
candlestickchart.setMaxSticksNum(chartData.size());
// 最大纬线数
// candlestickchart.setLatitudeNum(5);
// // 最大经线数
// candlestickchart.setLongitudeNum(3);
// 最大价格
candlestickchart.setMaxValue(maxds.getVolume());
// 最小价格
int minIndex = chartData.indexOf(Collections.min(chartData, new ChartComparator()));
candlestickchart.setMinValue(chartData.get(minIndex).getVolume());
candlestickchart.setDisplayLongitudeTitle(true);
candlestickchart.setDisplayLatitudeTitle(true);
candlestickchart.setDisplayLatitude(true);
candlestickchart.setDisplayLongitude(true);
candlestickchart.setBackgroundColor(Color.BLACK);
candlestickchart.setDataQuadrantPaddingTop(5);
candlestickchart.setDataQuadrantPaddingBottom(5);
candlestickchart.setDataQuadrantPaddingLeft(5);
candlestickchart.setDataQuadrantPaddingRight(5);
// candlestickchart.setAxisYTitleQuadrantWidth(50);
// candlestickchart.setAxisXTitleQuadrantHeight(20);
candlestickchart.setAxisXPosition(Axis.AXIS_X_POSITION_BOTTOM);
candlestickchart.setAxisYPosition(Axis.AXIS_Y_POSITION_RIGHT);
// 为chart2增加均线
candlestickchart.setStickData(new ListChartData<IStickEntity>(ohlc));
candlestickchart.setOnDisplayCursorListener(new IDisplayCursorListener() {
public void onCursorChanged(IDataCursor dataCursor, int displayFrom,
int displayNumber) {
candlestickchart.setDisplayFrom(displayFrom);
candlestickchart.setDisplayNumber(displayNumber);
candlestickchart.postInvalidate();
}
});
candlestickchart.setOnTouchGestureListener(new OnTouchGestureListener() {
/* (non-Javadoc)
*
* #param touchable
* #param event
* #see cn.limc.androidcharts.event.OnTouchGestureListener#onTouchDown(cn.limc.androidcharts.event.ITouchable, android.view.MotionEvent)
*/
#Override
public void onTouchDown(ITouchable touchable, MotionEvent event) {
super.onTouchDown(touchable, event);
candlestickchart.touchDown(new PointF(event.getX(), event.getY()));
}
/* (non-Javadoc)
*
* #param touchable
* #param event
* #see cn.limc.androidcharts.event.OnTouchGestureListener#onTouchMoved(cn.limc.androidcharts.event.ITouchable, android.view.MotionEvent)
*/
#Override
public void onTouchMoved(ITouchable touchable, MotionEvent event) {
super.onTouchMoved(touchable, event);
candlestickchart.touchMoved(new PointF(event.getX(), event.getY()));
}
/* (non-Javadoc)
*
* #param touchable
* #param event
* #see cn.limc.androidcharts.event.OnTouchGestureListener#onTouchUp(cn.limc.androidcharts.event.ITouchable, android.view.MotionEvent)
*/
#Override
public void onTouchUp(ITouchable touchable, MotionEvent event) {
super.onTouchUp(touchable, event);
candlestickchart.touchUp(new PointF(event.getX(), event.getY()));
}
});
candlestickchart.setAutoCalcValueRange(true);
candlestickchart.setDisplayCrossXOnTouch(true);
candlestickchart.setDisplayCrossYOnTouch(true);
}
If you want to get the selected stick data index, you can use:
public int getSelectedIndex()
If you want to get the touched Point, you can use:
Inside setOnTouchGestureListener:
public void onTouchMoved(ITouchable touchable, MotionEvent event){
new PointF(event.getX(), event.getY())
}
Outside setOnTouchGestureListener (Activity, Fragment, ViewGroup):
public PointF getTouchPoint()
For more features supports, choose SlipCandleStickChart.
I started working on AndEngine and I have learnt a lot but i am stuck in creating levels selector for my game. I know this is something to do with getTextureManager() as i went through this when i am trying to attach ITextureRegion to my sprite object, that i solved but this time i am going nowhere for last day.
mainActivity.java
import org.andengine.engine.camera.Camera;
import org.andengine.engine.options.EngineOptions;
import org.andengine.engine.options.ScreenOrientation;
import org.andengine.engine.options.WakeLockOptions;
import org.andengine.engine.options.resolutionpolicy.FillResolutionPolicy;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.scene.background.Background;
import org.andengine.opengl.font.FontFactory;
import org.andengine.opengl.texture.ITexture;
import org.andengine.opengl.texture.TextureManager;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.BitmapTextureAtlasTextureRegionFactory;
import org.andengine.opengl.texture.atlas.bitmap.BuildableBitmapTextureAtlas;
import org.andengine.opengl.texture.atlas.bitmap.source.IBitmapTextureAtlasSource;
import org.andengine.opengl.texture.atlas.buildable.builder.BlackPawnTextureAtlasBuilder;
import org.andengine.opengl.texture.atlas.buildable.builder.ITextureAtlasBuilder.TextureAtlasBuilderException;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.texture.region.TextureRegion;
import org.andengine.ui.activity.SimpleBaseGameActivity;
import org.andengine.util.color.Color;
import android.graphics.Typeface;
import android.util.Log;
public class Main_Activity extends SimpleBaseGameActivity {
EngineOptions engine;
Camera mCamera;
private static final int WIDTH = 800;
private static final int HEIGHT = 480;
LevelSelector ls;
Scene mScene;
public org.andengine.opengl.font.Font mFont;
ITextureRegion mTextureRegion;
#Override
public EngineOptions onCreateEngineOptions() {
mCamera = new Camera(0, 0, WIDTH, HEIGHT);
engine = new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, new FillResolutionPolicy(), mCamera);
engine.setWakeLockOptions(WakeLockOptions.SCREEN_ON);
return engine;
}
#Override
protected void onCreateResources() {
BuildableBitmapTextureAtlas mBitmapTextureAtlas = new BuildableBitmapTextureAtlas(this.getTextureManager() ,32 , 32);
mTextureRegion = BitmapTextureAtlasTextureRegionFactory.createFromAsset(mBitmapTextureAtlas, this, "marble.png");
try {
mBitmapTextureAtlas.build(new BlackPawnTextureAtlasBuilder<IBitmapTextureAtlasSource, BitmapTextureAtlas>(0, 1, 1));
mBitmapTextureAtlas.load();
} catch (TextureAtlasBuilderException e) {
Log.e("", ""+e);
}
this.mFont = FontFactory.create(this.getFontManager(), this.getTextureManager(), 256, 256, Typeface.create(Typeface.DEFAULT, Typeface.BOLD), 32);
this.mFont.load();
}
#Override
protected Scene onCreateScene() {
mScene = new Scene();
mScene.setBackground(new Background(0.09804f, 0.6274f, 0.8784f));
ls = new LevelSelector(5, 2, WIDTH, HEIGHT, mScene, mEngine);
ls.createTiles(mTextureRegion, mFont);
ls.show();
return mScene;
}
}
LayerSelector.java
import org.andengine.engine.options.EngineOptions;
import org.andengine.entity.Entity;
import org.andengine.entity.scene.Scene;
import org.andengine.entity.sprite.Sprite;
import org.andengine.entity.text.Text;
import org.andengine.input.touch.TouchEvent;
import org.andengine.opengl.font.Font;
import org.andengine.opengl.texture.region.ITextureRegion;
import org.andengine.opengl.texture.region.TextureRegion;
import android.service.wallpaper.WallpaperService.Engine;
public class LevelSelector extends Entity {
/* Level selector layer properties */
private final int COLUMNS = 6;
private final int ROWS = 6;
/* Level selector tile properties */
private final int TILE_DIMENSION = 50;
private final int TILE_PADDING = 15;
private final Scene mScene;
private final org.andengine.engine.Engine mEngine;
/*
* The mChapter variable can allow each LevelSelector object to contain
* level tiles which begin levels in different chapters.
*/
private final int mChapter;
/* Variable containing the current max level unlocked */
private final int mMaxLevel;
/* Camera width and height are needed for the layout */
private final int mCameraWidth;
private final int mCameraHeight;
/* Initial x/y coordinates used for tile positioning */
private final float mInitialX;
private final float mInitialY;
/*
* Variable which defines whether the LevelSelector is hidden or visible
*/
private boolean mHidden = true;
/**
* The LevelSelector object can be used to display a grid of level tiles for
* user selection.
*
* #param pMaxLevel
* Current max unlocked level.
* #param pChapter
* Chapter/world number of this particular LevelSelector.
* #param pCameraWidth
* Camera object's width value.
* #param pCameraHeight
* Camera object's height value.
* #param pScene
* The Scene in which the LevelSelector will be displayed on.
* #param pEngine
* AndEngine's mEngine object.
*/
public LevelSelector(final int pMaxLevel, final int pChapter,
final int pCameraWidth, final int pCameraHeight,
final Scene pScene, final org.andengine.engine.Engine pEngine) {
/* Initialize member variables */
this.mScene = pScene;
this.mEngine = pEngine;
this.mChapter = pChapter;
this.mMaxLevel = pMaxLevel;
this.mCameraWidth = pCameraWidth;
this.mCameraHeight = pCameraHeight;
/*
* Obtain the initial tile's X coordinate by subtracting half of the
* entire level selector width including all tiles and padding from the
* center of the Scene
*/
final float halfLevelSelectorWidth = ((TILE_DIMENSION * COLUMNS) + TILE_PADDING
* (COLUMNS - 1)) * 0.5f;
this.mInitialX = (this.mCameraWidth * 0.5f) - halfLevelSelectorWidth;
/* Same math as above applies to the Y coordinate */
final float halfLevelSelectorHeight = ((TILE_DIMENSION * ROWS) + TILE_PADDING
* (ROWS - 1)) * 0.5f;
this.mInitialY = (this.mCameraHeight * 0.5f) + halfLevelSelectorHeight;
mEngine.getTextureManager();
}
/**
* Create the level tiles with a customized ITextureRegion representation as
* well as a customized Font.
*
* #param pTextureRegion
* The ITextureRegion to supply each of the level tiles.
* #param pFont
* The Font to be displayed by Text written on the tiles,
* specifying tile level number for example.
*/
public void createTiles(final ITextureRegion pTextureRegion,
final org.andengine.opengl.font.Font pFont) {
/* Temp coordinates for placing level tiles */
float tempX = this.mInitialX + TILE_DIMENSION * 0.5f;
float tempY = this.mInitialY - TILE_DIMENSION * 0.5f;
/* Current level of the tile to be placed */
int currentTileLevel = 1;
/*
* Loop through the Rows, adjusting tempY coordinate after each
* iteration
*/
for (int i = 0; i < ROWS; i++) {
/*
* Loop through the column positions, placing a LevelTile in each
* column
*/
for (int o = 0; o < COLUMNS; o++) {
final boolean locked;
/* Determine whether the current tile is locked or not */
if (currentTileLevel <= mMaxLevel) {
locked = false;
} else {
locked = true;
}
/* Create a level tile */
LevelTile levelTile = new LevelTile(tempX, tempY, locked,
currentTileLevel, pTextureRegion, pFont);
/*
* Attach the level tile's text based on the locked and
* currentTileLevel variables pass to its constructor
*/
levelTile.attachText();
/* Register & Attach the levelTile object to the LevelSelector */
mScene.registerTouchArea(levelTile);
this.attachChild(levelTile);
/* Increment the tempX coordinate to the next column */
tempX = tempX + TILE_DIMENSION + TILE_PADDING;
/* Increment the level tile count */
currentTileLevel++;
}
/* Reposition the tempX coordinate back to the first row (far left) */
tempX = mInitialX + TILE_DIMENSION * 0.5f;
/* Reposition the tempY coordinate for the next row to apply tiles */
tempY = tempY - TILE_DIMENSION - TILE_PADDING;
}
}
/**
* Display the LevelSelector on the Scene.
*/
public void show() {
/* Register as non-hidden, allowing touch events */
mHidden = false;
/* Attach the LevelSelector the the Scene if it currently has no parent */
if (!this.hasParent()) {
mScene.attachChild(this);
}
/* Set the LevelSelector to visible */
this.setVisible(true);
}
/**
* Hide the LevelSelector on the Scene.
*/
public void hide() {
/* Register as hidden, disallowing touch events */
mHidden = true;
/* Remove the LevelSelector from view */
this.setVisible(false);
}
public class LevelTile extends Sprite {
/*
* The LevelTile should keep track of level number and lock status. Feel
* free to add additional data within level tiles
*/
private final boolean mIsLocked;
private final int mLevelNumber;
private final org.andengine.opengl.font.Font mFont;
private Text mTileText;
/*
* Each level tile will be sized according to the constant
* TILE_DIMENSION within the LevelSelector class
*/
public LevelTile(float pX, float pY, boolean pIsLocked,
int pLevelNumber, ITextureRegion pTextureRegion, org.andengine.opengl.font.Font pFont) {
super(pX, pY, LevelSelector.this.TILE_DIMENSION,
LevelSelector.this.TILE_DIMENSION, pTextureRegion,
LevelSelector.this.mEngine.getVertexBufferObjectManager());
/* Initialize the necessary variables for the LevelTile */
this.mFont = pFont;
this.mIsLocked = pIsLocked;
this.mLevelNumber = pLevelNumber;
}
/* Method used to obtain whether or not this level tile represents a
* level which is currently locked */
public boolean isLocked() {
return this.mIsLocked;
}
/* Method used to obtain this specific level tiles level number */
public int getLevelNumber() {
return this.mLevelNumber;
}
/*
* Attach the LevelTile's text to itself based on whether it's locked or
* not. If not, then the level number will be displayed on the level
* tile.
*/
public void attachText() {
String tileTextString = null;
/* If the tile's text is currently null... */
if (this.mTileText == null) {
/*
* Determine the tile's string based on whether it's locked or
* not
*/
if (this.mIsLocked) {
tileTextString = "Locked";
} else {
tileTextString = String.valueOf(this.mLevelNumber);
}
/* Setup the text position to be placed in the center of the tile */
final float textPositionX = LevelSelector.this.TILE_DIMENSION * 0.5f;
final float textPositionY = textPositionX;
/* Create the tile's text in the center of the tile */
this.mTileText = new Text( textPositionX,
textPositionY, this.mFont,
tileTextString, tileTextString.length(),
LevelSelector.this.mEngine
.getVertexBufferObjectManager());
/* Attach the Text to the LevelTile */
this.attachChild(mTileText);
}
}
#Override
public boolean onAreaTouched(TouchEvent pSceneTouchEvent,
float pTouchAreaLocalX, float pTouchAreaLocalY) {
/* If the LevelSelector is not hidden, proceed to execute the touch
* event */
if (!LevelSelector.this.mHidden) {
/* If a level tile is initially pressed down on */
if (pSceneTouchEvent.isActionDown()) {
/* If this level tile is locked... */
if (this.mIsLocked) {
/* Tile Locked event... */
LevelSelector.this.mScene.getBackground().setColor(
org.andengine.util.color.Color.RED);
} else {
/* Tile unlocked event... This event would likely prompt
* level loading but without getting too complicated we
* will simply set the Scene's background color to green */
LevelSelector.this.mScene.getBackground().setColor(
org.andengine.util.color.Color.GREEN);
/**
* Example level loading:
* LevelSelector.this.hide();
* SceneManager.loadLevel(this.mLevelNumber);
*/
}
return true;
}
}
return super.onAreaTouched(pSceneTouchEvent, pTouchAreaLocalX,
pTouchAreaLocalY);
}
}
}
FYI, this code belongs to code bundle in Android game development using AndEngine cookbook.
I have edited few variables like font and engine , but i have't changed the logic or flow of program.
Now when I run this I get the below screen
Alright i solved my problem, its was the padding i was using, it should't be there.
try {
mBitmapTextureAtlas.build(new BlackPawnTextureAtlasBuilder<IBitmapTextureAtlasSource, BitmapTextureAtlas>(0, 1, 1));
mBitmapTextureAtlas.load();
} catch (TextureAtlasBuilderException e) {
Log.e("", ""+e);
}
it should be
try {
mBitmapTextureAtlas.build(new BlackPawnTextureAtlasBuilder<IBitmapTextureAtlasSource, BitmapTextureAtlas>(0, 0, 0));
mBitmapTextureAtlas.load();
} catch (TextureAtlasBuilderException e) {
Log.e("", ""+e);
}
I'm currently facing an issue with my android game. Normally when calling SoundPool.play() the function needs about 0.003 seconds to finish, but sometimes it takes 0.2 seconds which makes my game stutter. where could his anomaly come from?
thanks to Tim, using a Thread for playing seemed to workaround the problem successfully.
Thread
package org.racenet.racesow.threads;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import org.racenet.racesow.models.SoundItem;
import android.media.SoundPool;
/**
* Thread for playing sounds
*
* #author soh#zolex
*
*/
public class SoundThread extends Thread {
private SoundPool soundPool;
public BlockingQueue<SoundItem> sounds = new LinkedBlockingQueue<SoundItem>();
public boolean stop = false;
/**
* Constructor
*
* #param soundPool
*/
public SoundThread(SoundPool soundPool) {
this.soundPool = soundPool;
}
/**
* Dispose a sound
*
* #param soundID
*/
public void unloadSound(int soundID) {
this.soundPool.unload(soundID);
}
#Override
/**
* Wait for sounds to play
*/
public void run() {
try {
SoundItem item;
while (!this.stop) {
item = this.sounds.take();
if (item.stop) {
this.stop = true;
break;
}
this.soundPool.play(item.soundID, item.volume, item.volume, 0, 0, 1);
}
} catch (InterruptedException e) {}
}
}
SoundItem
package org.racenet.racesow.models;
/**
* SoundItem will be passed to the SoundThread which
* will handle the playing of sounds
*
* #author soh#zolex
*
*/
public class SoundItem {
public int soundID;
public float volume;
public boolean stop = false;
/**
* Default constructor
*
* #param soundID
* #param volume
*/
public SoundItem(int soundID, float volume) {
this.soundID = soundID;
this.volume = volume;
}
/**
* Constructor for the item
* which will kill the thread
*
* #param stop
*/
public SoundItem(boolean stop) {
this.stop = stop;
}
}
what im trying to do is when someone hold there finger down on the screen forward equals true but when they take it off it equals false
so i tryed using the get_actions() methods
but only the action_down gets called
heres my code
public class zombView extends SurfaceView{
private Bitmap bmp, grass, joystick;
private SurfaceHolder holder;
Timer t = new Timer();
float x = 0, y = 0;
boolean forward;
public zombView(Context context) {
super(context);
holder = getHolder();
holder.addCallback(new SurfaceHolder.Callback() {
#Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
#Override
public void surfaceCreated(final SurfaceHolder holder) {
t.scheduleAtFixedRate(new TimerTask(){
public void run(){
Canvas c = holder.lockCanvas(null);
onDraw(c);
holder.unlockCanvasAndPost(c);
if(forward){
x = x + 5;
}
onTouchEvent(null);
}
},200,100);
}
#Override
public void surfaceChanged(SurfaceHolder holder, int format,
int width, int height) {
}
});
bmp = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
grass = BitmapFactory.decodeResource(getResources(), R.drawable.grassland);
joystick = BitmapFactory.decodeResource(getResources(), R.drawable.joystic);
}
#Override
protected void onDraw(Canvas canvas) {
canvas.drawColor(Color.BLACK);
canvas.drawBitmap(grass, getWidth() - getWidth(), getHeight() - getHeight(), null);
canvas.drawBitmap(joystick, getWidth() - getWidth(),joystick.getHeight(), null);
canvas.drawBitmap(bmp, x, y, null);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
/*switch (event.getAction() & MotionEvent.ACTION_MASK) {
case MotionEvent.ACTION_DOWN: forward = true;
case MotionEvent.ACTION_POINTER_DOWN: forward = true;
case MotionEvent.ACTION_UP: forward = false;
case MotionEvent.ACTION_POINTER_UP:forward = false;
case MotionEvent.ACTION_MOVE: forward = true;
}*/
if(event.getAction()== MotionEvent.ACTION_DOWN){
forward = true;
}if(event.getAction()== MotionEvent.ACTION_UP){
forward = false;
}
return super.onTouchEvent(event);
}
}
The layout containing this SurfaceView is not passing event to this SurfaceView. What you need to do is override ontouch menthod and return false in that. I hope this would be helpful.
use this
case MotionEvent.ACTION_DOWN:
touch_start(x, y);
invalidate();
break;
case MotionEvent.ACTION_MOVE:
touch_move(x, y);
invalidate();
break;
case MotionEvent.ACTION_UP:
touch_up();
invalidate();
break;
}
Timer in UI is unsafe. I could propose a class of my own purposed to keep some times and dates, showing themselves in some views.
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import android.os.Handler;
import android.widget.TextView;
/**
* The class for creating and refreshing many different fields on different layouts,
* that can hold actual time and/or date in different formats
* The formats should be as in http://developer.android.com/reference/java/text/SimpleDateFormat.html.
* Only present and visible fields are being actualized, so there is no need to clean the clock list after closing an activity
*
* Examples of use:
*
* Clock.registerClock((TextView) findViewById(R.id.TimeField), "HH:mm");
* Clock.registerClock((TextView) findViewById(R.id.DateField), "d.M.yyyy EEE");
* Clock.start(10000L);
*
* #author Petr Gangnus
*/
public final class Clock {
/**
* the handler that works instead of timer and supports UI
*/
static private Handler handler = new Handler();
/**
* the interval of the time refreshing
*/
static private long refreshStep;
/**
* pairs TextView timer+time/date format
*/
private TextView clockFace;
private String format;
private Clock(TextView clockFace, String format){
this.clockFace=clockFace;
this.format=format;
}
// here is the list of views containing the visual timers that should be held actual
static private ArrayList<Clock> clocks=new ArrayList<Clock>();
/**
* fills all timer fields by actual time value, according to their formats.
*/
static private Runnable mUpdateTimeTask = new Runnable() {
public void run() {
for(Clock clock:clocks){
showActualTimeDate(clock);
}
handler.postDelayed(this,refreshStep);
}
};
//============================================ public members ====================================================================
/**
* add a clock to the list of updating clocks
* #param clockFace - the place where the time or date will be shown
* #param format - the format of the time/date
* #return
*/
public static boolean registerClock(TextView clockFace, String format){
if (clockFace==null) return false;
if(clocks.contains(clockFace)){
// old clockFace
clocks.get(clocks.indexOf(clockFace)).format=format;
} else {
// new clockFace
clocks.add(new Clock(clockFace, format));
}
return true;
}
/**
* remove a clock from the updating list
* #param clockFace
* #return
*/
public static boolean unRegisterClock(TextView clockFace){
if (clockFace==null) return false;
if(clocks.contains(clockFace)){
// found clockFace
clocks.remove(clocks.indexOf(clockFace));
} else {
// not found clockFace
return false;
}
return true;
}
/**
* put in the "place" the actual date/time in the appropriate "format"
* #param place
* #param format
*/
public static void showActualTimeDate(Clock clock){
if (clock.clockFace==null) return;
if (clock.clockFace.getVisibility()!=TextView.VISIBLE) return;
Date thisDate=new Date();
SimpleDateFormat df=new SimpleDateFormat(clock.format);
clock.clockFace.setText(df.format(thisDate));
}
/**
* start the ticking for all clocks
* #param step the tick interval
*/
public static void start(long step) {
refreshStep=step;
handler.removeCallbacks(mUpdateTimeTask);
handler.postDelayed(mUpdateTimeTask, 0);
}
/**
* Stopping ticking all clocks (not removing them)
* the calling could be put somewhere in onStop
*/
public static void stop() {
handler.removeCallbacks(mUpdateTimeTask);
}
}