Проблемы с ограничивающими рамками в Cocos2d-X

Я пытаюсь заставить свою ограничивающую рамку работать должным образом, но продолжаю терпеть неудачу, когда Карта масштабируется. Я мог бы действительно использовать некоторую помощь здесь, поскольку это было проклятием моего существования.

В двух словах, у меня есть 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();
}

1

Решение

Вы можете рассчитать точную ограничительной рамки в соответствии с положением в родительском узле, масштаба и точки привязки. Вы можете сделать что-то вроде этого:

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};
1

Другие решения

Других решений пока нет …