3
\$\begingroup\$

I've done my moving actions which consists of sequences of CCBezierBy. However I would like the sprite to rotate by following the direction of the movement (like an airplane). How sould I do this with cocos2d?

I've done the following to test this out.

    CCSprite *green = [CCSprite spriteWithFile:@"enemy_green.png"];
    [green setPosition:ccp(50, 160)];
    [self addChild:green];

    ccBezierConfig bezier;
    bezier.controlPoint_1 = ccp(100, 200);
    bezier.controlPoint_2 = ccp(400, 200);
    bezier.endPosition = ccp(300,160);

    [green runAction:[CCAutoBezier actionWithDuration:4.0 bezier:bezier]];

In my subclass:

@interface CCAutoBezier : CCBezierBy

@end

@implementation CCAutoBezier

- (id)init
{
    self = [super init];
    if (self) {
        // Initialization code here.
    }

    return self;
}

-(void) update:(ccTime) t
{
    CGPoint oldpos=[self.target position];
    [super update:t];
    CGPoint newpos=[self.target position];

    float angle = atan2(newpos.y - oldpos.y, newpos.x - oldpos.x);
    [self.target setRotation: angle];
}

@end

However it rotating, but not following the path...

\$\endgroup\$

2 Answers 2

2
\$\begingroup\$

I'm not sure if there is a class dedicated to this purpose or not but you can simply implement your own. just inherit your class from CCBezierBy class and then in update function after applying what CCBezierBy by does change direction of airplane based on movement generated bu CCBezierBy.

there might be some errors in this code(i'll be glad if you fix them), but this is showing how easy you can implement it!

-(void) update: (ccTime) t
{
    CGPoint oldpos=[target position];
    [super update:t];
    CCPoint newpos=[target position];

    float angle = atan2(-newpos.y + oldpos.y, newpos.x - oldpos.x) * 180 / M_PI;
    [target setRotation: angle];
}

I'm not sure if this will help you but here is my code (though in c++ using cocos2d-x)

class mybezier : public CCBezierBy
{
public:
    static CCBezierBy* actionWithDuration(float t,ccBezierConfig k)
    {
        mybezier* b = new mybezier;
        b->CCBezierBy::initWithDuration(t,k);
        return b;
    }

    virtual void update(ccTime t)
    {
        CCPoint oldpos = getTarget()->getPosition();
        CCBezierBy::update(t);
        CCPoint newpos = getTarget()->getPosition();
        float angle = atan2(-newpos.y + oldpos.y, newpos.x - oldpos.x) * 180 / M_PI;
        getTarget()->setRotation(angle);//*  180);
    }
};

and I'm calling this class using this lines:

ccBezierConfig x;
x.controlPoint_1 = CCPoint(CCDirector::sharedDirector()->getWinSize().width / 2,0);
x.controlPoint_2 = CCPoint(0, CCDirector::sharedDirector()->getWinSize().height / 2);
x.endPosition = CCPoint(0,0);
pSprite->runAction(CCRepeatForever::actionWithAction(mybezier::actionWithDuration(10,x)));
\$\endgroup\$
10
  • \$\begingroup\$ That update method, where do you call it? Or is it called automatically? I really don't like the idea of having to call update from its parent. It would be good if I just simply CCAction:[BezierSubclass ...] and this autorotates the sprite. \$\endgroup\$
    – marcg11
    Commented Dec 3, 2011 at 18:21
  • \$\begingroup\$ it's called automatically, you just have to change every CCBezier word in your game to CCBezierSubclass and everything will work as expected. \$\endgroup\$
    – Ali1S232
    Commented Dec 3, 2011 at 19:12
  • \$\begingroup\$ Hmm, its not even rotating the sprite. \$\endgroup\$
    – marcg11
    Commented Dec 3, 2011 at 20:11
  • \$\begingroup\$ did you also override init and alloc methods? I think the main problem is by calling [CCBezierSubclass alloc] you are getting a reference to CCBezier class since alloc is not override in inherited class. \$\endgroup\$
    – Ali1S232
    Commented Dec 3, 2011 at 20:19
  • \$\begingroup\$ What should I put in init and alloc method? \$\endgroup\$
    – marcg11
    Commented Dec 3, 2011 at 20:22
2
\$\begingroup\$

This works great, here it is in Objective-C for Cocos2d on iOS. Just use CCTBezierRotateTo instead of CCBezierTo. Same thing should work for CCBezierBy. My sprites rotate to follow the path given by bezierForward.

I call it like this:

id bezierForward = [CCTBezierRotateTo actionWithDuration:10.0 bezier:bezier];
[missileSprite runAction:bezierForward];

Here is the .h:

#import "CCActionInterval.h"
@interface CCTBezierRotateTo : CCBezierTo
@end

Here is the class:

@implementation CCTBezierRotateTo

-(CCBezierBy*) actionWithDuration :(float)t :(ccBezierConfig) k {
    CCTBezierRotateTo* r = [CCTBezierRotateTo actionWithDuration:t];
    return r;
}

-(void) update:(ccTime)time {
    CGPoint oldpos = [[self target] position];
    [super update:time];
    CGPoint newpos = [[self target] position];
    float angle = atan2(-newpos.y + oldpos.y, newpos.x - oldpos.x) * 180 / M_PI;
    angle += 90; // my sprites start pointing up
    [[self target] setRotation:angle];
    NSLog(@"oldpos %f,%f newpos %f,%f angle %f", oldpos.x, oldpos.y, newpos.x, newpos.y,  angle);
}
\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .