On iOS, how can smooth animation be achieved? - ios

Is it true that for Angry Birds or Cut the Rope, they draw the whole frame of the whole screen first (the whole view), and then paint the whole frame onto the screen, making the animation smooth?
That's because if we animate a metal ball, of size 20 x 20 pixel, and if we erase the ball first, and then draw the ball at a new location, then there might be some flickering very subtle but noticeable.
The same might be if it is animated by drawRect, which will erase the whole screen, and then draw everything in their new locations, which might have even more flicker than above?
Going back to the drawing whole frame method: if a ball was at coordinate (100,100), and now the ball is painted on top of the whole screenshot (with the new background exposed), at coordinate (103, 100), then it is very unnoticeable for the changes. (no disappearing and then reappearing happening at all).
How can smooth animation be achieved that looks like Angry Birds or Cut the Rope game?

They make use of OpenGL, which is a lot faster than any of the Quartz methods (ie. drawRect) since it makes use of the GPU instead of the CPU for rendering. Using Quartz can be hundreds or thousands of times slower depending on what you are doing exactly.
If you do not want to resort to OpenGL. You can put the object inside a UIView and then animate it. As long as the contents of the view is static, this is plenty fast for most applications. For example, making the background a view, and the metal ball a view, you can move that view around and achieve very smooth animations without problems.

Use CALayers. They are more lightweight than views.

If an app uses OpenGL, the answer is yes, it does its rendering before the frame buffer is presented to the screen. I think the other ways to draw to the screen use the same technique of drawing to an off-screen buffer before transferring the completed image to the screen, but I'm not so sure about that.

Related

ccDraw. Fill screen everywhere except on sprite

