Error with setAnchorPoint in CCLayer

  • in CCLayer.cpp,line 42 + 43:

    setAnchorPoint(ccp(0.5f, 0.5f)); (*)
    m_bIsRelativeAnchorPoint = false;

although you set m_bIsRelativeAnchorPoint = false, there are something wrong with layer anchor point.
see my simple example:

CCLayer* testLayer = CCLayer::node();
CCSize size = CCDirector::sharedDirector()->getWinSize();
testLayer->setScale(0.5);
CCSprite* star1 = CCSprite::spriteWithFile("star.png");
CCSprite* star2 = CCSprite::spriteWithFile("star.png");
star1->setPosition(ccp(size.width,100));
star2->setPosition(ccp(0,100));
testLayer->addChild(star1);
testLayer->addChild(star2);
addChild(testLayer);

add this code to helloworld::init(). And you can see,star1 and star2 not appear in the position you want.
But if you remove line ( * ) , everything will correct.
So because you set AnchorPoint for Layer, if you set Scale for Layer ( I need to scale all my object on this Layer), all of your object position will wrong.
In my Project I remove line (*), don’t set AnchorPoint for CCLayer. Till now,I don’t see anything wrong.
Maybe you need fix it.

Sorry,but can you check it out? I am afraid that it was my fault.

please fix this in next version, it caused weird problems before reading this post!
thanks

cocos2d-iphone also initialize anchor point in CCLayer.
What’s the problem?

hello Minggo,
In short I’m currently working on a project, porting my app from iOS to Android. There is a tactical map function in my app, it zooms out the terrain by modifying scale property of the main game layer. There is no camera operation (seteye etc.) To keep the original center point centered after the scale operation, there is a moveby action parallel to the zoom. On iOS it works OK, but fails in cocos2dx.
I double-checked all variables (layer position, scale value, destinations etc.) debugging on two machines in some test cases: values of variables are the same in two versions, but there are different operation/result in cocos2dx.
After I removed that line, everything worked fine just as Rubby Entertainment said. I don’t know the purpose, but there is a bug around that, which causes problems after scale of layer has modified.

I’m having the same issue as well.

I have a class that is inheriting from CCLayer. I want to scale that layer down to 50% so I use node~~>setScale.
Before looking at this post I had the same problem: as soon as I set the scale I had the following side-effect: my layer position was wrong all of a sudden.
Removing the line mentionned above, which is in CCLayer’s default constructor, ‘fixes’ the position problem and the scaling is also working fine. I dug a bit deeper and found this code in CCNode::nodeToParentTransform:
<pre>
// optimization:
// inline anchor point calculation if skew is not needed
// Adjusted transform calculation for rotational skew
if )
{
x = cy * ~~m_obAnchorPointInPoints.x * m_fScaleX +~~sx * ~~m_obAnchorPointInPoints.y * m_fScaleY;
y += sy *~~m_obAnchorPointInPoints.x * m_fScaleX
cx *~~m_obAnchorPointInPoints.y * m_fScaleY;
}

I don’t use Cocos2d for iphone just Cocos2d-x so I can’t compare. However, what is obvious for now is that if we remove the line in CCLayer’s constructor, the code won’t go into that optimization because the AnchorPoint equals 0.

I’ll tinker more with the code and if I find a real fix, I’ll let you know.

edit: SDK info: cocos2d-2.1rc0-x-2.1.3

Cheers!

I think I have an idea of where it is coming from. CCLayers have m_bIgnoreAnchorPointForPosition set to true. Then in CCNode::nodeToParentTransform, there’s:

        // Translate values
        float x = m_obPosition.x ;
        float y = m_obPosition.y ;

        if (m_bIgnoreAnchorPointForPosition)
        {
            x += m_obAnchorPointInPoints.x;
            y += m_obAnchorPointInPoints.y;
        }

        // Rotation values
        // Change rotation code to handle X and Y
        // If we skew with the exact same value for both x and y then we're simply just rotating
        float cx = 1, sx = 0, cy = 1, sy = 0;
        if (m_fRotationX || m_fRotationY)
        {
            float radiansX = -CC_DEGREES_TO_RADIANS(m_fRotationX);
            float radiansY = -CC_DEGREES_TO_RADIANS(m_fRotationY);
            cx = cosf(radiansX);
            sx = sinf(radiansX);
            cy = cosf(radiansY);
            sy = sinf(radiansY);
        }

        bool needsSkewMatrix = ( m_fSkewX || m_fSkewY );


        // optimization:
        // inline anchor point calculation if skew is not needed
        // Adjusted transform calculation for rotational skew
        if (! needsSkewMatrix && !m_obAnchorPointInPoints.equals(CCPointZero))
        {
            x += cy * -m_obAnchorPointInPoints.x * m_fScaleX + -sx * -m_obAnchorPointInPoints.y * m_fScaleY;
            y += sy * -m_obAnchorPointInPoints.x * m_fScaleX + cx * -m_obAnchorPointInPoints.y * m_fScaleY;
        }

At the top, we have:

        if (m_bIgnoreAnchorPointForPosition)
        {
            x += m_obAnchorPointInPoints.x;
            y += m_obAnchorPointInPoints.y;
        }

but at the bottom, we have:

        if (! needsSkewMatrix && !m_obAnchorPointInPoints.equals(CCPointZero))
        {
            x += cy * -m_obAnchorPointInPoints.x * m_fScaleX + -sx * -m_obAnchorPointInPoints.y * m_fScaleY;
            y += sy * -m_obAnchorPointInPoints.x * m_fScaleX + cx * -m_obAnchorPointInPoints.y * m_fScaleY;
        }

It seems to me that they are out of synch. The first part seems to be trying to cancel the second part by pre-adding the anchor values to x and y. However, in the second part, the actual value is multiplied by other factors such as scaling before being added.

For me, since the problem is because of scaling, in the top part when it tries to cancel the second part, I can just add the scaling to fix it. However, with rotations and when ScaleX != ScaleY, it’ll get more complicated.

Hopefully, this will help getting this issue addressed. I don’t have more time to look at it but I would be happy to submit a bug report if such a tool exists.