Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

andengine smooth scrolling and zooming with SurfaceScrollDetector, PinchZoomDetector

I'm trying to implement smooth TMX map scrolling and zooming with SurfaceScrollDetector and PinchZoomDetector.

Here is my code:

public class TMXTiledMapExample extends SimpleBaseGameActivity implements IOnSceneTouchListener, IScrollDetectorListener, IPinchZoomDetectorListener {

private static final int CAMERA_WIDTH = 480;
private static final int CAMERA_HEIGHT = 320;

private SmoothCamera camera;

private TMXTiledMap mTMXTiledMap;

private SurfaceScrollDetector mScrollDetector;
private PinchZoomDetector mPinchZoomDetector;
private float mPinchZoomStartedCameraZoomFactor;

@Override
public EngineOptions onCreateEngineOptions() {
    this.camera = new SmoothCamera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT, 400, 400, 10f);
    final CroppedResolutionPolicy canvasSurface = new CroppedResolutionPolicy(CAMERA_WIDTH, CAMERA_HEIGHT);
    EngineOptions engineOptions = new EngineOptions(true, ScreenOrientation.LANDSCAPE_FIXED, canvasSurface, this.camera);

    if (MultiTouch.isSupported(this)) {
        if (MultiTouch.isSupportedDistinct(this)) {
            Toast.makeText(this, "MultiTouch detected --> Both controls will work properly!", Toast.LENGTH_SHORT).show();
        } else {
            Toast.makeText(this, "MultiTouch detected, but your device has problems distinguishing between fingers.\n\nControls are placed at different vertical locations.", Toast.LENGTH_LONG)
                    .show();
        }
    } else {
        Toast.makeText(this, "Sorry your device does NOT support MultiTouch!\n\n(Falling back to SingleTouch.)\n\nControls are placed at different vertical locations.", Toast.LENGTH_LONG).show();
    }

    return engineOptions;
}

@Override
public void onCreateResources() {
    BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
}

@Override
public Scene onCreateScene() {
    this.mEngine.registerUpdateHandler(new FPSLogger());

    final Scene scene = new Scene();
    scene.setOnAreaTouchTraversalFrontToBack();

    this.mScrollDetector = new SurfaceScrollDetector(this);
    this.mPinchZoomDetector = new PinchZoomDetector(this);

    scene.setOnSceneTouchListener(this);
    scene.setTouchAreaBindingOnActionDownEnabled(true);

    try {
        final TMXLoader tmxLoader = new TMXLoader(this.getAssets(), this.mEngine.getTextureManager(), TextureOptions.BILINEAR, this.getVertexBufferObjectManager(),
                new ITMXTilePropertiesListener() {
                    @Override
                    public void onTMXTileWithPropertiesCreated(final TMXTiledMap pTMXTiledMap, final TMXLayer pTMXLayer, final TMXTile pTMXTile,
                            final TMXProperties<TMXTileProperty> pTMXTileProperties) {
                    }
                });
        this.mTMXTiledMap = tmxLoader.loadFromAsset("tmx/desert2.tmx");

    } catch (final TMXLoadException e) {
        Debug.e(e);
    }

    final TMXLayer tmxLayer = this.mTMXTiledMap.getTMXLayers().get(0);
    scene.attachChild(tmxLayer);

    this.camera.setBounds(0, 0, tmxLayer.getHeight(), tmxLayer.getWidth());
    this.camera.setBoundsEnabled(true);

    return scene;
}

@Override
public void onScrollStarted(final ScrollDetector pScollDetector, final int pPointerID, final float pDistanceX, final float pDistanceY) {
    final float zoomFactor = this.camera.getZoomFactor();
    this.camera.offsetCenter(-pDistanceX / zoomFactor, -pDistanceY / zoomFactor);
}

@Override
public void onScroll(final ScrollDetector pScollDetector, final int pPointerID, final float pDistanceX, final float pDistanceY) {
    final float zoomFactor = this.camera.getZoomFactor();
    this.camera.offsetCenter(-pDistanceX / zoomFactor, -pDistanceY / zoomFactor);
}

@Override
public void onScrollFinished(final ScrollDetector pScollDetector, final int pPointerID, final float pDistanceX, final float pDistanceY) {
    final float zoomFactor = this.camera.getZoomFactor();
    this.camera.offsetCenter(-pDistanceX / zoomFactor, -pDistanceY / zoomFactor);
}

@Override
public void onPinchZoomStarted(final PinchZoomDetector pPinchZoomDetector, final TouchEvent pTouchEvent) {
    this.mPinchZoomStartedCameraZoomFactor = this.camera.getZoomFactor();
}

@Override
public void onPinchZoom(final PinchZoomDetector pPinchZoomDetector, final TouchEvent pTouchEvent, final float pZoomFactor) {
    this.camera.setZoomFactor(this.mPinchZoomStartedCameraZoomFactor * pZoomFactor);
}

@Override
public void onPinchZoomFinished(final PinchZoomDetector pPinchZoomDetector, final TouchEvent pTouchEvent, final float pZoomFactor) {
    this.camera.setZoomFactor(this.mPinchZoomStartedCameraZoomFactor * pZoomFactor);
}

@Override
public boolean onSceneTouchEvent(final Scene pScene, final TouchEvent pSceneTouchEvent) {
    this.mPinchZoomDetector.onTouchEvent(pSceneTouchEvent);

    if (this.mPinchZoomDetector.isZooming()) {
        this.mScrollDetector.setEnabled(false);
    } else {
        if (pSceneTouchEvent.isActionDown()) {
            this.mScrollDetector.setEnabled(true);
        }
        this.mScrollDetector.onTouchEvent(pSceneTouchEvent);
    }

    return true;
}
}

Scrolling and zooming in this code are not very smooth. Where is the issue with it ? How to create nice, inertial scrolling ?

One more question for zooming. How it could be restricted with min and max zoomfactor ? Should I place a special conditions into the IPinchZoomDetectorListener methods or it could be achived with some parameters provided to my camera object ?

Also, what is a "normal" values for the three last SmoothCamera parameters - final float pMaxVelocityX, final float pMaxVelocityY, final float pMaxZoomFactorChange ?

like image 958
alexanoid Avatar asked Nov 30 '25 15:11

alexanoid


1 Answers

I have done similar type of work before so I can help you in achieving your objective.

First of all if you want zoom in/out functionality then you have to use ZoomCamera in which you have to only give width and height, all other parameters are used by default value.

    mZoomCamera = new ZoomCamera(0, 0, Constants.CAMERA_WIDTH,
            Constants.CAMERA_HEIGHT);
    mZoomCamera.setBounds(0f, 0f, Constants.CAMERA_WIDTH,
            Constants.CAMERA_HEIGHT);
    mZoomCamera.setBoundsEnabled(true);

In the example code, you see how I set bounds for camera so there is no chance camera can go out of this. And also I thing you get abnormal behaviour because of inappropriate velocity you are providing.

For for setting specific zoom value you can use following code,

private void setCameraZoomFactor(float pZoomFactor) {
    newZoomFactor = mPinchZoomStartedCameraZoomFactor * pZoomFactor;
    if (newZoomFactor < 1f)
        newZoomFactor = 1f;
    if (newZoomFactor > 1.5f)
        newZoomFactor = 1.5f;

    mZoomCamera.setZoomFactor(newZoomFactor);
}

You have to call this method in your onPinchZoom method.

I think now I have given answer of your all of the questions.

like image 53
Siddharth Avatar answered Dec 02 '25 03:12

Siddharth



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!