How do I control animation timing along a NSBezier path? - objective-c

In Apple's docs about CAKeyframeAnimation they say:
"For most types of animations, you specify the keyframe values using
the values and keyTimes properties. During the animation, Core
Animation generates intermediate values by interpolating between the
values you provide. When animating a value that is a coordinate point,
such as the layer’s position, you can specify a path for that point to
follow instead of individual values. The pacing of the animation is
controlled by the timing information you provide."
What I want to do is to make an animation of an image along the path above while controlling the timing. More specific, the path starts at (0,0) and goes to (100,0) during 1 sec, then follows a half-circle path to point (300,0) during 3 sec, and the goes to point (400,0) during 1 sec.
I have already definied this path as a NSBezier path and I can make the animation, but I don't know how to control the timing of the different parts of the path. From Apple's docs it seems that this should be possible, but how?

Get reference from here Controlling Animation Timing

There is a simple solution. The only thing you have to choose are the points on your path that you want to use for time control. In my case I have 4 points p0=(0,0), p1=(100,0), p2 =(200,0), and p3 =(300,0). I then use
animation.values = #[[NSValue valueWithPoint:p0],
[NSValue valueWithPoint:p1],
[NSValue valueWithPoint:p2],
[NSValue valueWithPoint:p3]];
animation.keyTimes = #[#0.0, #0.2, #0.8, #1.0];
The fact that we are using a half circle (or any other complicated) path DOES NOT have any influence (as long as it doesn't cross itself). You just choose some points on the path, use them to define animation.values, and then choose (relative) times for those points and use them to define animation.keyTimes. That's all, really.

Related

change CAMetalLayer background color

My CAMetalLayer background color is black, even if i'm assigning new color as the backgroundColor property.
Am i missing something? Thanks!
Link to the original project :
https://github.com/audiokit/MetalParticles
This project takes a rather unconventional approach to clearing the drawable's texture each frame: it replaces the textures contents with an array of zeros that is the same size as the texture (width * height * 4). Subsequently, it encodes some compute work that actually draws the particles. This is almost certainly not the most efficient way to achieve this effect, but if you want to make the smallest change that could possibly work (as opposed to experimenting with making the code as efficient as possible), Just fill the blankBitmapRawData array with your desired clear color (near line 82 of ParticleLab.swift).
I have gone through your code and can not see a place where you are setting background Color.
The metal layer is added as a sublayer to it, so you have to set it explicitly.
Add this line at the end of your init method in ParticialLab class and see if it works.
self.backgroundColor = UIColor.redColor().CGColor
I found that self.isOpaque = false was needed on the layer.

How to make an SKNode continue in the same direction after finishing following a path

In my project I have an SKNode following a CGPathRef made with touchesMoved. What I want to have happen is once it reaches the end of the CGPathRef, it follows in the same direction that it ended in. I am using the SKAction followPath and tried to implement this by adding a line from the last point on the path (touchesEnded) all the way to the end of the scene using some previous points and a unit vector however this was not only complicated but also very inconsistent. Is there another method I can use to make it just continue on its path after it finishes the CGPath? Thanks!
I suggest storing your node's CGVector (dx, dy) which represents the direction of movement for your node. For example, if the last moving vector was 15,15 that translates to your node having moved up and to the right. You can use this value to continue moving. If the values are too low or too high, you can add a min/max filter.

How to detect/handle touch events on curved regions?

I'm starting on a native iPad app (we can assume iOS 4.3+ if necessary) where I need to have a series of curved regions that bump up against each other.
I'd love some advice about the best way to handle this.
One thought I had was to use a WebView and just have a JPG and an HTML image map but I'd really prefer to use some kind of native UI element that supports curves.
Any recommendations?
We had a problem something like this. To resolve it, we created a black and white mask in Adobe Illustrator. You'll need to do this for each and every distinct region that you want.
Next, we exported this file. I can't remember the file export option, but basically you get a text file that has a load of path data that includes lines, bezier curves, etc.
We then took this file and wrote an importer that parsed it and created a CGPath.
The final stage is the easy bit. You get your touch point from UITouch and do a CGPathContainsPoint call.
Here's some pseudo code for this:
Skip lines until we get to one with "1 XR". That's the
indication of something meaningful in the subsequent line.
Split the line into an array of components using a separator of " ".
The last component of the line is the action. If it's "m" it's a path move, if it's "C", it's a bezier curve, and if it's "L" it's a line.
If it's a "Y" or a "V" then you need to get the previous line's components and parse as follows:
(a) Component count includes action, so we need to reduce this. E.g. 274.5600 463.6800 m
(b) If this line has four coordinates and the previous one has two, then it's a point node to a bezier node. Figure your bezier curve points as follows:
cp1x = previous line's components object at index 0
cp1y = previous line's components object at index 1
cp2x = this line's components object at index 0
cp2y = this line's components object at index 1
x = this line's components object at index 2
y = this line's components object at index 3
(c) Otherwise if this line has four coordinates and the previous line has four or six coordinates, figure as follows:
cp1x = this line's components object at index 0
cp1y = this line's components object at index 1
cp2x = this line's components object at index 2
cp2y = this line's components object at index 3
x = this line's components object at index 2
y = this line's components object at index 3
Where cp is "control point". So you have control point one and control point two with their respective x and y coordinates.
Create bezier paths that each represent separate regions (by doing lineToPoint or similar functions).
UIBezierPath *p1 = [UIBezierPath bezierPath];
[path1 lineToPoint:somePoint];
[pointArray1 addObject:NSStringFromCGPoint(somePoint)];
// create lots of points and close p1 path
Then find some triangulation algorithm for concave shapes that would turn each bezier path to an array of triangles (i.e. instead of storing array of bezier path point coordinates you'd store array of triangles' coordinates (array of array of points). Algorithm and explanations can be found in any game development forum or even on GameDev of stack exchange.
Repeat the bezier path creation and triangulation for each region.
Then having these arrays it's just a matter of simple iterations to check if certain point of interest is in one of these triangles.
update seems that #omz comment renders my answer useless, hence it's just a matter of creating bezier paths and calling method on each of them .)

Projectile hit coordinates at the apex of its path

I have a projectile that I would like to pass through specific coordinates at the apex of its path. I have been using a superb equation that giogadi outlined here, by plugging in the velocity values it produces into chipmunk's cpBodyApplyImpulse function.
The equation has one drawback that I haven't been able to figure out. It only works when the coordinates that I want to hit have a y value higher than the cannon (where my projectile starts). This means that I can't shoot at a downward angle.
Can anybody help me find a suitable equation that works no matter where the target is in relation to the cannon?
As pointed out above, there isn't any way to make the apex be lower than the height of the cannon (without making gravity work backwards). However, it is possible to make the projectile pass through a point below the cannon; the equations are all here. The equation you need to solve is:
angle = arctan((v^2 [+-]sqrt(v^4 - g*(x^2+2*y*v^2)))/g*x)
where you choose a velocity and plug in the x and y positions of the target - assuming the cannon is at (0,0). The [+-] thing means that you can choose either root. If the argument to the square root function is negative (an imaginary root) you need a larger velocity. So, if you are "in range" you have two possible angles for any particular velocity (other than in the maximum range 45 degree case where the two roots should give the same answer).
I suspect one trajectory will tend to 'look' much more sensible than the other, but that's something to play around with once you have something working. You may want to stick with the apex grazing code for the cases where the target is above the cannon.

Label and LabelAtlas comparison? LabelAtlas is hard to use

I have some confusion about how to use AtlasLabel. It seems Label consume a lot memory than LabelAtlas?
Such as if I create 100 line of text. Each of them is created by Label, then will it consume more memory than 100 line of text created by LabelAtlas?
Label *label1 = [[Label alloc] initWithString:#"text1" dimensions:CGSizeMake(0, 0) alignment:UITextAlignmentLeft fontName:#"Arial" fontSize:22];
.....
.....
Label *label100 = [[Label alloc] initWithString:#"text100" dimensions:CGSizeMake(0, 0) alignment:UITextAlignmentLeft fontName:#"Arial" fontSize:22];
will they be the same with
LabelAtlas *label1 = [LabelAtlas labelAtlasWithString:#"text1" charMapFile:#"abc_22c.png" itemWidth:34 itemHeight:40 startCharMap:' '];
........
.......
LabelAtlas *label100 = [LabelAtlas labelAtlasWithString:#"text100" charMapFile:#"abc_22c.png" itemWidth:34 itemHeight:40 startCharMap:' '];
I assume LabelAtlas is less expensive than Label since it uses just one image. Label creates likely an image each time it created.
I would like to convert all the text from label to labelAtlas. But I still don;t really understand how to use LabelAtlas deeply. I hardly display the string I want. I read number of examples. It seems simple but when I tried....It does not give me what I expect. Could you show me some example for displaying a long text using LabelAtlas instead of Label. I used LabelAtlas before for my point counter. But it is so hard now to display a long string. Thanks in Advance
The main difference between CCLabel and CCLabelAtlas is that the atlas version (like all the other atlas classes) uses one big texture with all the letters pre-rendered to draw a string. This means that the drawing is much faster, because if you draw 100 labels, the graphics processor doesn't have to read in 100 textures but just keep one texture in memory. But it also means that all the letters will be of a fixed size. If you want to get around the fixed-size limitation, use CCBitmapFontAtlas.
And, yes, CCLabel creates one texture for every label, whereas CCLabelAtlas renders the text on the fly, using the provided texture (containing all the characters), so using CCLabelAtlas results in lower memory consumption.
In general, try to always use the *Atlas versions of classes. You can start by using the non-atlas versions and then switch to the atlas version when you've progressed a bit and had time to generate the atlas bitmaps. Don't worry too much about it if you're just starting out.