PLEASE ASSIST! Bounding Box Issues


#1

Hello,
I am trying to get my bounding box to work properly, but keep failing when the Map gets scaled. I could really use some assistance here as this has been the bane of my existence.

In a nutshell, I have 1 scene, 2 layers. One layer is a HUD and another is a map. The map is a layer that is rendered by tiling 100 images from a large sliced image. I scale these images to the given spacial scaling and they look great at all sizes. The problem occurs when I try to set a bounding box for the Width/Height of the Map while scaled. I am unable to get it to lock properly (Only right boundary and top boundary, left and bottom work fine). As an FYI, this will work beautifully when Scale is equal to 1, but as soon as I scale, everything gets awkward, most likely due to the changing X,Y of the Map Tiles when I scale the Sprite.

Please help as I don’t know what I am doing wrong and cannot wrap my head around the spaces… Here is some code to help:

bool MapLayer::init()
{
    // Super init
    if ( !CCLayer::init() )
    {
        return false;
    }

    // We need to enable touches for this layer
    setTouchEnabled( true );

    // Set the Anchor Point
    setAnchorPoint(ccp(0,0));

    // We need to initialize the Map Textures for Rendering (Break up further for performance)
    for(int row = 0; row < NUM_MAP_FRAME_ROWS; row++)
    {
        for(int col = 0; col < NUM_MAP_FRAME_COLS; col++)
        {
            char imageFrameFile[25] = "";
            int imageFrame = ((row * 10) + col) + 1;

            // Create the String to load the image frame
            sprintf(imageFrameFile, "map_%02d.png", imageFrame);

            // Create the Sprite
            map[row][col] = CCSprite::create(imageFrameFile);

            // Add the Sprite to the Scene
            this->addChild(map[row][col], 0);
        }
    }

    // Render the Map at the default Scale (Show entire Map)
    renderMap();

    // Position the Viewport to the center of the map
    setPosition(ccp(0 - (((map[9][9]->getPosition().x + map[9][9]->getContentSize().width) / 2.0f) - ((map[9][9]->getContentSize().width / 2.0f))),
                    0 - ((map[0][0]->getPosition().y / 2.0f) - ((map[0][0]->getContentSize().height / 2.0f)))));

    return true;
}
@



void MapLayer::renderMap(void)
{
    int overlapBuffer = 0;
    float spritePositionX = 0.0f;
    float spritePositionY = 0.0f;

    // Reset our Boundary variables
    rightBoundary = 0;
    topBoundary = 0;

    // Display the Tile-based Map
    for(int row = NUM_MAP_FRAME_ROWS - 1; row >= 0; row--)
    {
        // Reset the starting position
        spritePositionX = 0.0f;

        for(int col = 0; col < NUM_MAP_FRAME_COLS; col++)
        {
            CCSprite * pSprite = map[row][col];
            CCSize spriteContentSize = pSprite->getContentSize();
            float spriteWidth = spriteContentSize.width;
            float spriteHeight = spriteContentSize.height;

            // Position the Sprite by using the previous Sprite's location
            pSprite->setScale(getScale());
            pSprite->setAnchorPoint(ccp(0, 0));
            pSprite->setPosition(ccp(spritePositionX, spritePositionY));

            // Increment for the next Sprite Position
            spritePositionX += (float)(spriteWidth * pSprite->getScale()) - overlapBuffer;

            // Increment if this is the last column item
            if(col == (NUM_MAP_FRAME_COLS - 1))
            {
                // Increment for the next Sprite Position
                spritePositionY += (float)(spriteHeight * pSprite->getScale()) - overlapBuffer;
            }
        }
    }





    // TEST CODE
    CCPoint boundaries = convertToWorldSpace(ccp(spritePositionX, spritePositionY));
    rightBoundary = boundaries.x;
    topBoundary = boundaries.y;
    // TEST CODE
}












