Rotation of sprite following a bezier path

Forums Programming cocos2d support (graphics engine) Rotation of sprite following a bezier path

This topic contains 14 replies, has 10 voices, and was last updated by  the_drewster 2 years, 2 months ago.

Viewing 15 posts - 1 through 15 (of 15 total)
Author Posts
Author Posts
August 16, 2009 at 10:41 pm #216408

sledbox
@sledbox

It is very possible that I am missing something here, but is there way for a sprite to autorotate based on a bezier path it is following? An example would be a train following a curvy track – the train car should rotate as it turn. Any help would be very much appreciated.

Thanks

August 17, 2009 at 1:05 pm #254524

simo
@simo

Basically you want to figure out the rotation angle for each step in the animation.

I think some trigonometry can help you out here.

Calculate a tangent for the point in the bezier curve.

Calculate a rotation angle between edge of the screen and that tangent?

Rotate your sprite accordingly.

Some quick google searches found this:

http://stackoverflow.com/questions/292774/calculating-rotation-along-a-path

http://bimixual.org/AnimationLibrary/beziertangents.html

Not sure if cocos2d has any helper functions for this, though.

August 17, 2009 at 5:18 pm #254525

sledbox
@sledbox

Thanks for your help. I was hoping I was missing something, but I think you’re right.

It is too bad there isn’t something similar to the rotationMode property for CAKeyframeAnimation.

http://developer.apple.com/documentation/GraphicsImaging/Reference/CAKeyframeAnimation_class/Introduction/Introduction.html#//apple_ref/occ/cl/CAKeyframeAnimation

Looks like I’m going to have to refresh my trig skills.

August 17, 2009 at 5:45 pm #254526

patrickC
Participant
@patrickc

How are you following the body?

If you’re able to calulate 2 points in the bezier curve depending on your sprite’s body, then you can calculate the angle the sprite should have.

If you include chipmunk, you have access to the vector calculation functions.

You would calculate the vector between the 2 points (with cpvsub), the angle of the vector (with cpvtoangle) and then apply that result to the sprite.

chipmunk works in radians while cocos2d uses degrees (also, inverted sign), so you’ll need to multiply the value by -180/M_PI.

Hope that helps!

August 17, 2009 at 5:50 pm #254527

cjl
Participant
@cjl

FYI, I think many of the vector functions are also in Cocos2d, in CGPointExtension:

http://code.google.com/p/cocos2d-iphone/source/browse/trunk/cocos2d/Support/CGPointExtension.h

August 17, 2009 at 6:00 pm #254528

patrickC
Participant
@patrickc

Ah, so they are!

some extra ones too, thanks for the tip!

August 18, 2009 at 3:41 am #254529

sledbox
@sledbox

Thanks to all of you for your help. Having those vector functions have been helpful, although I still don’t have a robust enough figured out. I’ll certainly share once I have something working.

August 18, 2009 at 4:16 am #254530

Steffen Altwiese
Moderator
@steve-oldmeadow

Google derivative (as in calculus, not finance).

August 18, 2009 at 3:35 pm #254531

sledbox
@sledbox

Ok, I believe I have a pretty solid solution.

I first tried doing these calculations inside the sprite that was moving by saving reference points and calculating slope – very messy! I realized that this would be much easier and efficient if I just added some code in the method where the sprite position on the curve is calculated. So here is what I have.

In the update of BezierBy in IntervalAction.m I added this block (near line 678):

// calculate the rotation in degrees

// find the point in time t with a quadratic bezier of the first 3 points

float qx = (powf(1-t,2)*xa + 2*(1-t)*t*xb+powf(t,2)*xc);

float qy = (powf(1-t,2)*ya + 2*(1-t)*t*yb+powf(t,2)*yc);

// the tangent is equal to the slope between the position point and the point on the quadradic bezier

double deltaX = x-qx;

double deltaY = y-qy;

double degrees = (-180/M_PI)*ccpToAngle(CGPointMake(deltaX,deltaY));

[target setPosition: ccpAdd( startPosition, ccp(x,y))];

You could add in some flag to turn this on or off, but this satisfies my needs.

@simo – your links were very helpful!

I hope this helps anyone else trying to do the same thing. Thanks again for all of your help.

September 14, 2009 at 7:22 pm #254532

