views:

212

answers:

3

I'm animating a pendulum which swings from 0 degrees to max 200 degrees and then back again. The problem is that if the pendulum goes over 180 degrees, it returns to 0 by the shortest route which is to continue clockwise. And I'd like it to go anticlockwise. Here's my code: ('right' is a boolean which is TRUE when the pendulum is swinging from left to right)

 - (void)swingPendulum {
    CABasicAnimation *rotationAnimation;
    rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
    if (right) 
        rotationAnimation.toValue = [NSNumber numberWithFloat:degreesToRadians(kMax)];
    else
        rotationAnimation.toValue = [NSNumber numberWithFloat:degreesToRadians(kMin)];                               
    rotationAnimation.duration = 1.0;
    rotationAnimation.repeatCount = 1.0; 
    rotationAnimation.delegate = self;
    rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    rotationAnimation.removedOnCompletion = NO;

    [pendulum.layer addAnimation:rotationAnimation forKey:@"rotationAnimation"];
}

Any ideas how I can make this work? It's the final piece of my swingometer puzzle which is otherwise working great :D Thanks!

Michael

A: 

I'm not sure exactly what the issue is, but if you use the animation's auto reverse feature, you can probably simplify this and cause it to rotate (swing) back and forth. This works for me:

CABasicAnimation* rotationAnimation = 
          [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
[rotationAnimation setToValue:[NSNumber numberWithFloat:DegreesToRadians(200.0)]];
[rotationAnimation setDuration:1.0];
[rotationAnimation setRepeatCount:HUGE_VALF]; // Repeat forever
[rotationAnimation setAutoreverses:YES]; // Return to starting point

[[pendulum layer] addAnimation:rotationAnimation forKey:nil];
Matt Long
A good idea, but the reverse swing isn't an exact reversal of the forward swing. I.e. the forward swing starts at 0, but the reverse swing swings back to -20. So I'd rather call a function which swings it back from its current transform to a specific angle. I'm not trying to make a pendulum exactly, rather a golf game style swingometer - the player stops it once on the way up for power and again on the way down for accuracy. It works perfectly unless the bar goes over 180 degrees on the way up, after which it will carry on anticlockwise to 0, rather than reverse.. So I need to force is somehow
Smikey
A: 

Try setting something like

rotationAnimation.valueFunction = [CAValueFunction functionWithName:kCAValueFunctionRotateZ];

Using value transform functions, animations can effect the transform property of a layer using arbitrary transforms of each component (no normalization to 360°) and concatenate in the normally when multiple animations are applied at once.

You use a value transform function that rotates from 0° to 180° around the z-axis by creating a CAValueTransform function specifying the kCAValueFunctionRotateZ and then creating an animation with a fromValue of 0, a toValue of M_PI, and set the animation’s valueTransform property to the value transform instance.

tc.
Thanks. I'm a little reluctant to change the approach I'm already using unless there's no way to fix it, since I have a lot of other code that relies of the methods I've already used. As commented above, I'm actually creating a golf-game style swingometer, rather than a pendulum, so at any point the user can interrupt the swing on the way up (to determine power) and it will swing back, so the user can interrupt again (to determine accuracy). I have all this functionality, apart from the fact that if the user lets the bar swing over 180 degrees, it does not swing back, rather it goes forward.
Smikey
Try setting it and seeing if it works? I get the impression that it ought to.
tc.
I did - it started behaving pretty strangely... I'll have a bit more of a fiddle and get back!
Smikey
A: 

To get it to go anticlockwise, just set x to a negative value (add - in front) where rotationAnimation.toValue = [NSNumber numberWithFloat:degreesToRadians(x)];

Lily
Thanks for the answer but it doesn't seem to make a difference I'm afraid. Setting it to a -ive value just seems to make the animation snap at the end... I think perhaps I might have to re-write it to use an NSTimer and animate the thing frame by frame...
Smikey
Actually, you're right - since kMin is currently set to -20, so that does infact make the pendulum swing anti-clockwise, but only if it doesn't go past 180 degrees. If it goes past 180, then no matter what value I set it at (-180, -90, 90 etc), it always continues clockwise, even if it isn't the shortest route... Any other ideas?
Smikey
AAAAH, if I set it to a value like -380 however, it works. I'm not really sure why, but I've just added a condition that switches the toValue according to whether or not the initial swing passes 180 degrees. Thanks for all the help!
Smikey