Cocos2d-X的边界框问题

Bounding Box Issues with Cocos2d-X

本文关键字:问题 边界 Cocos2d-X      更新时间:2023-10-16

我试图让我的边界框正常工作,但当Map被缩放时,总是失败。我真的需要一些帮助,因为这一直是我生存的祸根。

简而言之,我有1个场景,2层。一层是HUD,另一层是地图。贴图是通过从大的切片图像平铺100个图像来渲染的层。我将这些图像缩放到给定的空间比例,它们在所有尺寸上都看起来很棒。当我尝试在缩放时为贴图的"宽度/高度"设置边界框时,就会出现问题。我无法将其正确锁定(只有右边界和上边界,左边界和下边界可以正常工作)。仅供参考,当"比例"等于1时,这将非常有效,但一旦缩放,一切都会变得尴尬,很可能是由于缩放精灵时贴图平铺的X、Y发生变化。

请帮帮我,因为我不知道自己做错了什么,也无法理解空间。。。这里有一些代码可以帮助:

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();
}

您可以计算相对于父节点中的位置、比例和锚点的精确边界框。你可以这样做:

CCSize size = CCSizeMake(node.width * node.scaleX, node.height * node.scaleY);
CCPoint origin = ccp(node.position.x - (size.width * node.anchorPoint.x), node.position.y - (size.height * node.anchorPoint.y));
CCRect boundingBox = (CCRect){origin, size};