5
votes

I am trying to change my Sprite anchor point so that I can rotate over a 0.0f,0.0f anchorpoint. At first my object is rotation at the default anchor point (0.5f,0.5f). However later on I need it to rotate over a 0.0,0.0 AnchorPoint.

The problem is I cannot change the anchor point and change the position accordingly, so it stays on the same position, without the object appearing to quickly move and reposition to its original point.

Is there a way I can set the anchor point and the position of my Sprite at once, without it moving at all?. Thank you.

-Oscar

4
What kind of sprites are you talking about?Nikolai Ruhe
Sorry I forgot to include that. I am talking about openGL 2.0 for iPhone Sprites.Oscar Gomez
Perhaps you mean cocos2d? OpenGL doesn't have a "iPhone Sprite".bentford

4 Answers

2
votes

This is a good question, and I don't know the full answer yet.

As you may have noticed, the anchorPoint cannot be changed without affecting scale and rotation.

For scaled sprites:

You have to simultaneously change the anchorPoint and position of your sprite. See this question for a hint

For rotated sprites:

Intuition says you would need to simultaneously change anchorPoint, rotation, and position. (I have no idea how to compute this.)

NOTE: I'm still learning graphics programming, so I'm not 100% able to compute this stuff yet.

3
votes

I found a solution to this with a UIView elsewhere, and rewrote it for cocos2d:

- (void)setAnchorPoint:(CGPoint)anchorPoint forSprite:(CCSprite *)sprite
{
    CGPoint newPoint = CGPointMake(sprite.contentSize.width * anchorPoint.x, sprite.contentSize.height * anchorPoint.y);
    CGPoint oldPoint = CGPointMake(sprite.contentSize.width * sprite.anchorPoint.x, sprite.contentSize.height * sprite.anchorPoint.y);

    newPoint = CGPointApplyAffineTransform(newPoint, [sprite nodeToWorldTransform]);
    oldPoint = CGPointApplyAffineTransform(oldPoint, [sprite nodeToWorldTransform]);

    CGPoint position = sprite.position;

    position.x -= oldPoint.x;
    position.x += newPoint.x;

    position.y -= oldPoint.y;
    position.y += newPoint.y;

    sprite.position = position;
    sprite.anchorPoint = anchorPoint;
}
2
votes

I've needed this a couple of times and decided to make a extension for CCNode, tested it abit and seems to work fine. Can be really useful to some :)

It's tested with 1.x but It should work fine in 2.x too. Supports transformed nodes and HD.

Just add this to your project and import whenever you need it - It will be added to all classes deriving from CCNode. (CCSprite, CCLayer)

Interface

#import "cocos2d.h"

@interface CCNode (Extensions)

// Returns the parent coordinate for an anchorpoint. Useful for aligning nodes with different anchorpoints for instance
-(CGPoint)positionOfAnchorPoint:(CGPoint)anchor;

// As above but using anchorpoint in points rather than percentage
-(CGPoint)positionOfAnchorPointInPoints:(CGPoint)anchor;

//Sets the anchorpoint, to not move the node set lockPosition to `YES`. Setting it to `NO` is equal to setAnchorPoint, I thought this would be good for readability so you always know what you do when you move the anchorpoint
-(void)setAnchorPoint:(CGPoint)a lockPosition:(BOOL)lockPosition;

@end

Implementation

#import "CCNode+AnchorPos.h"

@implementation CCNode (Extensions)

-(CGPoint)positionOfAnchorPoint:(CGPoint)anchor
{
    float x = anchor.x * self.contentSizeInPixels.width;
    float y = anchor.y * self.contentSizeInPixels.height;

    CGPoint pos = ccp(x,y);

    pos = CGPointApplyAffineTransform(pos, [self nodeToParentTransform]);

    return ccpMult(pos, 1/CC_CONTENT_SCALE_FACTOR());
}

-(CGPoint)positionOfAnchorPointInPoints:(CGPoint)anchor;
{
    CGPoint anchorPointInPercent = ccp(anchor.x/self.contentSize.width, anchor.y/self.contentSize.height);
    return [self positionOfAnchorPoint:anchorPointInPercent];
}

-(void)setAnchorPoint:(CGPoint)a lockPosition:(BOOL)lockPosition
{
    CGPoint tempPos = [self positionOfAnchorPoint:a];
    self.anchorPoint = a;

    if(lockPosition)
    {
        self.position = tempPos;
    }
}

@end
0
votes

Cocos2d-x + Fixed scale

YourClass.h

virtual cocos2d::Vec2 positionFromSprite(cocos2d::Vec2 newAnchorPoint, cocos2d::Sprite *sprite);

YourClass.m

Vec2 YourClass::positionFromSprite(Vec2 newAnchorPoint, cocos2d::Sprite *sprite) {
    Rect rect = sprite->getSpriteFrame()->getRect();
    Vec2 oldAnchorPoint = sprite->getAnchorPoint();
    float scaleX = sprite->getScaleX();
    float scaleY = sprite->getScaleY();

    Vec2 newPoint = Vec2(rect.size.width * newAnchorPoint.x * scaleX, rect.size.height * newAnchorPoint.y * scaleY);
    Vec2 oldPoint = Vec2(rect.size.width * oldAnchorPoint.x * scaleX, rect.size.height * oldAnchorPoint.y * scaleY);

    Vec2 position = sprite->getPosition();

    position.x -= oldPoint.x;
    position.x += newPoint.x;

    position.y -= oldPoint.y;
    position.y += newPoint.y;

    return position;
}