I have created a project .
and there are three groups of images need to display , and every group has 5 images .
In the app , the image will be changed once per 0.2 seconds .
and the size of the image is only 30*30 , so there are about 80 images on screen , they all have the animation .
But when I test this , I feel the fps seems become 0.8 seconds , it was very slow .
All the images are drawn in ONE UIView . I use [image drawInRect:] in the method -(void)drawRect .
So is there any suggestions for me to make the fps more faster ?
Have you tried putting 80 UIImageViews on the screen? If you only set the new image on each of these when required, you should see an improvement.
The reason is that each UIView has its own CALayer, which is copied to the graphics memory when required. It's quite slow to copy across a pixel (but once it's there it's cached), so if you only update one 30x30 tile at a time you should see better performance than if you were constantly updating the screen.
You could of course manually manage 80 CALayers within a single UIView but that would be much more difficult than using 80 UIImageViews.
Any time you override -(void)drawRect you're likely to hurt performance a lot, because of the way CALayers interact with graphics memory. The iPhone's Quartz graphics system is optimised for having lots of static layers than can then be manipulated with graphics commands (transform, opacity etc).
Profile. Use the Instruments application to find out which part of your code is running slowest, and then see whether you can either speed it up or avoid calling it so often. For example: do you really need to re-draw all of the images all of the time? Could you replace some Cocoa Touch code with the same behaviour using Core Animation or OpenGL ES?
Iterate. Once you've made a tweak, profile again. Did it get better? If it did, then look for the next thing to speed up. If it didn't, decide whether it's at all helpful or should be reverted.
well, every time you draw something... it's a work... you probably can get better performances just loading all your images at the beginning and then just swap them on screen (with hide/show your UIImageView), if images are so small you won't have memory problems...
Related
I'm making an iPhone game and using UIView objects to draw sprites. Most of the time, I have no performance problems. However, once I have around 15 to 20 objects on the screen (and maybe 5 of them moving around), the game becomes considerably slower, especially on the iPhone 3G. The frame rate can drop to as low as a single frame per second.
Is this simply a limitation of using UIView objects, or should iOS be able to handle this many UIView objects on screen at the same time?
In order to isolate the problem, I've made drawing my views very simple — drawing a red rectangle. drawRect is only getting called once per view. The view hierarchy is very simple and shallow. I'm using CADisplayLink to update the UIView locations every frame.
There's very little else going on, so I'd like to hear if anyone else has had success using this number of UIView objects.
The key to my problems ended up being that I had labels on top of my game content. The labels are not opaque, which likely was a large part of the problem, as phix23 suggested.
The first thing that made a big difference was removing a frames per second label that was on top of the content. Having a label that changed content on every frame caused a lot of slowdown.
I also had a large label that displayed on top of much of the game and changed shape when you level up. It turned out that drawing this label on top of everything caused a lot of slowdown as well.
In answer to my original question, I've found that on an iPhone 3G I can support about 30-40 opaque UIViews onscreen at the same time, with 2 or 3 non-opaque views as well. Non-opaque UIViews that change size, shape, or location are by far the worst, and even one of these that covers a significant amount of the screen can quickly cause problems.
If you're setting the opaque property of each view to NO, keep in mind that this seriously affects the speed of drawing the views. If your views aren't transparent, you should leave this set to YES, which is default.
for such type of application you should use CoreGraphics / Quartz / OpenGL but anyway I don't think there is a limitation on such low count. For example if I have a table view with 9 rows and each row has 5 subviews its still displayed acceptable fast. Have you tried using UIView animation to change the position in view?
good luck in learning OpenGL ;)
I have a problem when try to load the big animation with about 54 images (320x480 each image) into CCSpriteFrameCache, I can't use plist for this. How can I make the animation work? At this time, my animation can't work on iPhone 2G, 3G, and iPod.
Thank for your help,
John
You won´t be able to do it...
Consider playing a video or just animating an small portion of the screen.
Your best bet is to determine why the animation has 54 images that are all the width/height of the screen. This is an unnecessary number of images.
Break the animation down:
Is the background 'static' (does it move around, change constantly, etc?)
If it moves around a bit, but is really part of a much larger "canvas" then simply export out the entire background canvas and perform the movements yourself using the Cocos2D Actions available to you (CCMoveTo, CCJumpTo, CCDelayTime, CCSequence, etc)
What in the animation moves around, and how does it move around?
Can it be broken into much smaller bits and the frames for the various "characters"
or "movable objects" within the scene be exported out onto a sprite sheet (saved out
via Zwoptex?)
A good animation sequence should be a series of much smaller images, all working together in unison to create the final "animation sequence".
If you break it down, I wouldn't be surprised if you were able to reduce your 54 images at 320x480 each down to a handful of 512x512 spritesheets (ala Zwoptex).
If your having trouble breaking it down, I would be available to look at the final animation and help you determine what could be minimized to reduce the overhead.
in my (puzzle) game the pieces are drawn on-screen using a CALayer for each piece. There are 48 pieces (in an 8x6 grid) with each piece being 48x48 pixels. I'm not sure if this is just too many layers, but if this isn't the best solution I don't know what is, because redrawing the whole display using Quartz2D every frame doesn't seem like it would be any faster.
Anyway, the images for the pieces come from one big PNG file that has 24 frames of animation for 10 different states (so measures 1152 x 480 pixels) and the animation is done by setting the contentsRect property of each CALayer as I move it.
This actually seems to work pretty well with up to 7 pieces tracking a touch point in the window, but the weird thing is that when I initially start moving the pieces, for the first 0.5 a second or so, it's very jerky like the CPU is doing something else, but after that it'll track and update the screen at 40+ FPS (according to Instruments).
So does anyone have any ideas what could account for that initial jerkiness?
The only theory I could come up with is it's decompressing bits of the PNG file into a temporary location and then discarding them after the animation has stopped, in which case is there a way to stop Core Animation doing that?
I could obviously split the PNG file up into 10 pieces, but I'm not convinced that would help as they'd all (potentially) still need to be in memory at once.
EDIT: OK, as described in the comment to the first answer, I've split the image up into ten pieces that are now 576 x 96, so as to fit in with the constraints of the hardware. It's still not as smooth as it should be though, so I've put a bounty on this.
EDIT2: I've linked one of the images below. Essentially the user's touch is tracked, the offset from the start of the tracking is calculated (they can one move horizontal or vertical and only one place at a time). Then one of the images is selected as the content of the layer (depending on what type of piece it is and whether it's moving horizontally or vertically). Then the contentsRect property is set to chose one 48x48 frame from the larger image with something like this:-
layer.position = newPos;
layer.contents = (id)BallImg[imgNum];
layer.contentsRect = CGRectMake((1.0/12.0)*(float)(frame % 12),
0.5 * (float)(frame / 12),
1.0/12.0, 0.5);
btw. My theory about it decompressing the source image a-fresh each time wasn't right. I wrote some code to copy the raw pixels from the decoded PNG file into a fresh CGImage when the app loads and it didn't make any difference.
Next thing I'll try is copying each frame into a separate CGImage which will get rid of the ugly contentsRect calculation at least.
EDIT3: Further back-to-basics investigation points to this being a problem with touch tracking and not a problem with Core Animation at all. I found a basic sample app that tracks touches and commented out the code that actually causes the screen to redraw and the NSLog() shows the exactly the same problem I've been experiencing: A long-ish delay between the touchesBegin and first touchesMoved events.
2009-06-05 01:22:37.209 TouchDemo[234:207] Begin Touch ID 0 Tracking with image 2
2009-06-05 01:22:37.432 TouchDemo[234:207] Touch ID 0 Tracking with image 2
2009-06-05 01:22:37.448 TouchDemo[234:207] Touch ID 0 Tracking with image 2
2009-06-05 01:22:37.464 TouchDemo[234:207] Touch ID 0 Tracking with image 2
2009-06-05 01:22:37.480 TouchDemo[234:207] Touch ID 0 Tracking with image 2
Typical gap between touchesMoved events is 20ms. The gap between the touchesBegin and first touchesMoved is ten times that. And that's with no computation or screen updating at all, just the NSLog call. Sigh. I guess I'll open this up a separate question.
I don't think it's a memory issue; I'm thinking that it has to do with the inefficiency of having that large of an image in terms of Core Animation.
Core Animation can't use it natively, as it exceeds the maximum texture size on the GPU (1024x1024). I would break it up some; individual images might give you the best performance, but you'll have to test to find out.
IIRC, UIImageView does its animating by setting successive individual images, so if it's good enough for Apple….
When it is about performance, I definitly recommend using Shark (also over Instruments). In the 'Time Profile' you can see what are the bottlenecks in your app, even if it is something in Apple's code. I used it a lot while developing my iPhone app that uses OpenGL and Core Animation.
Have you tried using CATiledLayer yet?
It is optimized for this type of work.
Pretty new to iPhone / objective-C.
I have an application that has 15-100 small images (16x16 or 8x8 PNG) on the screen. For this example sake, let's assume that I can create these images using CGContext if I needed to.
I would have to assume that iPhone would perform better using that method rather than loading images (PNG's). However, the bitmap version is easier to develop and also has other advantages (like built in touch events) that I need.
If performance is not the ultimate metric for this application, does placing 100 small images degrade performance/memory enough to even consider switching to the CGContext method. My instinct tells me that I will not see that much of a performance difference either way but I am too new to iPhone development to know enough about it to make a difference.
I suppose it depends on the complexity of your image generation algorithm.
I will also depend on you application: will you be drawing this images many times per second, like in an animation? If that's the case, use UIImageViews.
I think using 100 or so UIImageViews should be fine as long as you don't need to rapidly animate them or update them at the same time. You should avoid doing anything that would change the size of the views (like resizing the view that contains them all), and if you use Core Animation to animate them, perform all of the animations inside a single animation block. (Wrap everything with one [UIView beginAnimations:context:], [UIView commitAnimations] - not one for each view)
Good luck!
I'd try the bitmap version first, then CGContext one if bitmap is too slow.
THEN if it's still too slow, I'd put all the icons into a GL texture.
I'm developing a 2D game for the iPhone using OpenGL ES and I'd like to use a 320x480 bitmapped image as a persistent background.
My first thought was to create a 320x480 quad and then map a texture onto it that represents the background. So... I created a 512x512 texture with a 320x480 image on it. Then I mapped that to the 320x480 quad.
I draw this background every frame and then draw animated sprites on top of it. This works fine except that the drawing of all of these objects (background + sprites) is too slow.
I did some testing and discovered that my slowdown is in the pixel pipeline. Not surprisingly, the large background image is the main culprit. To prove this, I removed the background draw and everything else rendered very fast.
I am looking for advice on how to keep my background and also improve performance.
Here's some more info:
1) I am currently testing on the Simulator (still waiting on Apple for the license)
2) The background is a PVR texture squeezed down to 128k
3) I had hoped that there might be a way to cache this background into a color buffer but haven't had any luck with that. that may be due to my inexperience with OpenGL ES or it just might be a stupid idea that won't work :)
4) I realize that the entire background does not always have to refresh, just the parts that have been drawn over by the moving sprites. I started to look into techniques for refreshing (as necessary) parts of the the background either as separate textures or with a scissor box, however this seems less than elegant.
Any tips/advice would be greatly appreciated...
Thank you.
Do not do performance testing on the simulator. Ever!
The differences to the real hardware are huge. In both directions.
If you draw the background every frame:
Do not clear the framebuffer. The background will overdraw the whole thing anyway.
Do you really need a background texture ?
What about using a color gradient via vertex colors ?
Try using the 2bit mode for the texture.
Turn of all render steps that you do not need for the background.
E.g.: Lighting, Blending, Depth-Test, ...
If you could post some of your drawing code it would be a lot easier to help you.
If you're making a 2D game, is there any reason you aren't using an existing library? Specifically, the cocos2d for iPhone may be worth your time. I can't answer your question about how to fix the issue doing it all yourself, but I can say that I've done exactly what you're talking about (having one full screen background with sprites on top) with cocos2d and it works great. (Assuming 60 fps is fast enough for you.) You may have your reasons for doing it yourself, but if you can, I would highly suggest at least doing a quick prototype with cocos2d and seeing if that doesn't help you along. (Details and source for the iPhone version are here: http://code.google.com/p/cocos2d-iphone/)
Thanks to everyone who provided info on this. All of the advice helped out in one way or another.
However, I wanted to make it clear that the main issue here turned out to be the behavior of simulator itself (as implied by Andreas in his response). Once I was able to get the application on the device, it performed much, much better. I mention this because, prior to developing my game, I had seen a lot of posts that indicated that the device was much slower than the simulator. This might be true in some instances (e.g. general application logic) but in my experience, animation (particularly 3d transformations) are much faster on the device.
I dont have much experience with OpenGL ES, but this problem occurs generally.
Your idea about the 'color buffer' is good intuition, essentially you want to be storing your background as a frame buffer and loading it directly onto your rendering buffer before drawing the foreground.
In OpenGL this is fairly straight forward with Frame Buffer Objects (FBO's). Unfortunatly I dont think OpenGL ES supports them, but it might give you somewhere to start looking.
you may want to try using VBOs (Vertex Buffer Objects) and see if that speeds up things. Tutorial is here
In addition, I just saw, that since OpenGL ES v1.1, there is a function called glDrawTex (Draw Texture) that is designed for
fast rendering of background paintings, bitmapped font glyphs, and 2D framing elements in games
You could use frame buffer objects similar to the GLPaint example from Apple.
Use a texture atlas to minimize the number of draw calls you make. You can use glTexCoordPointer for setting your texture coordinates that maps each image to its correct position. Remember to set your vertex buffer too. Ideally one draw call will render your entire 2D scene.
Avoid enabling/disabling states where possible.