views:

146

answers:

1

Hi there,

I'm trying to create a swingometer, a bit like the ones used in golf games, where the user holds a button to start a swing, releases at the apex to determine power, at which point the 'swing' reverses direction, and the user taps again on the way down to set the accuracy.

Rather than having a bar that fills up, I would like to use a pendulum that swings from left to right. The pendulum leaves a mark where it is first tapped (power) and another mark where it is tapped for the second time (accuracy).

My first problem is rotating the pendulum. I've been reading these posts about rotating a UIImageView - here , here and here but I was hoping I might be able to get a little extra advice :)

First of all, is rotating a UIImageView the best way to approach this? I was thinking of determining how close the pendulum is to the correct spot by comparing its coordinates to the coordinates of the correct spot. But for this to work, the UIImageView would have to physically move, which I'm not sure it does? Also, how does one make a UIImageView rotate around a specific spot, rather than the centre point. Or should I just make the pendulum's bounding box bigger so the centre point is in the correct position. And how can I leave a 'stamp' where the user hits (or releases) the button?

Any general help regarding the best way to approach this would be very much appreciated :) Perhaps my question is a little vague and generalised, but I'm hoping someone might like the challenge :)

Thanks!!

Michael

UPDATE:

Ok I've tried the following two approaches, both of which now work.

- (void)viewDidLoad {
    pendulum.image = [UIImage imageNamed:@"winkOpen.png"];
    [self swingPendulum];
}

- (void)swingPendulum {
CABasicAnimation *rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat:degreesToRadian(180)]; 
rotationAnimation.duration = 0.75;
rotationAnimation.repeatCount = 1.0; 
rotationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];

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

}

/*
- (void)swingPendulum {
    [UIView setAnimationBeginsFromCurrentState:YES];
    [UIView beginAnimations:nil context:nil];
    [UIView setAnimationDuration:1];
    pendulum.transform = CGAffineTransformMakeRotation(degreesToRadian(180));
    [UIView setAnimationDelegate:self];
    [UIView commitAnimations];
}
*/

Now I'm not sure which approach is better, but with the first, the pendulum swings above 0 degrees rather than below it, so I'm going with that.

Now I need to determine where the pendulum stops and reverse the swing... But maybe I'll post those as separate questions since this is getting a bit cluttered! I'll make sure my questions are more specific in future :)

+1  A: 

For the animation, you will want to look at transforms. See the Quartz 2D programming guide:Transforms.

You should not use the actual pixel location of the view for your calculations. If you do, changes in screen dimensions and/or resolution will require a complete rewrite. Instead create an abstract data model of the motion and location, perform your calculations within the abstract model. Then translate the abstract coordinates to the coordinates of the current display.

Getting the imageView to appear where you want it is relatively trivial compared to calculating where it should be in the first place. You have to get the motion right. Remember, "it don't mean thing if you ain't got that swing!"

TechZen
Thanks for the answer! I've since decided that I don't need to calculate accurately how far from the correct point the pendulum is stopped, simply if it's too strong, too weak or just right. I can presumably do this by just taking the angle it's at when the user hits the button. I.e. < 170 degrees = too weak, > 170 and < 190 = just right and > 190 = too strong. But then I need to extract the current image's transformation angle from somewhere...Also, I'm having trouble simply making the pendulum swing - will post the code I'm using now and update the question, so any help much appreciated
Smikey
Transforms are a big topic. The real trick to learning them is that they don't accumulate like you expect them to e.g. you have a rotation transform of 45 degrees and you call it twice. You would expect that that the transformed object would rotate 90 degrees. It doesn't. It rotates 45 degrees no matter how many times you call it because the transform always starts with the original object position. To make the transforms accumulate, you have to transform the existing transform. So, you set a 45 degree transform then call another 45 degree transform on the first transform.
TechZen
I see - well I've managed to make the pendulum swing one way now, but as you say, when I apply a secondary transformation to make it swing back, it applies the transform to the original position, not the current position, so the pendulum just swings in reverse from its original position. So from what you say, I need to apply the current transform to the pendulum itself, before applying the reverse transform. Do you know how I might extract the current transform angle from the current animation? I hope that makes sense... :s And thanks for the help!
Smikey
@Smikey - You can extract the rotation angle using code like I have in this answer: http://stackoverflow.com/questions/877198/is-there-a-way-to-figure-out-how-many-degrees-an-view-is-rotated-currently-durin/878618#878618 , but your best bet is to incrementally rotate the transform using CATransform3DRotate() from the current transform, rather than using CATransform3DMakeRotation().
Brad Larson
Right - thanks Brad, I've managed to get it pretty much up and running and working in some cases. There's one question I have about the post you link to above, and for some reason I can't comment on it, only submit and answer. When I use that code to extract the angle, if the pendulum swings past 180 degrees, the trigonometry used produces negative angles. I'd really like it to continue to 200 degrees as the max value on the right, and if possible, -20 degrees on the left. My trig is pretty rusty/bad and I wouldn't know how to do this. Any suggestions? Thanks :)
Smikey