How to implement a D-Pad Xcode 5 on an iPad - ios

I have tried many times to implement a D-Pad for my new maze game, but am having trouble doing so. I am doing it in the style of 4 UIButtons and if you press one, it moves another image up, down, left or right. I have tried using the quartzcore and CAAnimation, but only know limited code.
I have the methods and the buttons declared, but cannot code a working one.
I was doing:
-(IBAction)Up:(id)sender{
CGPoint origin1 = self.Player.center;
CGPoint target1 = CGPointMake(self.Player.center.x, self.Player.center.y-124);
CABasicAnimation *bounce1 = [CABasicAnimation animationWithKeyPath:#"position.y"];
bounce1.duration = 0.1;
bounce1.fromValue = [NSNumber numberWithInt:origin1.y];
bounce1.toValue = [NSNumber numberWithInt:target1.y];
[self.Player.layer addAnimation:bounce1 forKey:#"position"];
}
The ghost moves down, but bops back up immediately. I've been stumped for hours and it may be glaring me in the face, but please understand my noobishness.

In Core Animation, there are two layer hierarchies: one of model layers and one of presentation layers. Presentation layers are what you see; model layers are what you often interact with in code. This separation is valuable because it lets you create implicit animation -- e.g. set the position of a layer, and it'll animate to the new spot. (But if you assign a value to position, you want that to be the value you read back immediately thereafter, even if the animation is still in progress.)
When you use addAnimation:forKey:, you're affecting the presentation, not the model. So, during the animation, you see the Player layer moving, but that layer is "really" still where you left it. As soon as the animation ends, it's removed from the layer, so the presentation matches the model again -- you see it at its original position.
If you want the model position to change as well, you need to change it separately:
self.player.layer.position = CGPointMake(self.player.layer.position.x, target1.y);
You can either update the model immediately after adding the animation (you'll see the change after the animation completes), or use a completion block to schedule it at the end of the animation. There are subtleties to consider for either approach.
Often, though, if you just want to animate a specific change like that, especially for the main layer of a UIView, it's simpler to use the implicit animation API on UIView:
[UIView animateWithDuration:0.1 animations: ^{
self.player.center = CGPointMake(self.player.center.x, target1.y);
}];
This will both update the model value and create and run an animation for moving from the current position to the target position.
BTW: It helps to follow Cocoa code style conventions: use initial caps only for class names or other type names, and lowercase for variable/property/method names.

Related

How do I set fire to a UIView in Swift?

How do I produce an animation that simulates the burning effect of fire consuming an UIView from top to bottom in Swift?
I found Fireworks, an app that allows users to tweak and try out different settings of CAEmitterLayer with instant results. The effects are great for applying to a whole screen but how would I use it for my purpose - where the UIView must disappear as the fire consumes it from one end to the other?
Is there some tutorial on consuming UIViews with fire using the particle emitter anywhere? I know that I’m supposed to show some code but anything I put here would be irrelevant. I’ve also exhausted my search engine looking for something similar. That’s how I found the Fireworks app actually.
This seems to be a use case that shouldn't be uncommon.
I haven't done much with CAEmitterLayer, so I decided to try my hand at this.
I created a project that does this an posted it on Github. It uses the approach in this Youtube video as a starting point. You can download it here:
FireEmitter project
Here is a small thumbnail of what it looks like:
The project includes a custom subclass of UIView called BurnItDownView
The BurnItDownView is meant to contain other views.
It has one public method, burnItDown(). That triggers the animation.
There are multiple parts to the animation:
A CAEmitterLayer set up to simulate flames burning off a flat surface:
An animation that lowers the emitter layer from the top of the view to the bottom,
A CAGradientView applied as a mask to the view that starts ot fully opaque (with colors of [.clear, .white, .white] and locations of [-0.5, 0, 1] (where the clear color is above the top of the view) and animates the locations property of the gradient view to mask away the view contents from top to bottom. (Animating the locations property to [0, 0, 0], so the entire gradient layer is filled with clear color, fully masking the view's layer.)
Once the view is fully masked, it starts lowering the "birthRate" of the emitter layer in steps until the birth rate is 0. It then holds this step for 2 seconds until all the flame particles have animated away.
Once the flame is fully "extinguised", it resets the locations array to the original value of [-0.5, 0, 1]. This causes an "implicit animation" so the view animates back from the bottom, but quickly
Finally, it resets the emitter layer and emitter cells back to newly a newly created emitter layer and emitter cell to get it ready for the next pass of the animation. (I couldn't figure out how to restore the emitter back to its original state. It was simpler to just create new ones.) It also invokes an Optional completion handler passed to the burnItDown() method. (The app's view controller uses the closure to re-enable the "Burn it down" button.
I was once in your shoe before and came across this Open source library called particle animations.
I would NOT recommend using the library itself since it's deprecated. But I would recommend referring to its source code to get an idea of how to use CAEmitterLayer and CAEmitterCell to make the looks of a Fire!
As you could see from its readme, it has direct examples of Fire. It also states that even Apple and Facebook uses CAEmitterLayer and CAEmitterCell to produce the effect of a fire.
Feel free to ask for more questions.

iOS - How to make an animation track touches

What is the best way to implement a smooth reversing animation which tracks touches? I am referring to those animations in which, for example, if the user executes a swipe gesture some elements smoothly animate on screen, and others off, but if the user instead slowly drags a pan gesture back and forth the same objects will move forward/backward as a percent in accordance with the touch position. This is seen in many app intros and also in transitions. I have found
One tutorial which discusses the built-in facility for this but it is only between view controller transitions, not providing the full granular control I see in many apps (http://www.doubleencore.com/2013/09/ios-7-custom-transitions/)
Jazzhands, which is a kit by IFTTT, but this is a packaged solution that might not cover how the solution is best implemented at a lower level (https://github.com/IFTTT/JazzHands)
A question here for which one answer shows how you might execute an animation after a gesture ends (iOS Touch, Gestures, Animation)
What I don't grasp - and I'm comfortable using CAAnimations and gestures - is how something can be both animated and interactive.
Typically, when I create an animation, I commit the animation and it goes from start to finish. While I could interrupt the animation as touches continue, that seems like it would be stilted.
On the other hand, moving things in response to user input is easy, but that is not animated.
How is the effect achieved where something can change according to an animation, but also have that exact same animation occur tied to touches, and yet still also have it so that although the animation reaches completion it doesn't really "finish" (become irreversible) unless the user releases touch, while at any point during interaction if the user releases panning then the animation either reverts backwards to its starting position or animates to completion depending on the last touch location and velocity. These requirements are baffling.
The glimpses of this technique I see all involve keyframe animations, but what I don't understand is where the touch events intersect with an animation to create these smooth effects I see.
Any tips, examples, or tutorials are most welcome.
What I don't grasp - and I'm comfortable using CAAnimations and gestures - is how something can be both animated and interactive.
It is because, having set up an animation, you can set that animation to any "frame" you wish. Thus you can track the animation in correspondence to the movement of a gesture.
The way this works is that an animation is a feature of the render tree, belonging to a CALayer. CALayer implements the CAMediaTiming protocol. The timeOffset of a CALayer thus determines what "frame" of an animation that layer displays. If a complex animation involves many different layers, no problem; just set the timeOffset of their mutual superlayer, to control the frame of the entire animation.
That in fact is exactly how the new iOS 7 interactive custom transition feature works (to which you rightly refer in your question). For instance, in this example code:
https://github.com/mattneub/Programming-iOS-Book-Examples/blob/master/iOS7bookExamples/bk2ch06p296customAnimation2/ch19p620customAnimation1/AppDelegate.m
... I keep updating the UIPercentDrivenInteractiveTransition to tell it how far through the gesture the user is, and the animation therefore tracks the gesture. Now ask yourself: how the heck is this possible???
Well, the UIPercentDrivenInteractiveTransition, in turn, behind the scenes, keeps adjusting the layer's timeOffset to portray the animation at the corresponding frame. (You can actually add logging code to my example to see that this is true.)
Moreover, when I end the gesture at an incomplete point, the animation either hurries to its end or runs backwards to its beginning - again, this is because of the CAMediaTiming protocol, which lets you change the speed of the animation, including a negative value to run it backwards.

How to make UI object responsive after CABasicAnimation

I'm having trouble trying to find a way to make my UI object (UISegmentedControl) touch responsive after a CABasicAnimation slide in and bounce. How can I pull this off?
I know the UI object is in the presentation tree after the move. But I really like the setTimingFunction feature CABasicAnimation provides and I just won't be able to get such a smooth bounce using UIView animation.
Example GIF of animation (Looped):
Code I'm using inside viewDidLoad
CABasicAnimation *startAnimation = [CABasicAnimation animationWithKeyPath:#"transform.translation.y"];
[startAnimation setFromValue:[NSNumber numberWithFloat:0]];
[startAnimation setToValue:[NSNumber numberWithFloat:slidingUpValue]];
[startAnimation setDuration:1.0];
startAnimation.fillMode = kCAFillModeForwards;
startAnimation.removedOnCompletion = NO;
[startAnimation setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:0.0 :0.0 :0.3 :1.8]];
[[gameTypeControl layer] addAnimation:startAnimation forKey:nil];
What went wrong
The problem is these two lines of code and not understanding the side effects of using them:
startAnimation.fillMode = kCAFillModeForwards;
startAnimation.removedOnCompletion = NO;
The first line configures the animation to keep showing the end value after the animation has completed (you can see a visualization of fillMode and the other timing related properties in my little cheat sheet).
The second line configures the animation to stay attached to the layer after it finishes.
This sounds just fine at first, but is missing an essential part of Core Animation: animations added to a layer never affect the model, only the presentation. The Core Animation Programming Guide mention this on the second page of the section "Core Animation Basics":
The data and state information of a layer object is decoupled from the visual presentation of that layer’s content onscreen.
Animations happen on a separate layer called the presentation layer which is what you see on screen. If you print out the values of the animated property during the animation they don't change at all.
During the animation you have a difference between the presentation and the model but the animation is probably short and that difference will go away as soon as the animation finishes, so it doesn't really matter... unless the animation doesn't go away. Then the difference has persisted and now you have to deal with having out-of-sync data in two places.
How not to solve this issue
One could say that everything looks good, it's just that hit testing is wrong. Let's patch hit testing! Change the hit testing to use the segment control's layer's presentation layer and hit testing will work. Great, right? This would be like putting one plaster on top of another instead of solving the problem at its origin.
How to get rid of the side effects
It's really simple: don't use those lines and remove animations when they are finished. One might say that this technique (not removing an animation) has been used by Apple in slides and sample code so it's what Apple recommends, but there is a subtle detail that is easily missed:
When Apple introduced Core Animation at WWDC 2007 they used this technique to animate layers being removed (for example, fading out). Quote below is from Session 211 - Adding Core Animation to Your Application:
To animate layer removal, use animations with
fillMode = forwards, removedOnCompletion = NO
Animation delegate can remove the layer
In this case it's perfectly fine to not remove the animation since it could cause the layer to jump back to it's original size, opacity, etc. for one frame before being removed from the layer hierarchy. As they said in the above slide: the "animation delegate can remove the layer" (that is: do the clean up).
In other cases no one does the clean up and you are left with the mess of having out of sync data in two places (as mentioned above).
The solution is a different approach to the animation
When building animations, I try to think of like this:
If your animation mysteriously went away, the model value should be the expected end state.
Applied to your example, the segmented control is moving towards it's final position to stop there and stay there. In that case the actual position of the segmented control should be the end position. The application should work even if the animation isn't there.
So what about the animation? Instead of animating from 0 offset to some offset, you reverse that and animate from some negative offset to 0 offset.
CABasicAnimation *startAnimation = [CABasicAnimation animationWithKeyPath:#"transform.translation.y"];
[startAnimation setFromValue:#(-slidingUpValue)]]; // these two changed
[startAnimation setToValue:#(0.0)]; // places with each other
[startAnimation setDuration:1.0];
// no fill mode
// animation is removed on completion
[startAnimation setTimingFunction:[CAMediaTimingFunction functionWithControlPoints:0.0 :0.0 :0.3 :1.8]];
[[gameTypeControl layer] addAnimation:startAnimation forKey:#"Move in game type control from bottom"]; // I like adding descriptive keys for easier debugging

CABasicAnimation speed -- Keeping up with user input

Update: It really was as simple as not animating the UI element when utilizing touches. It perfectly follows touches now with no lag.
I'm currently attempting to implement a UI feature by implementing a CALayer subclass inside of a UIView subclass. I receive touch events in the custom UIVIew's corresponding view controller, notify the UIView about the touches, which in turn notifies the CALayer in order to animate the UI elements drawn in the layer.
It all works, but I have noticed that when there is a big delta in movement (as in when quickly scrolling a finger), the CABasicAnimation lags behind. Ideally I want the animation to stay perfectly aligned with the user's finger.
I've come up with a hacky way of just setting the animation's speed arbitrarily high as in
anim.speed = 10.0f;
which essentially keeps up with the user's finger, but I feel that this is a total hack and not a shippable solution. Should I be artificially limiting how many touch events are processed in order to solve this problem? Is there some sort of calculation I should be doing for the speed/duration of the animation that I'm not aware of?
Thanks for any help with this!
During the continuous gesture, one shouldn’t animate movements, but rather just move directly to the gesture’s location. When the gesture finishes, if you want it to settle in some other position, then animate that final, post-gesture, destination. But don’t animate during the gesture itself.
In rare cases, where rendering of a single frame is incredibly slow, there can still be perceived lagginess. Obviously, one should optimize the draw(_:) process so that it isn’t slow (or take a snapshot and animate the snapshot view rather than the complicated view). But during the gesture, you can also use “predictive touches,” where the OS estimates where user’s gesture is going to be in the future. For example, you can implement touchesMoved(_:with:) and then call predictedTouches(for:). By moving the view to the predicted touch location, it reduces perceived lagginess.

Is it possible to control a CAAnimation's timeline?

I have a complex animation that usually runs just by itself, driven by a certain CAMediaTimingFunction. This works fine.
Now, I want to control that same animation's time(line) using an external value, for example from a slider or a gesture recognizer. In other words, I don't want to have the "clock" drive the timeline, but a slider, so one can scrub back and forth with it and "freeze" the animation by putting the slider to a certain value.
Is this possible? If so, how?
It's possible (and quite easy), but I only tried this as an experiment (for a complex animation driven by a pinch gesture recognizer), so I'd love to hear if this solution is sufficient:
You need to set the speed of your animation to 0 and the time offset to the point in time you want to jump to, e.g.
CABasicAnimation* animation = [CABasicAnimation ...];
animation.speed = 0;
animation.duration = 1;
animation.timeOffset = 0.5;
will make the animation jump to the point it would be after half a second.
Now, you can't manipulate CAAnimation objects after they've been added to the layer, so you'll need to add a new animation every time the offset changes (and remove the old one, don't forget ;).

Resources