AndEngine – Smooth scaling on a sprite

| | August 18, 2015

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.

2 Responses to “AndEngine – Smooth scaling on a sprite”

  1. Plastic Sturgeon on November 30, -0001 @ 12:00 AM

    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);
    
  2. 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);        
    }
    

Leave a Reply