So I am trying to get a very basic "flashlight"-style thing going in one of my games.
The way I was getting it to work, was having a layer on top of my game screen, and this layer would draw a black rectangle with ~ 80% opacity, creating the look of darkness on top of my game scene.
ccDrawSolidRect(ccp(0,0), ccp(480,320), ccc4f(0, 0, 0, 0.8));
What I want to do is draw this rectangle EVERYWHERE on the screen, except for around a cone of vision that will represent the "light source".
What this would create would be a dark overlay on top of everything except for the light, giving it the illusion of a torch/light/flashlight.
The only way I can foresee this happening is by using ccDrawSolidPoly(), but since the position of the light source changes, so would the vertices for the poly.
Any suggestions on how to achieve this would be great.
You can use ccDrawSolidPoly() and avoid having to manually update vertices. For this you can create a new subclass of CCNode representing your light object, and do your custom shape drawing in its -(void)draw method.
The ccDraw...() functions will draw relative to the local sprite coordinates, so you can then move and rotate your new sprite to suit your needs and cocos2d will do the vertices transformations for you.
Update: I found out that you might be better off subclassing CCDrawNode instead of CCNode, as it has some facilities for raw OpenGL drawing (OpenGL's vertexArrayBuffer and vertexBufferObject internal variables and a buffer for vertices, their colors and their texCoords). If your stuff is very simple, maybe subclassing the plain CCNode is enough.
Could a png be used instead as a mask, as the layer above
Like that binocular vision you sometimes see in cartoons?
Or a filter similar to a photoshop mask that darkens as it grows outwardly to wards the edge of the screen
Just a thought anyway...
A picture of more of what your trying to explain might be good too

Painting app with huge canvas

I'm working on yet another drawing app with canvas that is many times bigger than screen.
I need some advice/direction on how to that.
Basically what i want is to scroll around this big canvas, drawing only in visible region.
I was thinking of two approaches:
Have 64x64 (or whatever) "tiles" to draw on, and then on scroll just load new tiles.
Record all user strokes (points) and on scroll calculate which are in specified region, and draw them, using only screen-size canvas.
If this matters, i'm using cocos2d for prototype.
Forget the 2000x200 limitation, I have an open source project that draws 18000 x 18000 NASA images.
I suggest you break this task into two parts. First, scrolling. As was suggested by CodaFi, when you scroll you will provide CATiledLayers. Each of those will be a CGImageRef that you create - a sub image of your really huge canvas. You can then easily support zooming in and out.
The second part is interacting with the user to draw or otherwise effect the canvas. When the user stops scrolling, you then create an opaque UIView subclass, which you add as a subview to your main view, overlaying the view hosting the CATiledLayers. At the moment you need to show this view, you populate it with the proper information so it can draw that portion of your larger canvas properly (say a circle at this point of such and such a color, etc).
You would do your drawing using the drawRect: method of this overlay view. So as the user takes action that changes the view, you do a "setDisplayInRect:" as needed to force iOS to call your drawRect:.
When the user decides to scroll, you need to update your large canvas model with whatever changes the user has made, then remove the opaque overlay, and let the CATiledLayers draw the proper portions of the large image. This transition is probably the most tricky part of the process to avoid visual glitches.
Supposing you have a large array of object definitions used for your canvas. When you need to create a CGImageRef for a tile, you scan through it looking for overlap between the object's frame and the tile's frame, and only then draw those items that are required for that tile.
Many mobile devices don't support textures over 2048x2048. So I would recommend:
make your big surface out of large 2048x2048 tiles
draw only the visible part of the currently visible tile to the screen
you will need to draw up to 4 tiles per frame, in case the user has scrolled to a corner of four tiles, but make sure you don't draw anything extra if there is only one visible tile.
This is probably the most efficient way. 64x64 tiles are really too small, and will be inefficient since there will be a large repeated overhead for the "draw tile" calls.
There is a tiling example in Apples ScrollViewSuite Doesn't have anything to do with the drawing part but it might give you some ideas about how to manage the tile part of things.
You can use CATiledLayer.
See WWDC2010 session 104
But for cocos2d, it might not work.

Does shouldRasterize on a CALayer cause rasterization before or after the layer's transform?

I'm attempting to optimize my app. It's quite visually rich, so has quite a lot of layered UIViews with large images and blending etc.
I've been experimenting with the shouldRasterize property on CALayers. In one case in particular, I have a UIView that consists of lots of sub views including a table. As part of a transition where the entire screen scrolls, this UIView also scales and rotates (using transforms).
The content of the UIView remains static, so I thought it would make sense to set view.layer.shouldRasterize = YES. However, I didn't see an increase in performance. Could it be that it's re-rasterizing every frame at the new scale and rotation? I was hoping that it would rasterize at the beginning when it has an identity transform matrix, and then cache that as it scales and rotates during the transition?
If not, is there a way I could force it to happen? Short of adding a redundant extra super-view/layer that does nothing but scale and rotate its rasterized contents...
You can answer your own question by profiling your application using the CoreAnimation instrument. Note that this one is only available in a device.
You can enable "Color hits in Green and Misses Red". If your layer remains red then it means that it is indeed rasterizing it every frame.

Custom UIview free rotation too slow

Programming for iOS, I have a composite custom view consisting of many UIViews. Some UIViews in this composites are responsible for drawing shadow and others for some custom shading. The shadow and shading need to be redrawn upon rotation recognized by UIRotationGestureRecognizer. However the speed of the rotation is far from satisfactory. When I commented out setNeedDisplay, the rotational speed is fine. However, if I do call setNeedDisplay, even when I commented out everything in all drawRects for the shadow and shading views, the rotation still lags significantly.
Are there any recommendations to speed things up?
I can think of one possible solution: make sure the system calls drawRect less often while in rotation. But I do not know how to do this, nor do I know if this is the best solution. Any suggestion appreciated. Thanks.
Calling setNeedsDisplay: too often, especially every frame will always be slow. setNeedsDisplay runs on the CPU, not the GPU. Don't redraw views during rotation and zooming. Wait until the end of the animation, then call setNeedsDisplay: to "render" the final position.
Take a look at how various UIKit views handle large animations:
While MapKit zooms in, the map image scales and looks blurry. Once the zoom gesture stops it renders a new image at that scale. (In this case the image is downloaded from the internet, but it still illustrates the concept.)
ZoomingPDF Sample code (see apple developer docs) shows how zooming on PDFs doesn't render in realtime, but after the zooming finishes.
Hope this helps.

How Can I Animate The Significant Blurring of a Sprite

I am using Cocos2d on the iPad to create a small game. I would like to, purposely, significantly blur a sprite, and then fade it out.
Particularly, I was hoping to make a sprite containing text get blurry (like the ink was fading or soaking into the paper) and then ultimately disappear, as if by magic.
I know how to animate the fade process using Cocos2D actions.
How can I animate the process of a sprite becoming super blurry?
I do not think it is possible to do a blur effect with the default cocos2d actions/functions.
you might want to try this custom gaussian blur class out instead
http://www.cocos2d-iphone.org/forum/topic/6315
the code is in the middle of the thread
or a more troublesome alternative is to create the blur effect using frame by frame animation

Resources