Applying Zoom Effect In cocos2D gaming environment?

rptwsthi picture rptwsthi · May 7, 2011 · Viewed 11.1k times · Source

I'm working on a game with cocos2D game engine and make load all the sprites while it load the level, now as because some of sprites (obstacles) are taller than 320 pixel, thus it seems difficult to check them out. So for the convenience sake I want to apply ZOOM IN and ZOOM out effect, which minimizes entire level's all sprites at once, and in zoom out case these will resided to there old position.

Can I achieve this?

If yes, then how?

Please tell about pinch zoom also.

Answer

Michael Fredrickson picture Michael Fredrickson · May 7, 2011

Zooming, is fairly simple, simply set the scale property of your main game layer... but there are a few catches.

When you scale the layer, it will shift the position of the layer. It won't automatically zoom towards the center of what you're currently looking at. If you have any type of scrolling in your game, you'll need to account for this.

To do this, set the anchorPoint of your layer to ccp(0.0f, 0.0f), and then calculate how much your layer has shifted, and reposition it accordingly.

- (void) scale:(CGFloat) newScale scaleCenter:(CGPoint) scaleCenter {
    // scaleCenter is the point to zoom to.. 
    // If you are doing a pinch zoom, this should be the center of your pinch.

    // Get the original center point.
    CGPoint oldCenterPoint = ccp(scaleCenter.x * yourLayer.scale, scaleCenter.y * yourLayer.scale); 

    // Set the scale.
    yourLayer.scale = newScale;

    // Get the new center point.
    CGPoint newCenterPoint = ccp(scaleCenter.x * yourLayer.scale, scaleCenter.y * yourLayer.scale); 

    // Then calculate the delta.
    CGPoint centerPointDelta  = ccpSub(oldCenterPoint, newCenterPoint);

    // Now adjust your layer by the delta.
    yourLayer.position = ccpAdd(yourLayer.position, centerPointDelta);
}

Pinch zoom is easier... just detect the touchesMoved, and then call your scaling routine.

- (void) ccTouchesMoved:(NSSet*)touches withEvent:(UIEvent*)event {

    // Examine allTouches instead of just touches.  Touches tracks only the touch that is currently moving...
    //   But stationary touches still trigger a multi-touch gesture.
    NSArray* allTouches = [[event allTouches] allObjects];

    if ([allTouches count] == 2) {            
        // Get two of the touches to handle the zoom
        UITouch* touchOne = [allTouches objectAtIndex:0];
        UITouch* touchTwo = [allTouches objectAtIndex:1];

        // Get the touches and previous touches.
        CGPoint touchLocationOne = [touchOne locationInView: [touchOne view]];
        CGPoint touchLocationTwo = [touchTwo locationInView: [touchTwo view]];  

        CGPoint previousLocationOne = [touchOne previousLocationInView: [touchOne view]];
        CGPoint previousLocationTwo = [touchTwo previousLocationInView: [touchTwo view]];

        // Get the distance for the current and previous touches.
        CGFloat currentDistance = sqrt(
                                       pow(touchLocationOne.x - touchLocationTwo.x, 2.0f) + 
                                       pow(touchLocationOne.y - touchLocationTwo.y, 2.0f));

        CGFloat previousDistance = sqrt(
                                        pow(previousLocationOne.x - previousLocationTwo.x, 2.0f) + 
                                        pow(previousLocationOne.y - previousLocationTwo.y, 2.0f));

        // Get the delta of the distances.
        CGFloat distanceDelta = currentDistance - previousDistance;

        // Next, position the camera to the middle of the pinch.
        // Get the middle position of the pinch.
        CGPoint pinchCenter = ccpMidpoint(touchLocationOne, touchLocationTwo);

        // Then, convert the screen position to node space... use your game layer to do this.
        pinchCenter = [yourLayer convertToNodeSpace:pinchCenter];

        // Finally, call the scale method to scale by the distanceDelta, pass in the pinch center as well.
        // Also, multiply the delta by PINCH_ZOOM_MULTIPLIER to slow down the scale speed.      
        // A PINCH_ZOOM_MULTIPLIER of 0.005f works for me, but experiment to find one that you like.
        [self scale:yourlayer.scale - (distanceDelta * PINCH_ZOOM_MULTIPLIER)
            scaleCenter:pinchCenter];
    }    
}