How to move and rotate object in iphone - iphone

I am developing a small game in iphone... Game concept is place an object in top of the bar...Rotating a bar using accelerometer. When bar rotating , i need to move an object with respect to bar. How to implement this concept...Any examples or references?
Rotating both img:
barImg,objImg //UIImageView
barImg.transform = CGAffineTransformMakeRotation(Ypos);
objImg.transform=CGAffineTransformMakeRotation(Ypos);

So for rotating 360 Degree with animation:
CABasicAnimation *rotationAnimation;
rotationAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.z"];
rotationAnimation.toValue = [NSNumber numberWithFloat:-M_PI * 2.0]; // full rotation*/ * rotations * duration ];
rotationAnimation.duration = 1;
rotationAnimation.cumulative = YES;
rotationAnimation.repeatCount = MAXFLOAT;
[rotatingTelIamgeview.layer addAnimation:rotationAnimation forKey:#"rotationAnimation"];
you can play with toValue for changing the angle.
For moving an object:
CGPoint startPoint = CGPointMake(lvMessageInputBar.animationBubbleImageView.layer.frame.origin.x+lvMessageInputBar.animationBubbleImageView.layer.frame.size.width/2
, lvMessageInputBar.animationBubbleImageView.layer.frame.origin.y +lvMessageInputBar.animationBubbleImageView.layer.frame.size.height/2 );
CGPoint endPoint = CGPointMake(endPoint.origin.x+Endpoint.size.width/2, bubleRect.origin.y+bubleRect.size.height/2);
CGPoint middlePoint = // any point between start and end corrdinates
CGMutablePathRef path = CGPathCreateMutable();
CGPathMoveToPoint(path, NULL, startPoint.x, startPoint.y);
CGPathAddQuadCurveToPoint(path, NULL,middlePoint.x, middlePoint.y,endPoint.x,endPoint.y);
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.delegate = self;
pathAnimation.removedOnCompletion = NO;
pathAnimation.path = path;
[pathAnimation setCalculationMode:kCAAnimationCubic];
[pathAnimation setFillMode:kCAFillModeForwards];
pathAnimation.duration = 0.3;
[lvMessageInputBar.animationBubbleImageView.layer addAnimation:pathAnimation forKey:nil];
The above example moves the layer of the object over a path.but CGPathAddQuadCurveToPoint makes the path not diagonal rather circular path (curve).
you can use CGPathAddPath if you do not want this effect.
If you are new to iPhone I would start with layer tutorial to get the idea behind CALayer and then take a look CALayer animations
CALayers introduction:
https://www.raywenderlich.com/3096-calayers-tutorial-for-ios-introduction-to-calayers
CALayer Animation documentation of from Apple:
https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreAnimation_guide/Introduction/Introduction.html
You can also watch Session 424 (Core Animation in Practice, Part 1) and 425 (Core Animation in Practice, Part 2) of WWDC 2010:
https://developer.apple.com/videos/archive/

Related

Flipping two UIView using CATransform3D

I have created Visiting Card which has Front view & back View. When i tap on the front view it should flip the UIView & show the back side of the View.
Here is Code which I am trying:
CATransform3D transform = CATransform3DMakeRotation(M_PI, 0, 1, 0);
transform.m34 = 1.0/700.0;
CABasicAnimation *rotation = [CABasicAnimation animationWithKeyPath:#"transform"];
rotation.fromValue = [NSValue valueWithCATransform3D:CATransform3DIdentity];
rotation.toValue = [NSValue valueWithCATransform3D:transform];
rotation.duration = DURATION;
CABasicAnimation *translation = [CABasicAnimation animationWithKeyPath:#"position"];
translation.fromValue = [NSValue valueWithCGPoint:CGPointMake(self.imageview.center.x,[[self.imageview superview] center].y-45)];
translation.toValue = [NSValue valueWithCGPoint:CGPointMake(_frame.origin.x+_frame.size.width/2,
_frame.origin.y+_frame.size.height/2)];
translation.duration = DURATION;
CABasicAnimation *translation = [CABasicAnimation animationWithKeyPath:#"position"];
translation.fromValue = [NSValue valueWithCGPoint:CGPointMake(self.imageview.center.x,[[self.imageview superview] center].y-45)];
translation.toValue = [NSValue valueWithCGPoint:CGPointMake(_frame.origin.x+_frame.size.width/2,
_frame.origin.y+_frame.size.height/2)];
translation.duration = DURATION;
CAAnimationGroup *group = [CAAnimationGroup animation];
group.animations = #[ translation, rotation ];
group.duration = DURATION;
group.delegate = self;
group.fillMode = kCAFillModeForwards;
group.removedOnCompletion = NO;
[layer addAnimation:group forKey:nil];
Above code works perfectly for single view. How to combine the 2nd view to get flipping from front & back effect.
Using Core Animation
You can add both front and back to a container view. The back view will have a 180 degree rotation around Y and the front will be just normal. Both layers will be single sided (by setting layer.doubleSided = NO;.
Then when you apply the rotation you would animate the rotation of the container view so that both front and back animate at the same time.
UIView transitions
Or you could just use the built in flip animation
transitionFromView:toView:duration:options:completion:
and pass either UIViewAnimationOptionTransitionFlipFromLeft or UIViewAnimationOptionTransitionFlipFromRight for the option.

Manipulating UIImageView During Animation with CAKeyframeAnimation

I need to move object (UIImageView) from point A to point B, then rotate image at point B by 180 degrees to face the opposite direction and move object from B to A (backwards).
I have the code below which moves from A to B. I also know how to rotate UIImageView. But how to know when object has reached point B and how to apply rotation action considering there are many objects on the screen?
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.duration = speed;
pathAnimation.calculationMode = kCAAnimationPaced;
pathAnimation.fillMode = kCAFillModeForwards;
pathAnimation.removedOnCompletion = NO;
CGMutablePathRef pointPath = CGPathCreateMutable();
CGPathMoveToPoint(pointPath, NULL, rect.origin.x, rect.origin.y);
CGPathAddLineToPoint(pointPath, NULL, x, y);
pathAnimation.path = pointPath;
CGPathRelease(pointPath);
[imageView.layer addAnimation:pathAnimation forKey:[NSString stringWithFormat:#"pathAnimation%#",objId]];
[imageView release];
Set a delegate on the CAAnimation object, and in the delegate implement the animationDidStop:finished: method.
OTOH, the animation you described sounds like it could be done easily enough with UIView's animation support. See Animating Views with Blocks if you're targeting 4.0 and up, or Animating Views if you're still targeting earlier versions.
You can use the CAAnimation delegate method
-(void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag

Why CABasicAnimation will send the layer's view to back and front?

There are two UIViews of similar size. UIView one (A) is originally on top of UIView two (B). When I try to perform a CABasicAnimation transform.rotation.y on A's layer:
CABasicAnimation *rotateAnimation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
CGFloat startValue = 0.0;
CGFloat endValue = M_PI;
rotateAnimation.fromValue = [NSNumber numberWithDouble:startValue];
rotateAnimation.toValue = [NSNumber numberWithDouble:endValue];
rotateAnimation.duration = 5.0;
[CATransaction begin];
[imageA.layer addAnimation:rotateAnimation forKey:#"rotate"];
[CATransaction commit];
During the animation, the animating layer's UIView (A) will be:
sent back (A is suddenly behind B)
rotating ... passed second half of the animation
sent front (A is now on top of B again)
Is there a way to keep A on top of B for the whole animation period? Thanks!
UPDATE: project source is attached: FlipLayer.zip
The problem is a rotation around the Y axis will, in a true 3D compositing system, make layer A intersect with layer B, such that half of layer A should be visible and half should be behind layer B. CoreAnimation does not provide a true 3D compositing system. Instead it attempts to determine which layer is in front of which other layer, and renders it entirely without intersection. In your case, during the first half of the rotation CoreAnimation has decided that layer B is on top of layer A in the 3D space. The simplest solution is probably to set the zPosition of layer A to layer.bounds.size.width (default is 0) for the duration of the animation (or permanently, if it should always be on top).
If you want to set it only for the duration of the animation, you can add a second animation for the transform.translation.z key path. Here's your -flip method modified to use this:
- (IBAction)flip:(id)sender {
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
CGFloat startValue = 0.0;
CGFloat endValue = M_PI;
animation.fromValue = [NSNumber numberWithDouble:startValue];
animation.toValue = [NSNumber numberWithDouble:endValue];
animation.duration = 5.0;
[imageOne.layer addAnimation:animation forKey:#"rotate"];
animation.keyPath = #"transform.translation.z";
animation.fromValue = [NSNumber numberWithFloat:imageOne.layer.bounds.size.width];
animation.toValue = animation.fromValue;
[imageOne.layer addAnimation:animation forKey:#"zPosition"];
}
Have you tried adding a [self.view bringSubviewToFront:imageA]; in your animation sequence?
You could try to translate on the z axis and bring A forward first. Perform the rotation and then set the z back to its starting value.
Also, you probably won't see any perspective on the rotation unless you set the .m34 property on the transform. Try something like this:
CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0f / -300.0f;
transform = CATransform3DRotate(transform, 0.0f, M_PI, 0.0f);
CABasicAnimation *rotateAnimation = [CABasicAnimation
animationWithKeyPath:#"transform"];
rotateAnimation.fromValue = [NSValue
valueWithCATransform3D(CATransformIdentity)];
rotateAnimation.toValue = [NSValue valueWithCATransform3D(transform)];
rotateAnimation.duration = 5.0;
[imageA.layer addAnimation:rotateAnimation forKey:#"rotate"];
You transaction block is unnecessary.
Best Regards.

UIView animation along a round path?

I need to make my little guy (in a UIIamgeView) jump forward and it has to look natural. I want to know is there a way to do it with CoreAnimation (beginAnimation/commitAnimation)?
I could do it by setting a point in between in the air but the movement looks not natural :P
Reading Brad Larson's post, I ended up with a nice function to make my image follow a circle.
You need to import QuartzCore framework: #import
Here is the code:
// Set up path movement
CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:#"position"];
pathAnimation.calculationMode = kCAAnimationPaced;
pathAnimation.fillMode = kCAFillModeForwards;
pathAnimation.removedOnCompletion = NO;
pathAnimation.repeatCount = INFINITY;
//pathAnimation.rotationMode = #"auto";
pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
pathAnimation.duration = 5.0;
// Create a circle path
CGMutablePathRef curvedPath = CGPathCreateMutable();
CGRect circleContainer = CGRectMake(0, 0, 400, 400); // create a circle from this square, it could be the frame of an UIView
CGPathAddEllipseInRect(curvedPath, NULL, circleContainer);
pathAnimation.path = curvedPath;
CGPathRelease(curvedPath);
[self.imageView.layer addAnimation:pathAnimation forKey:#"myCircleAnimation"];
Create a CAKeyframeAnimation and assign a CGPath to its path property.
To follow up on Ole's answer, my answer to this question provides code to perform such a curved animation using a CAKeyframeAnimation.

Failed Attempt to use Perspective Transformations in Core Animation

I'm trying to create a simple iPhone app that displays a picture with a reflection beneath, and I want to rotate the picture around the X axis, using Core Animation.
I've started by creating a new iPhone app using the "View-based Application" template. I added a "Picture.jpg" image file, and then I added this to the view controller:
- (void)awakeFromNib {
CGFloat zDistance = 1500.0f;
// Create perspective transformation
CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0f / -zDistance;
// Create perspective transform for reflected layer
CATransform3D reflectedTransform = CATransform3DMakeRotation(M_PI, 1.0f, 0.0f, 0.0f);
reflectedTransform.m34 = 1.0f / -zDistance;
// Create spinning picture
CALayer *spinningLayer = [CALayer layer];
spinningLayer.frame = CGRectMake(60.0f, 60.0f, 200.0f, 300.0f);
spinningLayer.contents = (id)[UIImage imageNamed:#"Picture.jpg"].CGImage;
spinningLayer.transform = transform;
// Create reflection of spinning picture
CALayer *reflectionLayer = [CALayer layer];
reflectionLayer.frame = CGRectMake(60.0f, 360.0f, 200.0f, 300.0f);
reflectionLayer.contents = (id)[UIImage imageNamed:#"Picture.jpg"].CGImage;
reflectionLayer.opacity = 0.4f;
reflectionLayer.transform = reflectedTransform;
// Add layers to the root layer
[self.view.layer addSublayer:spinningLayer];
[self.view.layer insertSublayer:reflectionLayer below:spinningLayer];
// Spin the layers
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
anim.fromValue = [NSNumber numberWithFloat:0.0f];
anim.toValue = [NSNumber numberWithFloat:(2 * M_PI)];
anim.duration = 3.0f;
anim.repeatCount = 1e100f;
[spinningLayer addAnimation:anim forKey:#"anim"];
[reflectionLayer addAnimation:anim forKey:#"anim"];
}
This almost works. The problem is that the spinning of the main picture and of the reflection are not perfectly synchronized. It's very close to perfect, but the edges of the bottom of the picture and of top of the reflection are a few pixels apart. They appear to differ by a few degrees.
On the left side of the screen, the reflection seems to be "ahead" of the picture, and on the right side, the reflection is behind the picture. In other words, it looks like the bottom corners of the top image are pushed toward the screen, while the top corners of the reflection are pulled toward the viewer. This is true both when looking at the front and at the back of the images as they spin.
If I increase zDistance, the effect is less noticeable. If I eliminate the perspective transformations altogether by leaving transform.m34 equal to zero for both layers, then the picture and reflection look to be perfectly synchronized. So I don't think the problem is related to time-synchronization issues.
I suspect my perspective transformations are missing something, but I'm not sure how to determine what's wrong. I think I'm basically doing the same transformation described in this related Stack Overflow question.
Can someone help?
I think I may have found an answer to my question. In my original code, I created the reflection by placing it underneath the picture, and applying the flip and perspective. The right way to do it seems to be to place the reflection at the same position as the picture, apply translation and rotation transforms to get it to the right place, and then apply the perspective transformation.
When animating the spin, it is necessary to spin the reflection in the opposite direction of the picture's animation.
So, here's code that works:
- (void)awakeFromNib {
CGFloat zDistance = 1500.0f;
// Create perspective transformation
CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0f / -zDistance;
// Create perspective transform for reflected layer
CATransform3D reflectedTransform = CATransform3DMakeTranslation(0.0f, 300.0f, 0.0f);
reflectedTransform = CATransform3DRotate(reflectedTransform, M_PI, 1.0f, 0.0f, 0.0f);
reflectedTransform.m34 = 1.0f / -zDistance;
// Create spinning picture
CALayer *spinningLayer = [CALayer layer];
spinningLayer.frame = CGRectMake(60.0f, 60.0f, 200.0f, 300.0f);
spinningLayer.contents = (id)[UIImage imageNamed:#"Picture.jpg"].CGImage;
spinningLayer.transform = transform;
// Create reflection of spinning picture
CALayer *reflectionLayer = [CALayer layer];
reflectionLayer.frame = CGRectMake(60.0f, 60.0f, 200.0f, 300.0f);
reflectionLayer.contents = (id)[UIImage imageNamed:#"Picture.jpg"].CGImage;
reflectionLayer.opacity = 0.4f;
reflectionLayer.transform = reflectedTransform;
// Add layers to the root layer
[self.view.layer addSublayer:spinningLayer];
[self.view.layer insertSublayer:reflectionLayer below:spinningLayer];
// Spin the layers
CABasicAnimation *anim = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
anim.fromValue = [NSNumber numberWithFloat:0.0f];
anim.toValue = [NSNumber numberWithFloat:(2 * M_PI)];
anim.duration = 3.0f;
anim.repeatCount = 1e100f;
[spinningLayer addAnimation:anim forKey:#"anim"];
CABasicAnimation *reflectAnim = [CABasicAnimation animationWithKeyPath:#"transform.rotation.y"];
reflectAnim.fromValue = [NSNumber numberWithFloat:0.0f];
reflectAnim.toValue = [NSNumber numberWithFloat:(-2 * M_PI)];
reflectAnim.duration = 3.0f;
reflectAnim.repeatCount = 1e100f;
[reflectionLayer addAnimation:reflectAnim forKey:#"reflectAnim"];
}
I'm not sure exactly why this works. It makes intuitive sense to me that placing the reflection at the same position as the original and then transforming it somehow puts the two images into the same "transformation space", but I'd appreciate it if someone could explain the mathematics behind this.
The full project is available at GitHub: https://github.com/kristopherjohnson/perspectivetest
You can use a CAAnimationGroup object to run two animations on the same time space. That should take care of any synchronization issues.
EDIT: removed silly code.