void MapLayer::scale(float newScale, CCPoint 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.
    CCPoint oldCenterPoint = ccp(scaleCenter.x * getScale(), scaleCenter.y * getScale());

    // Set the scale.
    setScale(newScale);

    // Get the new center point.
    CCPoint newCenterPoint = ccp(scaleCenter.x * getScale(), scaleCenter.y * getScale());

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

    // Now adjust your layer by the delta.
    setPosition(ccpAdd(getPosition(), centerPointDelta));

    // Render the Map to the new Scale
    renderMap();
}







void MapLayer::checkBoundingBox(void)
{
    // Grab the display size from the director
    CCSize winSize = CCDirector::sharedDirector()->getWinSize();






    cocos2d::CCLog("************************************");
    cocos2d::CCLog("WORLD Position-X: %f", convertToWorldSpace(getPosition()).x);
    cocos2d::CCLog("WORLD Position-Y: %f", convertToWorldSpace(getPosition()).y);

    cocos2d::CCLog("Position-X: %f", (getPosition()).x);
    cocos2d::CCLog("Position-Y: %f", (getPosition()).y);

//    cocos2d::CCLog("Map[0][0]-X: %f", convertToWorldSpace(map[0][0]->getPosition()).x);
//    cocos2d::CCLog("Map[0][0]-Y: %f", convertToWorldSpace(map[0][0]->getPosition()).y);
//    cocos2d::CCLog("Map[9][9]-X: %f", convertToWorldSpace(map[9][9]->getPosition()).x);
//    cocos2d::CCLog("Map[9][9]-Y: %f", convertToWorldSpace(map[9][9]->getPosition()).y);
    cocos2d::CCLog("WinSize Width: %f", winSize.width);
    cocos2d::CCLog("WinSize Height: %f", winSize.height);


    /*
     * Check if we have scaled beyond our limits
     */
    // Check the Width
    if(getPositionX() >= 0)
    {        
        // Set the Position
        setPositionX(0);
    }

    // Check the Height
    if(getPositionY() >= 0)
    {        
        // Set the Position
        setPositionY(0);
    }




    setPosition(ccpClamp(getPosition(),
                         ccp(-(rightBoundary - winSize.width),
                             -(topBoundary - winSize.height)),
                         ccp(0,0)));         
}








void MapLayer::ccTouchesMoved( CCSet *pTouches, CCEvent *pEvent )
{
    // Verify that we are Panning the Map
    if(pTouches->count() == 1)
    {
        // Grab the touch to handle the pan
        CCTouch * panTouch = (CCTouch *)pTouches->anyObject();

        // Get the touch and previous touch
        CCPoint touchLocation = panTouch->getLocationInView();
        CCPoint previousLocation = panTouch->getPreviousLocationInView();

        // Get the distance for the current and previous touches.
        float currentDistanceX = touchLocation.x - previousLocation.x;
        float currentDistanceY = touchLocation.y - previousLocation.y;

        // Set new position of the layer
        setPosition(ccp(getPosition().x + currentDistanceX, getPosition().y - currentDistanceY));
    }

    // Verify that we are Zooming the Map
    else if (pTouches->count() == 2)
    {
        // Grab Touch One
        CCTouch * touchOne = (CCTouch *)pTouches->anyObject();

        // Don't grab the same Touch
        pTouches->removeObject(touchOne);

        // Grab Touch Two
        CCTouch * touchTwo = (CCTouch *)pTouches->anyObject();

        // Get the touches and previous touches.
        CCPoint touchLocationOne = touchOne->getLocationInView();
        CCPoint touchLocationTwo = touchTwo->getLocationInView();

        CCPoint previousLocationOne = touchOne->getPreviousLocationInView();
        CCPoint previousLocationTwo = touchTwo->getPreviousLocationInView();

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

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

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

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

        // Then, convert the screen position to node space... use your game layer to do this.
        pinchCenter = 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.
        scale(getScale() + (distanceDelta * PINCH_ZOOM_MULTIPLIER), pinchCenter);
    }

    /*
     * Verify that the new position is within our bounding box, otherwise lock it
     */
    checkBoundingBox();
}