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 ?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With