How to rotate compass needle smoothly - iphone

I have done the coding for rotating a needle in a compass using:
NeedleView.transform=CGAffineTransformMakeRotation(theHeading);
but the rotation is not smooth. It is moving roughly.
Can anyone tell me how to do a smooth rotation of the compass needle with respect to angular movement?

You can compensate the jumpiness of the compass with the gyroscope. I have done a project using that method that you can see here: http://www.sundh.com/blog/2011/09/stabalize-compass-of-iphone-with-gyroscope/

Try this. Works well for me.
- (void)locationManager:(CLLocationManager *)manager didUpdateHeading:(CLHeading *)newHeading {
self.lblGrados.text = [NSString stringWithFormat:#"%.0f°", newHeading.magneticHeading];
[UIView animateWithDuration:0.5 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
needle.transform = CGAffineTransformMakeRotation((degrees-newHeading.trueHeading) * M_PI / 180);
} completion:nil];
}

Do an animation with the transform, don't just set it. If you set it, it will change rotation right away. Animation will slow it. You can select the duration over which the animation occurs to slow it down. Look at the docs for UIView for the animation APIs.

Related

Rotate in z-axis like core-animation slot machine

I was to able to move or animate my UIView by this code down here:
- (void) makeAnim1{
//downward animation
[UIView animateWithDuration:1.5
delay:0.15
options: UIViewAnimationCurveLinear
animations:^{
carousel.frame = CGRectOffset(carousel.frame, 0, 650);
}
completion:^(BOOL finished){ //task after an animation ends
[self performSelector:#selector(makeAnim1_1) withObject:nil afterDelay:2.0];
NSLog(#"Done!");
}];
}
- (void) makeAnim1_1{
//upward animation
[UIView animateWithDuration:1.5
delay:0.1
options: UIViewAnimationCurveLinear
animations:^{
carousel.frame = CGRectOffset(carousel.frame, 0, -650);
}
completion:^(BOOL finished){
NSLog(#"Done!");
}];
}
But it only move the UIView up and down. How can I make it spin like a Slot machine but only contains one image or view. Like rotate in z axis. But make it look like it contains more than one image.
Thanks for the help.
Instead of changing the frame inside the animation block you change the transform. The transform can be used to scale, rotate and translate (move) the view. You can only rotate around the z-axis but that is what you asked for. The transform property on the view takes a CGAffineTransform, like this:
// rotate pi/2 degrees clockwise
carousel.transform = CGAffineTransformMakeRotation(M_PI_2);
If you need to do more advanced transforms like rotating around another axis then you would need to use a little bit of Core Animation and to set the transform property of the views layer (which takes a CATransform3D instead of a CGAffineTransform).
As with all Core Animation code you need to import QuartzCore.framework and include QuartzCore/QuartzCore.h in your code.
The above animations you are doing is UIView animations which are only meant to animate views but the animation you are asking for requires more advanced animations of the views layer. I suggest that you look at the documentation for CABasicAnimation and also take a look at the Core Animation Programming Guide for iOS to learn more.
You can animate the x rotation of a views layer like this:
CABasicAnimation *slotAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.x"];
[slotAnimation setToValue:[NSNumber numberWithFloat:M_PI_2]];
// animation customizations like duration and timing
// that you can read about in the documentation
[[carousel layer] addAnimation:slotAnimation forKey:#"mySlotAnimation"];
The above code will indeed rotate the view around the x axis but will look very silly without perspective (search SO for "perspective Core Animation", it has been asked about before). There is probably a lot of tweaking to get the correct look but this should be enough to get you started.

How to change a CALayer's default animation time?

I use these code to move a CALayer:
CGPoint position = self.position;
position.x += 10;
position.y += 10;
self.position = position;
There is a default animation when i change the position of a layer without any animation call.This will cause lag on movement of a layer when i use these code in touchesMoved:withEvent:.
What i want to do is remove the default animation, and move the layer immediately so that it can responds to touch event quickly, just like the "center" property of UIView does.
What should i do? special thx!
The other poster had the right idea, but didn't provide enough information.
If you want to change layer properties instantly, without animation, you need to put those changes inside a CATransaction where you disable actions:
[CATransaction begin];
//[CATransaction setAnimationDuration: 1.0/30.0];
[CATransaction setDisableActions: TRUE];
//Put layer changes you want to take place without animation here.
[CATransaction commit];
Simply set
[CATransaction setDisableActions:YES];
this will make the Layer move without lag

smooth animation in iOS using CoreAnimation

CoreAnimation is a pretty easy thing, but:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:30];
MyImageView.frame = CGRectOffset(MyImageView.frame, 100, 0);
[UIView commitAnimations];
I want to move the ImageView by 100 Pixel veeeery slowly. Therefore all positioning values are double I expect the Layoutsystem to position the items with subpixel accuracy.
Butt when I watch this animation i see the ImageView "jumping" pixelwise instead of a smooth traveling.
Any ideas to come to a real subpixelpositioning?
I also tried to set the position with a timer and recalculate the frame-values, but same effect.
Update:
In an other part of my App I use the Accelerometer to update the position of a ImageView, and do basicly calculate the position ad size of the graphic an then do:
MyImageView.frame = newCGRect;
I get around 60 Updates/s from the Accelerometer and added the LowPass-Filter from the Accelerometer example from Apple.
Here the positioning is perfect?!?!
Why does this do not happen with CoreAnimation?
Thanks for any help.
Try using CGAffineTransformTranslate(MyImageView.transform, 100, 0) instead of CGRectOffset.
Reference here:
http://developer.apple.com/library/mac/#documentation/GraphicsImaging/Reference/CGAffineTransform/Reference/reference.html
If you use CABasicAnimation in QuartzCore framework, you can smoothen your animation using "CAMediaTimingFunction". Built-in alternatives worked for me but as far as I know you can define your own timing functions as well.
CABasicAnimation *starShineAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation"];
starShineAnimation.removedOnCompletion = NO;
starShineAnimation.fillMode = kCAFillModeForwards;
starShineAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
....

Developing A Simple Game without using Game Engines?

I am trying to develop a simple soccer game including penalty kicks in which i have to animate a ball from player to the goal post...earlier i have been using simple animations using a timer to add to the axis of ball image so that it moves from 1 point to another..but i did not have the desired result as animations were not that smooth...So i was thinking of using a Game Engine...Since i am a New Programmer i have no idea about game engine and neither can i find any proper documentation regarding engines like box2d or chipmunks or sparrow..i was also thinking of using UIView animations instead of the earlier animations as i think that can achieve far better animations without scratching my head trying to work on a game engine....I am going no where with this so it would be really great if someone can put some light on this issue of mine???
Use UIView animations, like in:
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3]; // or whatever time
object.center=CGPointMake(object.center.x+2, object.center.y+4);
// or whatever
[UIView commitAnimations];
You should also use an NSTimer with the same interval so that you can call animations smoothly.
NSTimer *timer=[NSTimer scheduledTimerWithTimeInterval:0.3 target: self
selector:#selector(animation) userInfo: nil repeats: YES];
Then, implement the method:
- (void)animation {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3]; // or whatever time
object.center=CGPointMake(object.center.x+5, object.center.y+7);
// or whatever
[UIView commitAnimations];
}
This should do for ANY simple game.
As you tagged the question with cocos2d, I guess you're using it, or planning to. Animating CCSprites is easy as you can see e.g. in this game https://github.com/haqu/tweejump.
In your onEnter implementation, just call
[self scheduleUpdate]
this will call routinely the update: where you can do your drawing
- (void)update:(ccTime)dt {
ball_pos.x += ball_velocity.x * dt;
ball_pos.y += ball_velocity.y * dt;
ball_velocity.x += ball_acc.x * dt;
ball_velocity.y += ball_acc.y * dt;
//game logic goes here (collision, goal, ...)
ball.position = ball_position;
}
That'll handle smooth movement of the ball. ball_pos, ball_velocity and ball_acc being vvCertex2F.
You probably don't even have to deal with acceleration, and only give an impulse to the ball when someone hit it (i.e. bump the velocity).
You probably also want some damping to slow the ball down. you do it by reducing the velocity at every step

Can i move the origin when doing a rotation transform in Quartz 2D for the iPhone?

Sorry if this is obvious or covered elsewhere, but i've been googling all day and haven't found a solution that actually worked.
My problem is as follows: I am currently drawing an image in a full screen UIView, for examples sake we'll say the image is in the bottom right corner of the UIView. I'd like to do a rotation transform(CGAffineTransformMakeRotation) at the center of that image, however, by default the rotation command rotates around the center of the UIView it self. As a result, my image moves around the screen when i rotate instead of it staying in place and rotating around its own center.
From what i've gathered, i need to translate my context so that the origin(center of the UIView) is at the center of my image, Rotate, and then restore the context by translating back to the original spot.
The following is the closest thing i've gotten to work, but the problem is that while the image is rotating, it moves downward while it's rotating. I think this is caused by animation tweening the 1st step translate and 3rd step translate instead of just realizing that the beginning and end point on the translates would be the same...
// Before this i'd make a call to a function that draws a path to a passed in context
CGAffineTransform inverseTranslation = CGAffineTransformMakeTranslation( transX, transY );
CGAffineTransform translation = CGAffineTransformMakeTranslation( -transX, -transY );
CGAffineTransform rot = CGAffineTransformMakeRotation( 3.14 );
CGAffineTransform final = CGAffineTransformConcat( CGAffineTransformConcat( inverseTranslation, rot ), translation );
// Then i apply the transformation animation like normal using self.transform = final etc etc
I've also tried stuff like CGContextTranslateCTM and CGContextSaveGState/UIGraphicsPushContext, but these seem to have little effect.
I've been fighting with this for days and my current solution seems close, but i have no clue how to get rid of that translating tweening. Does anyone have a solution for this or a better way to go about this?
[update]
For the time being i'm drawing my image centered at the UIview's center and then setting the UIView.center property to the origin i'd like to rotate and then doing the rotate command. Seems like a bit of a hack, but until i can get the real translates working it's my only choice.
Thanks!
duncanwilcox' answer is the right one, but he left out the part where you change the anchor of the view's layer to the point you want to rotate around.
CGSize sz = theview.bounds.size;
// Anchorpoint coords are between 0.0 and 1.0
theview.layer.anchorPoint = CGPointMake(rotPoint.x/sz.width, rotPoint.y/sz.height);
[UIView beginAnimations:#"rotate" context:nil];
theview.transform = CGAffineTransformMakeRotation( 45. / 180. * M_PI );
[UIView commitAnimations];
This is documented here: http://developer.apple.com/documentation/Cocoa/Conceptual/CoreAnimation_guide/Articles/Layers.html
This is also an option: a simple change of basis ;-)
CGAffineTransform transform = CGAffineTransformMakeTranslation(x, y);
transform = CGAffineTransformRotate(transform, angle);
transform = CGAffineTransformTranslate(transform,-x,-y);
where (x,y) is the rotation center you like
Rotation happens around the anchorPoint of the view's layer. The default for the anchorPoint is the center (0.5, 0.5), so the rotation alone without the translations should suffice.
Did a quick test and this works for me:
[UIView beginAnimations:#"rotate" context:nil];
self.transform = CGAffineTransformMakeRotation( 45. / 180. * 3.14 );
[UIView commitAnimations];
If you don't want an animation to occur, but just set the new rotation, you can use this:
CGFloat newRotation = 3.14f
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.0]; // no tweening
CGAffineTransform transform = CGAffineTransformMakeRotation(newRotation);
self.transform = transform;
[UIView commitAnimations];
The rotation should indeed take place around the center of the UIView. Setting the animationDuration to zero garantees no tweening should happen.
Be sure though you don't do this 60 times a second. It's very tempting to create game like animations with these tools. These kind of animations aren't exactly meant for a frame to frame based, "lots of sprites flying everywhere" game.
For that - and I've been down that road - the only way to go, is OpenGL.