How to Create and Optimize Sprite Sheets in Cocos2D with Texture Packer and Pixel Formats
来源:互联网 发布:好看的日剧推荐 知乎 编辑:程序博客网 时间:2024/06/06 04:37
Like this post? Follow me on Twitter! In Cocos2D, it’s important to combine your sprites into large images called sprite sheets, in order to get the best preformance for your games. If you’ve used Cocos2D for a while, you may have used a tool called Zwoptex that helps you make sprite sheets. Zwoptex is a great tool – I have used it in many apps and it has saved me a ton of time! However, there’s a new kid in town calledTexture Packer. It’s similar to Zwoptex in that it can create sprite sheets, but it has some amazing new features that come in really handy! This article will start with a tutorial showing you how to use Texture Packer in your Cocos2D games. Along the way, you’ll learn how to use pixel formats and Texture Packer wisely to make sure your games launch quickly, run smoothly, and use as little memory as possible – while still looking good! Full disclosure: I received a complimentary license key to check out Texture Packer from its author, Andreas Low. I didn’t promise a blog post in return, but after using it a bit to help reduce the memory load for one of my apps I’ve fallen in love with the tool, so wanted to tell you guys about it! This tutorial is intended for those who are already familiar with Cocos2D. If you are new to Cocos2D, you should start with the How To Create A Simple iPhone App series and some of the other cocos2d tutorials. First, make sure that you have the latest version of Cocos2D installed (at the time of writing this article, Cocos2D v0.99.5-rc1). It’s important to have the latest version, because the new version adds support for a new image format which you’ll be using later on in this article. Once you’ve got that installed, start up XCode and make a new project with the Cocos2D Application template, and name the project TextureFun. Next, you’ll need some images to make some sprite sheets with. Download this sample artwork I gathered together, and after you unzip it, drag the entire directory as a subfolder of your TextureFun project folder, as shown in the image below. Ok, now that you have a project template and some sample art to work with, time to make a sprite sheet using Texture Packer! The first thing you need to do is download a free copy of Texture Packer. Note you don’t have to buy anything – for the purposes of this tutorial you can use the free download. When you download the DMG, click on “TexturePacker.mpkg” that appears in the window, and follow the prompts to install Texture Packer on your machine. After you finish installing, find Texture Packer in your Applications folder and run it. When you see the first popup that appears, choose “Use Essential” (the free version) to continue. Now, click the “Add Folder” button in the top toolbar and choose the TextureFun/Art/sprites folder. Texture Packer will load the images and intelligently lay them out within the sprite sheet as follows: On the right hand side, you can see all of the images imported into Texture Atlas and click on each one to see the bounding box – another handy feature! You can also hover over the sprites to see if an alias was created (aliases are images that are actually the same after cropping). A few notes about adding images by the “Add Folder” option by the way. First, when you add sprites by folder like this, Texture Packer doesn’t add references to the individual sprites, it adds a reference to the folder. This means if you add more sprites to the folder, next time you run Texture Packer it will pick up any new sprites in the folder – pretty handy! Also note you don’t necessarily have to have all of your sprites in the same root folder, you could organize them in subfolders if you want (such as sprites/animals, sprites/monsters), and when retrieving them from Cocos2D you can refer to them by their relative path. Finally, note that you can include more than one folder of sprites if you want – this can be handy for larger games where you have the same items on multiple sprite sheets/levels. Ok, now take a look at the options on the left hand side. There you can configure the size, layout, and output options for the sprite sheet. Let’s quickly go through the size and layout options first: For this sprite sheet, you don’t need to change any of the above values from their defaults – they’re fine as-is. However, you will be changing the values in the output section. But before you get to that, let’s talk about pixel formats in Cocos2D. It’s important to understand pixel formats in Cocos2D, because pixel formats affect how much memory it takes to load an image in your game. Since games usually load a lot of images, you want to make sure that you make the best use of the limited memory available on a mobile device as you can. By default, when you load images in Cocos2D, it uses 4 bytes per pixel – 1 byte (8 bits) each for red, green, blue, and 1 byte (8 bits) for alpha transparency. This is known in shorthand as RGBA8888. So if you load an image in the default pixel format (RGBA888), you can calculate the memory it will take to store with the following calculation: In this case, you have a 512×512 image, so if you load it with the default pixel format it would be: Wow! Considering the iPhone 3G only has 128MB total, that’s a big chunk for just one small sprite sheet. Imagine if you had several (even bigger) spritesheets, like games often do! This is where pixel formats come to the rescue. You can save images with less bytes per pixel (2 bytes per pixel, or 16 bites per pixel), which trades off image quality for a reduction in memory. In general, your goal should be to load at the minimum possible level while still having your game look good. Backgrounds are often a good candidate for 8-bit or 16-bit formats, and sprites are usually 16-bit or 32-bit. For a great writeup of the various pixel formats and which you should use when, check out Riq’s understanding pixel format guide. By the way – if you look in the lower right corner of the window, Texture Packer will show you the image size your sprite sheet will take in memory based on your currently selected pixel format, so you don’t have to do the calculation by hand :] A lot of times, you can load an image with a smaller pixel format, and notice much of a reduction in quality. But in images that have a lot of gradients, you will notice some bad effects. Here’s an example of what it would look like if you load the art from this app with a 16-bit pixel format (RGBA4444) as-is: Notice how there is “striping” in the areas with a lot of gradients, especially in the background, bear, and ooze image. At this point, you might be tempted to rework your images to make less use of gradients or use a larger pixel format, but this is where Texture Packer comes in handy with another killer feature – image dithering! When you save sprite sheets using Texture Packer, you can specify the target pixel format to save your images to (such as RGBA4444), and then choose a “dithering method.” This basically modifies your image’s colors a bit so that they look good at lower quality, even when they have gradients or other colors that usually would cause problems. Go ahead and select RGBA4444 for this sprite sheet, and change the dithering option to “FloydSteinberg+Alpha”. Texture Packer will modify your images on the fly and show you an approximation of what they’ll look like – not bad when compared to the screenshot above, eh? Now let’s save out the sprite sheet. Click on the “…” next to Texture file, browse to your TextureFun/Resources directory, and name the file “sprites-hd.pvr.ccz”. Then click the “…” next to Data file, browse to your TextureFun/Resources directory, and name the file “sprites-hd.plist”. “But wait one gaddong minute”, you might say, “WTF is a pvr.ccz?!” Well I’m glad you asked… PVR images are an image container specific to the PowerVR graphics chip on iOS devices. They are good to use when possible on iOS because images can be loaded directly onto the graphics card, rather than needing to go through a conversion first. PVR images can contain image data using a variety of pixel formats. For a while, Cocos2Donly supported the pixel formats you can create with the texturetool app that comes with the iOS SDK, but Cocos2D was recently extended to support many more formats as well. And even more recently, Cocos2D was updated to support a compressed version of PVR images called pvr.ccz. The advantage of using these is a) your binary size is smaller since the images are compressed, and b) your game can start up much faster. So in summary, for this sprite sheet you are choosing to save the image in a 16-bit pixel format (to reduce memory cost) and save as a pvr.ccz (to load the app faster). Click “Publish, and your sprite sheet and property list will be generated! Texture Packer will tell you that some of the sprites will be created in red (since this is the free version). Let’s load up and optimize the background image as well. Click new to create a new Texture Packer window, click “Add Folder”, and choose the “TextureFun/Art/flower” folder. Change the image format to RGB565 (for large images you want the worst quality you can get away with), change the Dithering to “FloydSteinberg”, save the texture file as “TextureFun/Resources/flower-hd.pvr.ccz”, and save the data file as “TextureFun/Resources/flower-hd.plist”. Click “Publish”, close the warning, and when you’re done your screen should look like the following: Now go back to your project, right click on Resources, and choose “Add/Existing Files…”. Choose flower-hd.plist, flower-hd.pvr.ccz, sprites-hd.plist, and sprites-hd.pvr.ccz, cick Add, make sure that “Copy items into destination group’s folder (if needed)” is not selected, and click Add to finish. Next, open HelloWorldScene.m and replace the contents of your init method with the following: The first thing you do here is load the background image. You first tell Cocos2D to use the RBG565 pixel format (the 8-bit pixel format you’re using for the background), and then call spriteWithFile to load the image off the disk in pvr.ccz format. Note that you don’t need to really treat it as a sprite sheet (i.e. load the plist), since the “sprite sheet” is just one image. Note that you don’t really need the call to set the pixel format when loading from a pvr.ccz, because the file format itself contains information on what pixel format is contained within, but I wanted to add this here anyway because you do need this line if you are loading from a PNG instead (which is always saved as 32-bits per pixel, even though you may load it into memory in a different pixel format). Next add the following where the “more coming here soon” comment is: This changes the pixel format to RGBA4444 (the 16-bit pixel format you’re using for the main sprites) and then create a sprite batch node with the sprite sheet file. You also load the plist to get the definitions for each frame into the sprite frame cache. Finally, add the following right below the above: This loops through each of the images and scatters them across the screen. If you compile and run your code (use iPad, it’s targeted for that), you’ll see the following: This pretty much what you expect – and remember the red is just because you’re using the free version. But what’s impressive about the above are the things you don’t see. Behind the scenes, your app is loading a lot faster than it would have otherwise. It’s using a lot less memory, and best of all – it looks good. And the best part is it was totally easy to do just by using a few built-in settings with Texture Packer! While putting together this article, I did a couple simple tests to see how an app would perform in common scenarios, from worst to best. Here’s an overview of my findings: So overall, if you follow the best practice guidance above, I think you’ll be doing well for most cases :] If you want to see the test app I used and play around with it a bit, here ya go! When using Texture Packer, you can use the GUI tool as you did here, or you can integrate it into your XCode build so it automatically updates your sprite sheets for you (if necessary) each time you compile. If you’ve worked on a Cocos2D game in the past, you know how annoying it can be to have to constantly regenerate your sprite sheets. Even if it only takes a couple seconds each time, it adds up and gets old/annoying. So let’s set this up real quick in the project – it only takes a few seconds and saves a lot of time later. Right click on Resources, choose “Add/New File…”, choose Mac OS X/Other/Shell Script, and click Next. Name the file PackTextures.sh, and click Finish. Then replace the contents of PackTextures.sh with the following: Everything you can do with Texture Packer, you can do with a command line tool (named TexturePacker, oddly enough!) If you type “TexturePacker” at the command line, you’ll see a printout of all the options it takes. This script simply runs TexturePacker to create sprite sheets from the files in your Art directory – just like you did a little bit ago with the GUI tool. Check the TexturePacker command line help for more information about what each of these commands does. Next, you need to set up your project to run this shell script when you compile. Right click on Targets, choose “Add/New Target…”, and choose “External Target” (not Shell Script Target!), and click Next. Name the Target TexturePacker, and click Finish. Then double click on your TexturePacker target and set up the settings as follow: The final step is to set this target as a dependency of your app. Double click on your TextureFun target, go to the General tab,click the + button in Direct Dependencies, choose Texture Packer from the list, and click Add Target. Compile and run your app, and you should see the output from Texture Packer from your build results if everything is working OK. If you see those printouts, that means that if you want to add a new file to your sprite sheet, literally all you need to do is drop it into your sprites directory and recompile! Pretty convenient, eh? First of all let me say again, I am a big fan of Zwoptex, I think Robert has done an amazing job putting it together, and I honestly don’t think Cocos2D would be as far as it is today without it! However when just comparing the features between Texture Packer and Zwoptex, Texture Packer seems to have 90% of the features Zwoptex has (it’s currently missing a few minor things like drag and drop, manual placement of images, etc.), but in addition has three killer features not currently in Zwoptex: Although Zwoptex is great, it doesn’t yet have these extremely useful features so for now I have to give the win to Texture Packer. Texture Packer is a little more expensive ($17.95 vs. Zwoptex’s $14.95), but I think definitely worth it. And as Steffen Itterheim points out, both tools have a value worth even more than that! Here is a sample project with all of the code from the above tutorial. Are you a Texture Packer fan or a Zwoptex fan? Chime in your 2c below! Also if you have any good strategies for efficiently loading textures in Cocos2D, or any extra cool information, please let me know! :] Category: iPad //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////How to Create and Optimize Sprite Sheets in Cocos2D with Texture Packer and Pixel Formats
Getting Started
Creating a Sprite Sheet with Texture Packer
Pixel Formats and Cocos2D
width x height x bytes per pixel = size in memory
512 x 512 x 4 = 1MB (!)
Pixel Formats and Dithering
PVRs and Compression, Oh My!
Optimizing the Background
Using the Sprite Sheets in Cocos2D
-(id) init{ if( (self=[super init] )) { CGSize winSize = [CCDirector sharedDirector].winSize; [CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGB565]; CCSprite * background = [CCSprite spriteWithFile:@"flower-hd.pvr.ccz"]; background.anchorPoint = ccp(0,0); [self addChild:background]; // More coming here soon... } return self;}
[CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_RGBA4444];CCSpriteBatchNode *spritesBgNode;spritesBgNode = [CCSpriteBatchNode batchNodeWithFile:@"sprites-hd.pvr.ccz"];[self addChild:spritesBgNode]; [[CCSpriteFrameCache sharedSpriteFrameCache] addSpriteFramesWithFile:@"sprites-hd.plist"];
NSArray *images = [NSArray arrayWithObjects:@"bear_2x2.png", @"bird.png", @"cat.png", @"dog.png", @"turtle.png", @"ooze_2x2.png", nil]; for(int i = 0; i < images.count; ++i) { NSString *image = [images objectAtIndex:i]; float offsetFraction = ((float)(i+1))/(images.count+1); CGPoint spriteOffset = ccp(winSize.width*offsetFraction, winSize.height/2); CCSprite *sprite = [CCSprite spriteWithSpriteFrameName:image]; sprite.position = spriteOffset; [spritesBgNode addChild:sprite];} [CCTexture2D setDefaultAlphaPixelFormat:kCCTexture2DPixelFormat_Default];
Don’t Believe Me?
Texture Packer and XCode Integration
#!/bin/shTP="/usr/local/bin/TexturePacker"if [ "${ACTION}" = "clean" ]then echo "cleaning..." rm resources/sprites-hd.pvr.ccz rm resources/sprites-hd.plist rm resources/flower-hd.pvr.ccz rm resources/flower-hd.plist # .... # add all files to be removed in clean phase # ....else echo "building..." # create hd assets ${TP} --smart-update / --format cocos2d / --data resources/sprites-hd.plist / --sheet resources/sprites-hd.pvr.ccz / --dither-fs-alpha / --opt RGBA4444 / Art/sprites/*.png ${TP} --smart-update / --format cocos2d / --data resources/flower-hd.plist / --sheet resources/flower-hd.pvr.ccz / --dither-fs-alpha / --opt RGB565 / Art/flower/*.png # .... # add other sheets to create here # ....fiexit 0
Texture Packer vs. Zwoptex
Where To Go From Here?
- How to Create and Optimize Sprite Sheets in Cocos2D with Texture Packer and Pixel Formats
- How To Use Animations and Sprite Sheets in Cocos2D
- How to Use Animations and Sprite Sheets in Cocos2D 2.X
- How To Create Buttons in Cocos2D: Simple, Radio, and Toggle
- How To Create A Breakout Game with Box2D and Cocos2D Tutorial: Part 1/2
- How To Create A Breakout Game with Box2D and Cocos2D Tutorial: Part 2/2
- Enemies and Combat: How to Create a Tile Based Game with Cocos2D Part 3
- How to create a DLL library in C and then use it with C#
- How to optimize memory usage and bundle size of a Cocos2D app
- How to create and apply a patch with git
- How to create and apply a patch with Git
- How to Create Login Form with CSS3 and jQuery
- How to Create a Slick and Clean Button in Photoshop
- How to create (and deploy) a windows service in C# ?
- How To Drag and Drop Sprites with Cocos2D
- How to create a Flex project with java Env so you can compile and debug it in Jboss directly?
- [引用]SQL Server 2005 Books Online How to: Create a Job with Steps and a Schedule in Visual Basic .NET
- How to create aligned partitions in Linux for use with NetApp LUNs, VMDKs, VHDs and other virtual di
- linux 查看系统版本
- 轻松搭建Android开发环境
- Kingston DataTraveler G3 4G 量产成功
- MongoDB auto-sharding
- 明天你是否会想起
- How to Create and Optimize Sprite Sheets in Cocos2D with Texture Packer and Pixel Formats
- flex ant 例子
- How To Drag and Drop Sprites with Cocos2D
- 帮朋友记录点东西。
- How To Create A Mole Whacking Game with Cocos2D: Part 1/2
- 产品管理与产品营销的区别与合作
- How To Create A Mole Whacking Game with Cocos2D: Part 2/2
- Android 计时器Timer用法
- error C2146: syntax error : missing ';' before identifier 'PVOID64'