Tony
@tony

Ingenious sledbox! I’ve been calculating theta between two point and converting from radians to degrees outside the action. It works fine, but I like your solution much better. You should submit it to riq as an addition.

August 22, 2010 at 12:31 pm #254533

glnngu
@glnngu

Is there a solution to this for CCBezierTo function for 0.99.5?

October 28, 2010 at 4:59 am #254534

gwdp
Participant
@gwdp

Based on Kappa derived .

Thanks to : http://www.whizkidtech.redprince.net/bezier/circle/kappa/ .

Hope it helps !

bola = [CCSprite spriteWithFile:@"Bola.png"];

[bola setPosition:ccp(320/2,480/2+75)];

[self addChild:bola];

[bola runAction:[self returnBezierCurveWithDuration:1 andRadius:75 AndObjectPosition:bola.position];

- (CCFiniteTimeAction *)returnBezierCurveWithDuration:(float)_time andRadius:(int)_radius AndObjectPosition:(CGPoint)_pos {

ccBezierConfig bezierOne ;

bezierOne.controlPoint_1 = _pos ;

bezierOne.controlPoint_2 = ccp(_pos.x+_radius*sin(45) , _pos.y-(_radius-(_radius*sin(45))));

bezierOne.endPosition = ccp(_pos.x+_radius,_pos.y-_radius) ;

ccBezierConfig bezierTwo ;

bezierTwo.controlPoint_1 = ccp(_pos.x+_radius,_pos.y-_radius) ;

bezierTwo.controlPoint_2 = ccp(_pos.x+_radius*sin(45) , _pos.y-_radius-(_radius*sin(45)) );

bezierTwo.endPosition = ccp(_pos.x,_pos.y-_radius*2) ;

ccBezierConfig bezierThree ;

bezierThree.controlPoint_1 = ccp(_pos.x,_pos.y-_radius*2) ;

bezierThree.controlPoint_2 = ccp(_pos.x-_radius*sin(45) , _pos.y-_radius-(_radius*sin(45)) );

bezierThree.endPosition = ccp(_pos.x-_radius , _pos.y-_radius) ;

ccBezierConfig bezierFour ;

bezierFour.controlPoint_1 = ccp(_pos.x-_radius , _pos.y-_radius) ;

bezierFour.controlPoint_2 = ccp(_pos.x-_radius*sin(45) , _pos.y-(_radius-(_radius*sin(45))) );

bezierFour.endPosition = _pos ;

return [CCSequence actions:

[CCBezierTo actionWithDuration:_time/4 bezier:bezierOne],

[CCBezierTo actionWithDuration:_time/4 bezier:bezierTwo],

[CCBezierTo actionWithDuration:_time/4 bezier:bezierThree],

[CCBezierTo actionWithDuration:_time/4 bezier:bezierFour],

nil];

}

November 6, 2010 at 10:22 am #254535

elang
@srinivas87

hi, @gwdp

refer link: http://www.cocos2d-iphone.org/forum/topic/10862#post-62116

in that coding is ball flowing motion after the line(moving line) was display.

but the line is not displaying in console window the updating the time of every frames.

can u tell in that coding how to use this bezier or ribbon function. am new to this.

February 13, 2012 at 10:56 am #254536

the_drewster
@the_drewster

Hey. I can’t see where “degrees” is called, below.

// calculate the rotation in degrees

// find the point in time t with a quadratic bezier of the first 3 points

float qx = (powf(1-t,2)*xa + 2*(1-t)*t*xb+powf(t,2)*xc);

float qy = (powf(1-t,2)*ya + 2*(1-t)*t*yb+powf(t,2)*yc);

// the tangent is equal to the slope between the position point and the point on the quadradic bezier

double deltaX = x-qx;

double deltaY = y-qy;

double degrees = (-180/M_PI)*ccpToAngle(CGPointMake(deltaX,deltaY));

[target setPosition: ccpAdd( startPosition, ccp(x,y))];

February 13, 2012 at 11:25 pm #254537

the_drewster
@the_drewster

I’d like to implement this. I’ve updated IntervalAction.m to include the above, but I’m unsure how to call it. Where is the variable degrees used? Any help would be great. Thanks

Viewing 15 posts - 1 through 15 (of 15 total)

You must be logged in to reply to this topic.