# Jumping a sprite while moving in a Bezier action

I'm creating a game and I need the sprite to jump (move up and down basically) while it's moving on a bezier path so it moves vertically while it still follows the path. If I do this while it's moving along the bezier path:

[mySprite runAction:[CCJumpBy actionWithDuration:0.1 position:ccp(0,0) height:10 jumps:1]];


It jumps vertically but instantly it returns to the position on the path. What I want is to jump relative to the path.

Does anyone know anything about it?

It would looks something like this:

The curve is a sequence of CCBezierBy's by the way.

Thanks.

• Wouldn't you just continue updating the x axis as defined by the Bezier curve, but override the y value during the jump? I don't know anything about the tech your using so my suggesting could be stupid :)
– House
Mar 19 '12 at 20:39
• I'm not quite following what you're asking. Are you trying to only follow the X coordinates of the bezier curve or limit your jump height by the curve or what? Mar 19 '12 at 20:44
• This is what I'm imagining... Is that correct? Where the red line shows a jump.
– House
Mar 19 '12 at 20:51
• This code looks like it's sauced in some automagic library, making it hard to know what is going on. I wonder what actionWithDuration does and what happens if this number is increased. Mar 19 '12 at 20:52
• @Byte56 Thats exactly what I'm looking for. Mar 19 '12 at 20:56

Your sprite follows the bezier curve over time. So the position of your sprite is defined as:

sprite.x = bezier(time).x;
sprite.y = bezier(time).y;


This function updates the position of your sprite every frame. This is why you only see your 'jump' for a very short time (something like 1/30th of a second). To add the curve of jumping you need to change the function to this:

sprite.x = bezier(time).x;
sprite.y = bezier(time).y + jump(force, time);


This way you add the position on the curve of the jump, as defined by the force of the jump and the time to the y position.

Alternatively if you don't want the jump height to stay relative to the bezier curve you can do this:

if(jumping)
sprite.x = bezier(time).x;
sprite.y = bezier(timeOfJumpStart).y + jump(force, time);
else
// old code


Now my answer is very general so I hope it makes sense, but without seeing your code this is the best I can do.

• I'm using CCAction from cocos2d, with CCBezierBy you set up the bezier points and tell the sprite to run the action. Cocos2d runs and moves the sprite automaticlly through an internal timer. Thanks for answering but i don't think this will help me. Mar 19 '12 at 21:07
• Ah that's a bit different than most game engines work. Maybe you can respond to the internal timer? Mar 19 '12 at 21:18
• I really don't know if I can respond to the internal timer. Maybe someone knows... :( Mar 19 '12 at 21:31
• Is there no way to pull out the (x,y) coordinates at any given time with this CCBezierBy library? If it's open source, you may be able to go add your own utility method. Bezier Curves aren't actually all that complicated. Take a look at the "Interpolation and Splines" demo here: essentialmath.com/tutorial.htm Mar 19 '12 at 23:45
• If you're running animations in a separate thread and above all that you do not have any frame-to-frame update callback that allows you to change the position, the AI, the sounds, whatsoever... then I'm gonna say it frankly: your code architecture is wrong. Please consider refactoring by following the common patterns used in game development. In a nutshell, every frame you gather all the events that have been fired in the meantime, you update all the displayables or anything else you need to update with the latest changes that just happened, and finally you draw. Mar 20 '12 at 9:45

Aparently it is more simple than it looks. I had to sublclass CCJumpBy:

@implementation CCMyJumpBy

- (id)init
{
self = [super init];
if (self) {}
return self;
}

-(void) update:(ccTime) t
{
// parabolic jump (since v0.8.2)
ccTime frac = fmodf( t * jumps_, 1.0f );
ccTime y = height_ * 4 * frac * (1 - frac);
y += delta_.y * t;
ccTime x = delta_.x * t;
[target_ setPosition: ccp( ((CCNode*)target_).position.x + x, ((CCNode*)target_).position.y + y )];//This is what has been changed
}
@end


The CCAction classes aren't very well suited to incorporate user-interaction. The primary use for them is animation, where you want your object to perform some fixed action/movement over time.

That being said, there are still ways to do what you want. The cleanest and most flexible approach would be to simply go ahead and implement the Bezier movement yourself, looking at the source of CCBezierBy might be a good starting point (you'll find the source in cocos2d/CCActionInterval.m), then factor in jump strength, much like Roy T. described in his answer.

If that's too much work or if you'd rather stick with CCBezierBy, then are also ways to do what you want. The simplest approach would be to have a CCNode which holds your sprite. Then you animate the CCNode using CCBezierBy and animate your sprite using CCJumpBy:

CCNode -> animated using CCBezierBy
|
+--- CCSprite -> is child of CCNode and is animated using CCJumpBy

• @marcg11 It won't work using CCSpriteBatchNode. In that case you'll have to write the movement code yourself. Mar 20 '12 at 10:41
• I thought about this later, gonna try it. However, I'm using spriteBatchsheets, that means I can't add a node to the batch only sprites. How I'm I supose to fix that. Going to try what Roy suggests to. Mar 20 '12 at 10:44