The full text reads as follows:
I am currently completing my last contract project. One thing I need to consider in the final stages of this project is how to optimize the memory usage of the game.
In today's Idevblogaday article, I'll tell you how I've reduced the memory consumption of 25-30MB games (now the game consumes memory 90-95mb, and I've eliminated some of the program crashes caused by memory warnings). At the same time, I have reduced the size of the game program from 25MB to less than 20MB (if Apple did not recently increase the limit of the cellular download application from 20MB to 50MB, then my small optimization is great, it can potentially bring me more downloads).
I'll also show you how to show an animated loading interface when you load the game resources, and I'll add some best practices and tips.
What consumes 90% of the memory?
Let's guess:)
In most cases, it is the texture (textures) that consumes a lot of memory in the game program. Therefore, textures are our top priority, especially when you encounter memory warning problems.
Avoid loading png and JPG textures one by one (they wait at least one frame)
Cocos2d inside texture loading is divided into two stages: 1. Create a UIImage object from the picture file. 2. Create the Cctexture2d object with this created UIImage object. This means that when a texture is loaded, it consumes twice times the amount of memory it uses in its own memory in a short period of time. Why is it only for a short time? Because of the Autorelease pool and reference count relationships, temporarily created UIImage objects are recycled. )
This memory problem becomes even worse when you load 4 textures in a single method, one after another. Because before this method is finished, each texture consumes twice times its own memory.
I am not quite sure whether the present cocos2d is still so. Or is this case only applicable to manual reference count management, perhaps arc does not? I'm used to loading textures sequentially, but wait for a frame before loading the next texture. This will cause any texture load to consume less pressure on the memory. Because waiting for a frame, the reference count frees the temporary UIImage object and reduces the memory pressure. Also, in subsequent articles, you can use this method if you want to load textures sequentially in the background thread.
Do not use JPG images!
Cocos2d-iphone There is a problem when using JPG textures. Because JPG textures are converted to PNG textures in real-time when they are loaded. This means that the cocos2d-iphone load texture is very slow (there is a demo here), and the JPG texture consumes three times times the memory footprint of itself.
A 2048*2048-sized texture consumes 16M of memory. When you load it, it consumes 32MB of memory in a short period of time. Now, if this picture is in JPG format, you will see that this number will reach 48MB because of the extra UIImage object created. Although, eventually the memory will drop to 16M, but that moment of memory is high enough to let the OS kill your game process, causing crash, affecting the user experience.
JPG is poor both in terms of loading speed and memory consumption. So don't use jpg!.
Ignore file picture size
This situation, I see a lot. It may sound a bit absurd at first, but it's true because it requires knowledge of the file format that not every programmer knows. The argument I often hear is, "Hey! My program can not have memory warning, all my picture resources add up not to 30mb! ”。
What to say, because the picture file size and texture memory footprint are different. Suppose they were tents. The picture file is the equivalent of a tent being packed in a suitcase. However, if you want to use a tent, it must be propped up and "inflated".
The relationship between picture files and textures is similar. Picture files are mostly compressed, and they must be decompressed before they can be processed by the GPU and become familiar textures. A 2048*2048 PNG image, encoded in 32-bit color depth, uses only 2MB of space on the disk. However, if it becomes a texture, it will consume 16MB of memory!
Of course, reducing the amount of texture used to occupy memory is a way to drip.
Using 16-bit Textures
The fastest way to reduce texture memory usage is to load them as a 16-bit color depth texture. Cocos2d the default texture pixel format is 32-bit color depth. If you halve the color depth, then the memory consumption can be reduced by half. And it also brings about a 10% increase in rendering efficiency.
You can use the Cctexture2d object's class method Setdefaultalphapixelformat to change the default texture pixel format, with the following code:
[Cctexture2d SETDEFAULTALPHAPIXELFORMAT:KCCTEXTURE2DPIXELFORMAT_RGB5A1]; [[Cctexturecache Sharedtexturecache] addimage:@ "Ui.png"];
Here's the problem: first, changing the texture pixel format affects all textures that are loaded later. Therefore, if you want to load the texture later using a different pixel format, you must call this method again and reformat the pixel format again.
Second, if your cctexture2d pixel format does not match the pixel format of the image itself, it will cause serious distortion to appear. For example, the color is wrong, or the opacity is not.
What are some of the more useful texture pixel formats?
Generate 32-bit textures:kcctexture2dpixelformat_rgba8888 (default) Generate 16-bit Textures:kcctexture2dpixelformat _rgba4444generate 16-bit textures:kcctexture2dpixelformat_rgb5a1generate 16-bit textures:kcctexture2dpixelformat_ RGB565 (no alpha)
RGBA8888 is the default format. For 16-bit textures, use RGB565 to get the best color quality, since 16 bits are all used to display colors: A total of 65536 total color values. However, there is a drawback here, unless the picture is rectangular and there is no transparent pixels. So the RBG565 format is better suited for background pictures and some rectangular user controls.
The RBG5A1 format uses a single color to represent the alpha channel, so the picture can have a transparent area. Just, 1 bit seems a bit inadequate, it can only represent 32768 available color values. And the images are either all transparent pixels or all opaque pixels. Because of the alpha channel of a bit, there is no intermediate value. But you can use the fade in/out action to change the texture's opacity properties.
If your picture contains a translucent area, then the RBGA4444 format is useful. It allows each pixel value to have 127 alpha values, so the transparency efficiency is not much different from the texture of the RGBA8888 format. However, because the total color is reduced to 4096, RBGA4444 is the worst color quality in a 16-bit image format.
Now, you can get the disadvantage of the 16-bit texture: because of the decrease in the total color, some pictures may appear distorted and may produce a "gradient".
Make 16-bit textures look great
Fortunately, we have texturepacker. (hereafter referred to as TP)
TP has a feature called "jitter" which can improve the distortion caused by the decrease in the number of colors. (TP has a lot of jitter algorithms, for these algorithms, readers can refer to my translation of another article).
In particular, with the pixel density of the retina display, you can hardly see the difference between the 16-bit and 32-bit textures. Of course, the premise is that you need to use the "jitter" algorithm.
Cocos2d The default color depth will render all textures to the 16-bit color framebuffer, and then to the screen of your device. In that case, why don't we make all the textures in 16-bit format, and what's the use of 32 bits? It would have been rendered to the 16-bit framebuffer anyway. This is a bit too low-level, I don't want to dig deep, and I am not fit to explain the problem. (Translator: Haha, know for know, do not know for unknown)
Using Npot Textures
NOPT is the abbreviation for "Non Power of", translated "not a power of 2". Npot stands for "Non power of". In the cocos2d1.x, you must open the support for Npot in the CcConfig.h file, but cocos2d 2.x is not needed, it is supported Npot by default. All 3 Generations (iphone 3GS) later iOS settings support Cocos2d 2.x (because they support OpenGL ES2.0), so npot textures are also supported.
If the texture Atlas (texture) uses npot textures, it will have a big advantage: it allows TP to compress textures better. Therefore, we will waste less space in the texture atlas. In addition, such textures use less than 1% to 49% of memory when loading. And you can use TP to force the generation of npot textures. (You only need to tick "allow free size")
Why do you care about Npot? Because Apple's OpenGL driver has a bug that causes an additional 33% memory consumption if the pot texture is used.
Default use of the PVR format texture
TP allows you to create a PVR-formatted texture. In addition to the PVR texture support npot, they can not only be a power of 2, but also not square.
PVR is the most flexible texture file format. In addition to supporting standard uncompressed RGB picture formats, the PVRTC format of lossy compression is not supported. In addition, the memory consumption of the uncompressed PVR format texture is very low. Unlike a PNG image that consumes twice times its memory footprint, the PVR format simply consumes the size of the texture itself, plus a little bit of memory to handle the image format.
One drawback of the PVR format is that you can't open the view on your Mac. However, if you install TP, you can use the PVR image browser with TP to browse the PVR format picture. (We strongly recommend that you buy TP, support TP, no more piracy)
Files using the PVR format have almost no drawbacks. In addition, it can greatly increase the loading speed, which I will explain later.
Using the Pvr.ccz file format
In three selectable PVR file formats, the PVR.CCZ format is preferred. It is designed specifically for COCOS2D and TP. In TP, this is the smallest PVR file it generates. And the PVR.CCZ format is faster than any other file format.
When using the PVR format texture in cocos2d, use only the PVR.CCZ format and do not use any other format! Because it loads very fast and uses less memory when loading!
When the visual is not aware of, you can consider using PVRTC compression
The PVR texture supports the PVRTC texture compression format. It is mainly used for lossy compression. If you take a PVRTC picture against a JPG image, it has only a JPG image of medium quality, but the biggest benefit is that you can not decompress the texture in memory.
This compares the 32-bit PNG image (left) with the best-quality PVRTC4 (4-bit) image (click on the image to see the full size):
Note that in some high-contrast places, there are obvious flaws. The place with the color gradient looks a little bit better.
PVRTC is certainly not the texture format most games want to use. However, they are very useful for particle effects. Because small particles are constantly moving, rotating, and zooming, it's hard to see some visual artifacts.
PVRTC Compressed Picture format
The PVR format provided by TP has not only two of the above, but also TC2 and TC4, which have no alpha channel format.
Alpha in this case is the same as the alpha of the 16-bit texture. The absence of an alpha channel means that there are no transparent pixels in the image, but more color bits are used to represent the color, so the color quality will look better.
Sometimes, the PVRTC image format refers to the use of 4-bit or 2-bit color values, but not exactly. The PVRTC picture format can encode more color values.
Pre-load all textures
As the title says, do whatever you can to preload all the textures. If all your textures add up to no more than 80MB of memory consumption (referring to devices with Retina display, not half of retina), you can load them all in the first loading scene.
The best thing about this is that your gaming experience is very smooth, and you don't have to worry about loading and unloading the resources anymore.
This also allows you to use the appropriate texture pixel format for each texture, and makes it easier to find other texture-independent memory problems. Because if it is related to textures, the problem is exposed when all textures are loaded for the first time. If all of the textures are loaded and the memory problem occurs again, then it's definitely not about the texture, it's the other problem.
If you know that the problem is not related to textures, then finding the remaining memory problems will be easier. And you've avoided the situation above: when the 2048*2048 texture is loaded, it would have only consumed 16MB of memory, but it would have rushed to 32MB of memory for a short time. A way to solve the "intermittent memory Spike" ("Translator's Invention") method is presented later. (Translator: Hope that the next developer dialogue "intermittent memory high" will appear, hehe)
Load textures in order of size from large to small
Because of the additional memory consumption issues when loading textures, it is a best practice to use texture size from large to small to load textures.
Assume that you have a texture that takes up 16MB of memory and four memory-intensive 4MB textures. If you load the 4MB texture first, the program will use 16MB of memory, and when it loads the fourth texture, it will go to 20MB in a short time. At this point, you want to load the 16MB texture, the memory will immediately soar to 48MB (4*4 + 16*2), and then to 32MB (4*4 + 16).
However, in turn, you load the 16MB texture first and then go to 32MB in a short time. And then dropped to 16MB. At this point, you load the remaining 4 4MB in turn, at this time, up to the Puma (4*3 + 4*2 + 16=36) MB.
In both cases, the memory peak usage is 12MB, you know, maybe this 12MB will ruin your game progress of the small life Oh!
Avoid clearing the cache when a memory warning message is received
I sometimes see a strange "shoot my own Foot" behavior: The texture has all been loaded in the loading scene, when the memory warning occurs, and then cocos2d will release the unused texture from the cache.
It sounds good, the unused textures are released, but!
You've just loaded all the textures in and haven't entered any of the scenes (all the textures are treated as "unused"), but they're all removed from the texture cache right away. However, you also need to use them in other scenarios. What to do? You need to continue to judge that if a texture is not loaded, it continues to load. However, a load, due to "intermittent memory high", and immediately received a memory warning, then release, then judge, and then load .... My God, this is a cycle of death! This can also explain why some children's shoes, in the loading scene after the time to enter the next scene when the reason for the card.
Now, when I get a memory warning, my approach is to----do nothing. The memory warning still occurs, but it is only when the program starts loading. I know why, because "intermittent memory goes high", so I'm not going to take care of it. (However, if you are in the process of receiving memory warnings, you should pay attention, because this time you may have a memory leak!!!) )
I sometimes try to improve it by removing unused textures and some images that are only used in very special situations (such as the settings interface, which is not accessed frequently by players). Then, whenever I need a picture, I'll first check if the sprite frame is in the cache, and if it doesn't, load it. You'll see how it's done in the back.
Understand when and where to clear the cache
Do not randomly clear the cache, or you can try to free up some memory and remove unused textures. That's not a good code design. Sometimes, it even increases the number of loads and causes "intermittent memory to soar" multiple times. Analyze the memory usage of your program, see what's Inside the memory, and what should be erased, and then just clear the purge.
You can use the Dumpcachedtextureinfo method to see which textures are cached:
[[Cctexturecache Sharedtexturecache] dumpcachedtextureinfo];
The output of this method is as follows: (for the sake of clarity, I have screened out the information related to the-HD suffix)
Cocos2d: "Ingamescorefont.png" rc=9 name=ingamescorefont-hd.png id=13 x @ + BPP = kbcocos2d: "Ui.png" rc=15 Name=ui-hd.png id=5 2048 x 2048 @ bpp = 8192 kbcocos2d: "Ui-ingame.png" rc=36 name=ui-ingame-hd.png id=8 1024x768 x 10 @ + BPP = 2048 kbcocos2d: "Digits.png" rc=13 name=digits-hd.png id=10 x @ + BPP = kbcocos2d: "Hilfe . png "rc=27 name=hilfe-hd.png id=6 1024x768 x 2048 @ + BPP = 8192 kbcocos2d:" Settings.png "Rc=8 name=settings-hd.png id= 9 x 1024x768 @ + BPP = 2048 kbcocos2d: "Blitz_kurz.png" rc=1 name= (NULL) id=12 x @ 9 kbcocos2d: " Gameover.png "Rc=8 name=gameover-hd.png id=7 1024x768 x 2048 @ + BPP = 8192 kbcocos2d:" Home.png "rc=32 name=home-hd.png id=4 2048 x 2048 @ + BPP = 8192 kbcocos2d: "Particletexture.png" rc=2 name= (NULL) id=11 × x @ + BPP = KBc Ocos2d: "Stern.png" rc=2 name= (NULL) id=2 × x @ + BPP = kbcocos2d: "Clownmenu.png" rc=60 name=clownmenu-hd.png id=1 1024x768 x 2048 @ + bpp = 8192 kbcocos2d:cctexturecache dumpdebuginfo:13 textures using 60.1 MB (texture total memory size!!!) )
It contains a lot of useful information. The size of the texture, the color depth (BPP), and the size of each cached texture in memory. The "RC" here represents the "reference count" of the texture. If the reference count is equal to 1 or 2, then it means that the texture may not be used at this time, so you can safely remove it from the texture cache.
It's a good idea to only remove textures that you know are unlikely to be used in the current scenario (that is, the reference count described above is 1 or 2). In addition, only those textures that occupy large memory are removed. If a texture takes up only a few kilobytes of memory, the other move does not have much effect. This is the same as program optimization, do not do too much detail optimization, not premature optimization, to find performance bottlenecks, and then focus on optimization, in exchange for 20% of the time for 80% efficiency. Premature and excessive detail optimization is a need to be avoided for most applications.
Spriteframes retain textures!
In the example above, the reference count of textures can be a bit of a sight to understand. You will find that the texture set has a high retain count, even though you know that the textures in these texture sets are not currently being used.
You may have overlooked one thing: Ccsprteframe will retain its texture. So if you're using a texture set, it's not that easy for you to completely remove it. Because the sprite frame produced by this texture set remains in memory. So, you have to call Ccspriteframecache's Removespriteframesfromtexture method to completely erase the texture set in the texture cache. Remember, not the release method of the object you call, the object's memory will be freed, but the reference count is 0, the memory will be deleted)
[[Ccspriteframecache Sharedspriteframecache] removespriteframesfromtexture:uncachedtexture];
You can also use the removespriteframesfromfile and specify a texture set of the. plist file to clear the cached sprite frame (spriteframes).
Adding spriteframes is time consuming, every time!
Note: This is only valid for Cocos2d v1.0, and cocos2d v2.x is pre-judged before loading.
This seems a little ignorant (innocent):
[[Ccspriteframecache Sharedspriteframecache] addspriteframeswithfile:@ "ui.plist"];
However, be aware that Ccspriteframecache does not check if a sprite frame has been cached! This is different from the way Cctexturecache moves, and it loads spriteframes every time.
How much time this process takes, depending on the number of sprite frames you provide in the. plist file. I have noticed that only 14 frames of plist load are very different from plist loading with 280 frames. Therefore, you also need to be cautious about the loading of sprite frames.
So, you have to avoid some unnecessary addspriteframes* method calls. Because there is a small lag that causes the scene to switch.
You can clear any caches (such as animation,sprite frames, etc.), but do not easily clear the texture cache
Cocos2d has many cache classes, such as texture caching, sprite frame caching, animation caching, and so on. However, if you want to clean up the memory, the sprite frame cache and the animation cache have a very small amount of memory, which can be said to be minimal.
Of course, if you want to remove a texture from memory, you must also remove the sprite frame associated with it (because the sprite frame will retain the texture). In plain terms, it is not easy to remove Sprite frames and animation caches, because you might use an animated frame object or sprite frame object that does not have a cache, which can cause the program to crash.
Exception: Check the memory usage of the sound file!
The sound file is cached and can be played repeatedly without interruption. Because sound files are generally large, in particular, I see some developers using uncompressed sound files as the background music of the game, and these background music files are very large, they usually cause a lot of memory consumption.
Please use a sound file in MP3 format. Because using a sound file that is not compressed consumes both memory and program size. When you have finished loading some of the game sounds, remember to uninstall them when you don't need them. In the second article, I'll introduce you to more knowledge of sound files.
How to avoid caching a specific texture
If you have a texture and you really don't want to cache it, what do you do? For example, images in the initial load scene, or images that the user rarely cares about-such as your very bull-like thanks scene.
It is often easy to misunderstand that a texture is displayed, and it is cached. If you remove this texture from the cache, the program crashes when you remove the sprite. This understanding is not correct.
Cctexturecache is simply a call to add a retain function to the texture, so that when no other object (such as a sprite) holds a reference to the texture, the texture will still exist between the memory. Based on this, we can immediately remove from the cache, so that when the texture is not needed, it will be released from memory immediately. As shown in the following code:
BG = [Ccsprite spritewithfile:@ "Introbg.png"]; Don ' t cache this texture: [[Cctexturecache Sharedtexturecache] removetextureforkey:@ "Introbg.png"];
You need to keep in mind that when you remove a texture from the Cctexturecache, cocos2d will reload the texture the next time it calls Spritewithfile-whether or not a picture with the same name is being used by another sprite. Therefore, if you are not careful enough, you may end up loading two duplicate textures in memory.
One example is when you load textures in a loop, and these textures you don't want to cache. In this case, you will need to remove the cache of this texture outside of the loop, or it may cause multiple textures to be repeatedly loaded into memory:
nsarray* highscores = [achievements sharedachievements].highscores; For (highscoredata* data in highscores) { nsstring* entry = [NSString stringwithformat:@ "%05u", Data.score]; cclabelatlas* label = [Cclabelatlas labelwithstring:entry charmapfile:@ "pipizahlen.png" itemwidth:18 itemheight:27 startcharmap: '. ']; [Labelsnode Addchild:label z:10]; } Don ' t hold on to this texture: [[Cctexturecache Sharedtexturecache] removetextureforkey:@ "Pipizahlen.png"];
The above example is what I pulled out of the highscore scene, and once this scenario exits, you should not hold a reference to the Cclabelatlas texture. Therefore, we need to remove it from the texture cache. However, you must prevent repeated loading of textures into memory.
In this way, we can easily clear the textures in the cache, and it is best to clear the texture when creating it, rather than in other places, such as dealloc or simply let purge cache do it.
Use a loading scene
If you can't preload all the textures, you can use a loading scene and display an animation to show the progress of the load. This allows the previous scene to be destroyed before entering the next scene, freeing up the memory resources it occupies.
Very simple to implement. This loading scene dispatches a selector, and then each frame (or 0.1 seconds) executes a function, such as update. Unless you have a memory leak in the previous scenario, each time the update function executes, some memory resources with a reference count of 0 will be freed. In this update method, you can create a new scene.
This greatly avoids the "intermittent memory high" problem, which can greatly reduce the memory pressure.
Loading textures in the background
The Cctexturecache class also supports the ability to load resources asynchronously, using the Addimageasync method. You can add a callback method to the Addimageasync method in a way that can be notified when the texture is loaded asynchronously.
This is important: you must wait for a resource to be loaded. Otherwise, because of "intermittent memory high", the following issues may be raised:
1) Program crashes
2) texture is loaded two times! Because asynchronous loading does not guarantee the load order.
Load other game resources in the background
However, there is no way to asynchronously load sprite frames and other resources. However, we can use Performselectorinbackground to implement similar asynchronous loading capabilities:
[Self Performselectorinbackground: @selector (loadspriteframes:) Withobject:nil];
The selector method inside only receives an object parameter (but is not used). You can then load the resource asynchronously in this method, as follows:
-(void) Loadspriteframes: (ID) object{ [[Ccspriteframecache Sharedspriteframecache] addspriteframeswithfile:@ " Hilfe.plist "]; [[Ccspriteframecache Sharedspriteframecache] addspriteframeswithfile:@ "home.plist"]; [[Ccspriteframecache Sharedspriteframecache] addspriteframeswithfile:@ "ui.plist"]; [[Ccspriteframecache Sharedspriteframecache] addspriteframeswithfile:@ "gameover.plist"]; [[Ccspriteframecache Sharedspriteframecache] addspriteframeswithfile:@ "ui-ingame.plist"]; [[Ccspriteframecache Sharedspriteframecache] addspriteframeswithfile:@ "settings.plist"]; [[Ccspriteframecache Sharedspriteframecache] addspriteframeswithfile:@ "digits.plist"];}
The biggest benefit of this is that while you load resources, the loading scene can also play animations, add sprites and run some actions, all of which can be handled smoothly. This advantage is good even on a single CPU machine, but it works better if your device has multiple CPUs.
However, you need to be aware that you cannot load textures in the background line loads, you must use the Addimageasync method. This is because the texture must be loaded in the same thread as the public OpenGL context. This way, you have to load the texture asynchronously before you load the sprite frames in the background. You can't rely on Ccspriteframecache to load textures in a background thread.
Load game Resources sequentially
The following code is the method I used to load the texture and sprite frames asynchronously (loaded in another thread:)
Assume that each frame of the Loadassetsthengotomainmenu method is triggered. The Assetloadcount and Loadingasset variables are declared in the class interface, respectively, with the INIT and bool types:
-(void) increaseassetloadcount{assetloadcount++; Loadingasset = NO;} -(void) Loadassetsthengotomainmenu: (cctime) delta{NSLog (@ "Load Assets%i", assetloadcount); Switch (assetloadcount) {case 0:if (Loadingasset = = NO) {Loadingasset = YES; NSLog (@ "============= Loading home.png ==============="); [Cctexture2d SETDEFAULTALPHAPIXELFORMAT:KCCTEXTURE2DPIXELFORMAT_RGB5A1]; [[Cctexturecache Sharedtexturecache] addimageasync:@ "Home.png" Target:self selector: @selector (incr Easeassetloadcount)]; } break; Case 1:if (Loadingasset = = NO) {loadingasset = YES; [Self Performselectorinbackground: @selector (loadspriteframes:) Withobject:nil]; } break; Extend with + sequentially numbered cases, as needed//the default case runs last, loads the next scene Default: {[self unscheduleallselectors]; mainmenuscene* mainmenuscene = [Mainmenuscene node]; [[Ccdirector Shareddirector] replacescene:mainmenuscene]; } break; }}
When this method runs to the first case statement, in order to avoid the same image being loaded multiple times, we set the loadingasset tag to Yes. When the texture is finished loading, we add increaseassetloadcount (this number can be used to show the progress bar loading percentage). Later case statements can also load more things like sounds, font files, particle effects, physical configuration files, level information, and so on. No matter how many things are loaded, the last default statement executes, and then you can enter the Mainmenuscene.
The common point of this approach is that you can load multiple textures asynchronously with case and assetloadcount, while avoiding the "intermittent memory spike" problem. Because a method is called once per frame, the temporary memory in front of the texture loading has been freed. Because the Autorelease pool at the top of the current line stacks is emptied before each frame is rendered.
PostScript: The contents of this introduction are aimed at cocos2d-iphone, however, most of the content is suitable for cocos2d-x. Therefore, developers can rest assured to try these methods, if you have a better way to optimize the use of game memory, welcome to share. Hopefully this post will be the ultimate solution for cocos2d memory problems. If you think I translated well, I hope you can click the recommended button next to it. Thanks, enjoy!:)
Happy coding!
How to reduce the size of the game program? (The previous target is below 20MB, now the target is below 50MB, why?) You know! )
Reduce the size of your program
By reducing the depth of the texture's color bit to 16 bits, the memory pressure can be reduced and the program volume can be reduced effectively. However, there are other ways to further reduce the size of the program.
Texturepacker PNG Picture Optimization
If you have some reason to insist that you want to use the PNG file format instead of the Pvr.ccz file format that I tried to recommend to you before, then Texturepacker has an option called "PNG Opt Level" (PNG optimization), can help us reduce the size of the PNG file (note: This does not affect the picture load time)
As far as I'm aware, the maximum level of optimization can generate the smallest file size. However, it has one drawback, which is very time-consuming. For the 27-inch imac in 2009, it takes 10-20 of the time to process a slightly larger texture. Since this optimization process takes the form of multithreading, if you have a four-core machine, then the speed should be faster.
Of course, you only need to take advantage of this optimization feature when you really publish your app. The question now is, how much file volume can it reduce?
My biggest PNG picture has been reduced from 2.4MB to 2.2MB. Smaller textures are reduced from 180kb to 130kb. There may not be a lot of reductions in individual files, but when your PNG image has a total size of 18MB, it can be reduced to 16MB.
Note that there is a setting in Xcode that you might ignore. You need to turn off the "Compress PNG files" switch, as this option may cause your PNG image to swell. You can set it in Xcode's build settings as follows:
If you activate this PNG compression option, Xcode runs its own PNG optimizer when the PNG file is packaged into a program. Therefore, it is possible to inflate the PNG image that we previously optimized with TP. So, make sure this option is turned off again!
However, even if you do not disable this option, your program size will be reduced. Because, you may use some PNG images that have not been optimized by TP.
Check the size of your program in the app Store
Inside Xcode, run Archive build (select Product->archive in the menu). When build succeeds, Xcode's organizer window will open and you will see a "Estimate size" button that can be used to estimate the size of your application:
To remove unused resource files
You'll often add, remove, and replace game resources as you develop your game. So, you may forget to remove some of the unused picture resources for some reason. So, you need to pay extra attention to removing them from the project, at least from the program's target.
Especially if you use multiple target (for example, you maintain both the ipad and Mac versions), you will most likely add some wrong resources to a target.
Of course, after removing the resources, you must fully test your game. Remember! Be sure to test it thoroughly.
Reduce sound file size
Sometimes, we also ignore this problem. If you do not consider the format of the sound file, whether it is the use of memory or the size of the program is a great waste. Here are some methods you can use to reduce the size of your sound file. I recommend that you use a free sound editing tool.
Stereo channel Change mono – your MP3 file can be stereo, but is it worth it? If you can't hear the difference, it's recommended to use a single channel. This can reduce the file size and memory usage by half.
MP3 Bit Rate – on iOS devices, any sound with a bit rate greater than 192kbps is wasted. You can try to use low bitrate to get the best sound quality, which is a tradeoff. Generally speaking, 96 to 128kbps is sufficient for MP3 files.
Sample Rate – most sound files use 11,22,44, or 48kHz sample rate. The lower the sample rate, the smaller the sound file. However, the lower the quality of the sound. 44kHz has reached the CD's sound quality, and 48kHz will be better (this difference can only be heard by the tuner)
In most cases, the bit rate of 44kHz or higher is a bit wasteful. So, you can try to reduce the sample rate (inside Audacity: tarck->resample). Do not just modify the sample rate, as this will change the pitch of the sound file.
Streaming MP3 Files
The playback of the MP3 file is first loaded into memory and then decoded to the uncompressed sound buffer, which is then played back.
As far as I know, Cocosdenshion's simpleaudioengine playbackgoundmusic is streaming MP3 files. The flow test has two advantages: 1. A smaller memory footprint. 2. Decode the MP3 file using iOS hardware instead of CPU. However, the hardware can only decode one file at a time, if you play more than one, then only one is hardware decoding, the other is software decoding.
Reduce tilemap size
Many developers did not notice that the tilemap size is too large to consume a lot of memory. Suppose you have a 1000*1000 tilemap, which consumes about 1M of memory--if each tile consumes one byte of memory. However, if each tile consumes about 64 bytes, the Tilemap consumes 60MB of memory. Oh my God!
In addition to writing a better tilemap renderer, the only thing we can do is reduce the size of the tilemap, or divide the map in one.
reproduced from "Black rice gamedev block" original link: http://www.himigame.com/iphone-cocos2d/1043.html
COCOS2DX in-game memory optimization