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.

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. 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): ```
```
// 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 |

You must be logged in to reply to this topic.