0
\$\begingroup\$

I'm trying to implement a pinch zoom on a sprite. I would like to get an effect like the SmoothCamera, but on a single sprite. I've managed to pinch zoom on the sprite by changing its scale, but the zoom is really fast and not smooth... it doesn't feel right.

This code is on my sprite :

public class BoardSprite extends Sprite implements IPinchZoomDetectorListener {
...
private float scale = 1;
    @Override
    public void onPinchZoom(PinchZoomDetector pPinchZoomDetector,
            TouchEvent pTouchEvent, float pZoomFactor) {
        float newScale = scale * pZoomFactor;
        if (newScale > 3) {
            newScale = 3;
        } else if ( newScale < 1) {
            newScale = 1;
        } 

        scale = newScale;
        this.setScale(newScale);        
    }

I'm looking for a way to improve this solution or for a better approach.

\$\endgroup\$
  • \$\begingroup\$ Just curious: what if you tried float newScale = pZoomFactor; -- what effect would that produce? \$\endgroup\$ – Thomas Jan 20 '14 at 13:54
  • \$\begingroup\$ That's actually pretty good, the only problem is that it seems to start back to 1 each time I start a new pinch. I'll have a look at it later today. \$\endgroup\$ – Phil-R Jan 21 '14 at 14:14
2
\$\begingroup\$

I have no experience with AndEngine, but from your code I suspect that since you update the scale variable with the result of scale * pZoomFactor every time onPinchZoom is called, you're basically turning this multiplication into an exponentiation.

To avoid this, simply delete the scale = newScale; assignment. But now, since you want to compute the scale relative to the scale at the beginning of the pinch zoom, you have to add a method that initializes scale to that value. The following might work:

private float scale = 1;

@Override
public void onPinchZoomStarted(PinchZoomDetector pPinchZoomDetector, 
                               TouchEvent pSceneTouchEvent) {
    this.scale = Math.min(getScaleX(), getScaleY());
}

@Override
public void onPinchZoom(PinchZoomDetector pPinchZoomDetector,
                        TouchEvent pTouchEvent, float pZoomFactor) {
    float newScale = scale * pZoomFactor;
    if (newScale > 3) {
        newScale = 3;
    } else if (newScale < 1) {
        newScale = 1;
    } 

    // scale = newScale;
    this.setScale(newScale);        
}
\$\endgroup\$
1
\$\begingroup\$

Try setting a target scale, then ease towards that value, rather than setting the value directly. This is how the pinch zoom works in Angry Birds. It eases in over time.

The basic method is to increase the scale of your sprite by a fraction of the difference between the target scale and the current scale each update.

so in your onManagedUpdate(pUpdateSeconds) you'll add soemthing like this (writing from memory, code not tested)

float easeRate = 0.01; // Higher for faster easing;

float newscale = this.getScale() + (targetScale - this.getScale()) * easeRate * pUpdateSeconds/1000;

this.setScale(newscale);
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.