1

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 :)

Community
  • 1
  • 1
Smikey
  • 8,106
  • 3
  • 46
  • 74
  • I thought "Swingometer", that sounds interesting! Then I read the question and found out it was about golf. Sigh. Talk about a letdown. – TechZen Aug 10 '10 at 12:41
  • Well actually I'm not using it for a golf game, I just thought that was an example that would most accurately describe the problem. It's interesting, I promise :) – Smikey Aug 10 '10 at 13:42
  • 1
    Those "undefined symbols" errors you are seeing are because you are not linking the QuartzCore framework (which contains the Core Animation classes and data types). Also, as a practical matter, how will the user actually see the display as they are swinging? – Brad Larson Aug 10 '10 at 13:59
  • But I've imported the QuartzCore library like so: #import That should work no? If I don't have it, I have a whole load more complaints from the compiler... As for seeing the display - doesn't this animation play out when the function is called?? – Smikey Aug 10 '10 at 14:11
  • 1
    @Smikey - That's just importing a header. You also need to link the framework (those are linker errors you are seeing). To do this, right-click on your project and go to Add | Existing Frameworks... and choose QuartzCore.framework from the list. – Brad Larson Aug 10 '10 at 16:05
  • Brilliant - thanks Brad! I've never had to import a framework up until this point so there was a glaring gap in my knowledge. Now it works just fine! Now I just need to figure out how to make the thing swing back and forth, but this is a good start :) – Smikey Aug 10 '10 at 16:54

1 Answers1

1

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
  • 64,370
  • 15
  • 118
  • 145
  • 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 Aug 10 '10 at 13:26
  • 1
    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 Aug 10 '10 at 17:26
  • 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 Aug 10 '10 at 17:33
  • 1
    @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 Aug 10 '10 at 18:26
  • 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 Aug 11 '10 at 15:30