Archive for April, 2013

Unity3D Tech Tales, Part 3

Posted: April 30, 2013 in News

Part 3: “Smaller amounts of DRAM on the older devices”

Smaller amounts of DRAM on the older devices: well sure! Memory warnings will kill-off your app as quickly as an uninitialized pointer. Well maybe not – you do get a warning. But in a game there’s not a lot you can do aside from maybe calling the Garbage Collector (if you’re using something like C# with .net, like Unity3D games).

When testing Unity apps on iOS there are three different ways to do profiling:

  1. Enable the Internal Profiler by changing iPhone_Profiler.h and watching the output to the Xcode console
  2. Attach the Unity Profiler to drill down into your app’s internal details
  3. Use the Xcode profiler when your app is running on the target device.

It’d be a mistake to just use the first two. You might see that you’re using some number of MBytes of heap memory and confuse yourself into thinking that that was the entirety of memory use. It isn’t. For the record, I personally knew that it wasn’t.

The Unity profilers don’t show you all of the other memory used by your app. For that you really need to spend time with the Xcode profiler. While there’s no actual documented number for a maximum amount of memory to use, it’s best to keep it as small as possible. The reason for this, as every iOS dev already knows, is that your app resides in memory with all the other suspended and background apps that the user has launched. When memory gets low, apps are told to free memory – if they don’t then they might be terminated. Guess what – freeing memory is often impractical in the context of a game, much less in the Unity environment, where seemingly all you have access are the Game Objects in your scenes.

You really need to spend some time with the Xcode profiler and see where you’re wasting memory. You may be in for a surprise. There are some fairly simple passive and active means that you can use to keep memory use as low as possible.

Passively, by using compressed textures as often as possible, by having audio “stream from memory” when possible, and destroying assets you no longer need.

  • The more compressed your textures are the less memory they’ll take. Sorta obvious, eh? How about using 2 bits-per-pixel if you can?  How about combining textures into atlases?
  • There are several options for audio assets, most of the import options default to something that loads into memory. Many times that makes a lot of sense, especially for often-used game SFX: usually those are really short. But what if you have a 10-minute long mpg audio file that’s just for background music, that often users just shut off anyway (a subject of endless frustration).  Try the Stream From Disk option instead.

Actively, by Destroying unused GameObjects and other assets, and by using the Resources Folders.

  • Perhaps you have some user prompts or panelish textures shown at the start of a scene? Be sure to Destroy() things like that when you don’t need them.
  • Use the resources folder to store background textures for in-game panels such as tools panels, help panels, and other in-game items that are only needed occasionally but have large textures.
  • Call Resources.UnloadUnusedAssets() after your scene is completely initialized (this takes a little care).

The last  item in that list deserves some elaboration. There are two types of Resource folders: Resources and Streaming Assets. When you put something in the Resources folder it’s bundled with other assets in the app but not loaded into memory when the scene starts up. You can drag a texture into a Resources folder and then load/unload it when you need it. That was you only have a temporary memory increase, lessening the chance of a low-memory warning. The Streaming Assets folder saves your data in a Raw format, that is, not compressed with a bunch of other things. It’s actually a duplication of the folder heirarchy within the Streaming Assets folder in the target device’s file system. You might have some HTML files and images to use in an overlaid browser window. This way they’re not in the memory space of your app.

An example of how to use the Resources folder:

Texture2D  texture;
GameObject displayPlane;
texture  = Resources.Load ("someTexture") as Texture2D;
displayPlane.renderer.material.mainTexture = texture;

and later on….

displayPlane.renderer.material.mainTexture = null;
Resources.UnloadAsset(texture);

Actually, instead of ‘null’ you might have a tiny 64 x 64 black texture in your project and use that as the initial texture (i.e., set up using a black texture in the editor), then use that instead of “null” before the UnloadAsset(). That way the plane will appear black in the editor and you can tell where it is.  There’s plenty of documentation about Resource folders in the Unity Docs.

It seems simple, but these textures can be big – especially if your target is a Retina display iPad. If you have several of these, you can save several MBytes of memory.

Perhaps it’s a vestige of my days programming in assembly language, but it always seems better to be careful how you use memory. Hope these three articles save at least one person some time.

Unity3D tech Tales, part 2

Posted: April 27, 2013 in Programming, Unity3D

In the last installment I wrote about supporting different aspect ratios. The second item I mentioned in THIS earlier blog post is: Different levels of CPU/GPU performance.

CPU/GPU performance: I found that the 1.0 version of Numberheads worked great on the iPads and the iPhone 5. Not so great on the iPhone 4 and iPod Touch 4. They ran, but there were “hiccups” when a lot of pieces were moving around or when a lot of animated effects are fired-off at the same time.

Well, this wasn’t that surprising, but i was expecting that since I’d had been able to optimize well enough for the iPad 1 that the iPhone4 would be roughly the same performance. Well, no. Here’s a bit of advice – if you are developing for the iOS market, make it work well on an iPhone4 first, or maybe even an iPhone 3 (which I have not tried).

After a lot of work I identified the two basic problems: the CPU and the GPU seem to be weaker on the iPhone4 than on the iPad1. This is quite perplexing since the SOC (System On A Chip) on both is identical, although it seems as if the iPhone4 is clocked a little slower. The iPhone4 also has more DRAM than the iPad1, but that wouldn’t make things worse. The iPhone4 has fewer pixels, too. I was left with three possible conclusions.

  1. The information on WikiPedia about what’s in an iPhone4 and what’s in an iPad1 is incorrect.
  2. Might have something to do with the difference in physical screen types (retina on iPhone4 and normal on iPad1).
  3. There’s something about the architecture of the device that’s unclear.
  4. It doesn’t matter, I have to make it work (the engineering approach)

The truth is, I could waste a lot of time having fun figuring out what was going on or have less fun figuring out how to fix it.

The solution turned out to be fairly simple. I combined a few smaller texture atlases into one, 2K x 2K atlas. Part of what made this possible was the newer PVR image compressor with an improved quality setting. Previously, I had to have some of the texture atlases uncompressed, at 16 bpp so that they’d look clean on an iPad3 with it’s huge retina display. There are a LOT of sprites in Numberheads: each playing piece is actually several layered sprites. There are also a lot of effect sprites – little puffballs when pieces are removed, several types of explosion sprites, etc. But that’s not really a performance issue (inactive sprites are turned off with GameObject.SetActive(false) ). So combining all the sprites on to ONE big spritesheet was a big deal and only practical when Unity4 came out because of the new “best” quality setting for compression.

I also spent a lot of time code-reviewing, looking for bottlenecks caused by inefficient code. This really didn’t make much of a difference, since of course all of my code was perfect to begin with (channelling my inner Sheldon there).

In the end, the work I did on combining and compressing texture atlases made the most difference. But I was still finding hiccups – brief pauses – only sometimes – when a “bomb” piece “exploded” on the playfield. Those sprites are much bigger than the other ones, so I thought that perhaps it was something to do with having a large transparent area being drawn. But even if I commented-out the explosion the problem didn’t go away.

Light bulb! Turns out that it only happened when a “bomb” “exploded” next to a locked piece. Common to this type of game, a locked piece can’t be moved. But when a “bomb explodes” next to a locked piece the lock gets removed. And when that happens, a counter is incremented that keeps track of the number of unlocked pieces as part of an achievement that the player can earn. Of course, that has to be saved, and right away, too. That’s because with iOS apps you never really know when your app will be interrupted. But I was doing this save as part of the loop that was removing pieces from the board and that was key. I changed things so that the number of locks removed was kept as a variable and only AFTER the entire process was complete was that value saved.

Conclusion: Since this was NOT an issue on the iPad1 (or newer) the only possible reason is that the memory interface to the Flash memory which implements the device’s file system was slower. Both devices were using iOS 6 so that really couldn’t be it. The only other explanation is that this (well worn) iPhone4 that I bought on EBAY for $100 had had so much use that the Flash memory memory was reallocating internally (a Flash memory thing, sort of “self repairing”) because the memory had been over-used. That slows down access time when writing data to the flash memory, often for several hundred milliseconds. Again, the problem was fixed so in the end, I didn’t care.

Stay tuned for part 3 of this riveting series…

In a previous post I talked about a few stumbling blocks to supporting the three different iOS aspect ratios. To review:

iPad, iPhone4, and iPhone5 have different aspect ratios, and the iPad3 and newer have whopping big retina displays. This issue has some simple side-effects, like needing different splash-screen images. Not a big deal. More complex is how to handle this in-game. Do you have different sets of texures for each aspect ratio and maybe different textures for the iPad3 and 4?  That’s tricky if you want to have a “Universal” app; one that can be loaded on any type of i-device, and still fit within that 50 Mbyte OTA download limit. One solution is not to care about the download limit. I didnt’ like that one. Or one could have two different versions of your app. That’s a potential QA problem and Apple (anecdotally) seems to like it better if you make Universal apps.

If you look around on the Unity3D iOS forum there are many many posts about how to handle this, and to be fair, many have to do with true 3D games and I was only concerned with Numberheads, my 2D puzzle game. So I don’t assert any sort of universal solution, sorry.

One way to lay out a 2D game is to have an Orthographic camera, a background image,  and then to layer the other game elements (sprites, control buttons etc.) on top of that background layer. The background layer has no transparency, and the whole scene is often unlit so as to improve performance on mobile platforms. But how to reconcile these three different screen sizes:

  • iPad3 (and newer) 2048 px X 1536 px
  • iPhone4 (and similar sized iPod Touches) 960 px X 640 px
  • iPhone5 1136 px X 640 px

It actually turns out that you can use the nature of the Ortho camera and automatic scaling(note 1) to solve the problem rather simply. Simply use a 1 pixel = 1 game unit sizing scheme for all of your game assets, size the background texture for the iPad3 screen size and then adjust the camera’s ortho size as appropriate. Here is an image that can help understand this:

NHBG_website

This image (you can click on it to enlarge) is a screenshot taken right from Adobe Illustrator. Note that the HEIGHT of the image is 2750 pixels and the width is 1536 pixels. Huh?   That doesn’t make a heck of a lot of sense at first look; doesn’t seem right.  But, if you position the camera “above” the exact center of the image  and pointing directly at it you can then adjust the camera for the different devices. The key is to keep your game elements inside the lines “iPad Top” and “iPad bottom”. The other devices (i.e., not iPads) will have some empty space, that is, the background (whatever you choose to show).

It’s easy to programmatically determine which device you’re on using the iPhoneGeneration enumeration. For iPad-type aspect ratios set the camera’s “Orthographic Size” parameter to 1024, for iPhone4-type aspect ratios set the size to 1160, and for iPhone5-type aspect ratios set the size to 1374. Note that you have to be sure to choose the correct size for iPod Touch devices as well, those are like one or the other iPhone, and note that (as of this writing) all the iPads have the same aspect ratio.

While this may sound a bit confusing, it works because the camera’s presentation is scaled to the physical screen size. Recall that the “Orthographic Size” parameter is “half of the vertical size of the viewing volume” (from the scripting reference). So if it’s set to 1024 for iPad then the vertical size is 2048 which maps 1:1 to the iPad3 screen pixel height in Portrait mode. But on an iPad2 or other 1024×768 devices, this 2048 x 1536 presentation is scaled to fit in that size.

Minor con – you need a huge background texture. But in actuality, if you compress the source image down to a square texture and display that texture on a cube with the Transform scaled to 1536 x 2745 x 1 you’ll have a “pixel perfect” display. That’ll  look great even on the large Retina displays. Be sure to use the “best” RGB (not RGBA) Compressed PVRTC 4-bits compression and the texture will only be 2 mBytes. That’s a lot less space than if you needed three images, one for each aspect ratio.

This actually works in Landscape or Portrait orientations, has been tested on devices, and is in a shipping product on the App Store. Hopefully some Unity developers will find this information useful.

Note 1: The mechanism by which the scaling occurs is way beyond the scope of this post but can be seen by examining a built project’s “Classes/Unity” folder from within Xcode. Clearly I can’t post any of that without violating the Unity3D license agreement.

 

You say you’re a smart dev using Unity3D Pro and you’re trying to make it to the under-50 megabyte OTA cap on iOS and ya just need a little more weight reduction?  Here’s a quick tip: use small, uncompressed png files for your unused splash images.

splashesNotice that since this App is portrait-mode only, there are three potential unused splash screen images. Well, if you look at your Xcode project or an archived build you’ll see that there are some PNG files there for these unused orientations. They’re just the Unity3D logo, but there are several – for normal and retina resolutions.

  • Default-Portrait.png is 59 Kb, Default-Portrait@2x.png is 195 Kb, Default.png is 65 Kb, Default@2x.png is 204 Kb, and so on. If you’re not using them why waste the space? Just add a very small (say 64×64) black texture to your assets folder and use that instead of leaving the Unity inspector setting as “none”.

For example, “Default-Landscape@2x.png” (corresponding to “High Res iPad Landscape” in the image shown here)  is a 64×64 black texture and is just 9 Kb.  Now of course Apple uses its wierd PNG compression and will reduce these file sizes a bit more but you will still save space – try archiving before and after and you’ll always save something.

Why waste the space – save bytes, and take comfort in the fact that when you sell 10 million copies of your masterpiece the energy save by not transmitting these spurious bytes you’ll save people money on their data plans and save enough energy to light a 20 W LED bulb for 29 seconds!

Notes: You need Unity Pro to change the splash screen images in the first place. If you use a compressed texture you’ll get a warning every time you build.

The status for the following app has changed to Waiting For Review. App Name: Numberheads  DspDan Copyright 1994

Fearless Leader likes it!

Well it took about 10 weeks and ended up being a complete UI redesign but it’s finally done.  It’s time to write a little bit about what I had to do to complete this – perhaps it’ll be of some help to other developers.  Some of this is Unity-specific, some iOS device-specific, and some of it will be familiar.

A few shout-outs: I have a list of credits here but for software I’d especially like to give my own Benign Games badge of honor to Unity3D for being amazing. The architecture is a little reminiscent of the Zope Content Management System – not sure if it’s still in use that much but I spent some time developing with it and in it and although it’s written in Python and isn’t a Game Engine, the concept of building up a solution by adding your code into the overall namespace of the language in an intepreted environment  (I know that that statement is an oversimplification) just can’t be beat for rapid development.  I have seen people complain about the cost of the Pro version, but with all due respect: it’s a bargain.

Most honorable and distinguished mentions go to EZ-GUI, Sprite Manager2 and Finger Gestures.  Who in their right mind would want to write those libraries for themselves? No way it wouldn’t cost you squillions more in terms of your own time than laying out a few hundred squandroes (please convert in to your own fiat money system if you like) for these fine products.

ANYWAY

Biggest issues:  

  • Three different aspect ratios 
  • Different levels of CPU/GPU performance
  • Smaller amounts of DRAM on the older devices

Aspect ratios: iPad, iPhone4, and iPhone5 have different aspect ratios, and the iPad3 and newer have whopping big retina displays. This issue has some simple side-effects, like needing different splash-screen images. Not a big deal. More complex is how to handle this in-game. Do you have different sets of texures for each aspect ratio and maybe different textures for the iPad3 and 4?  That’s tricky if you want to have a “Universal” app; one that can be loaded on any type of i-device, and still fit within that 50 Mbyte OTA download limit. One solution is not to care about the download limit. I didnt’ like that one. Or one could have two different versions of your app. That’s a potential QA problem and Apple (anecdotally) seems to like it better if you make Universal apps.

CPU/GPU performance:  I found that the 1.0 version of Numberheads worked great on the iPads and the iPhone 5. Not so great on the iPhone 4 and iPod Touch 4. They ran, but there were “hiccups” when a lot of pieces were moving around or when a lot of animated effects are fired-off at the same time.

Smaller amounts of DRAM on the older devices: well sure! Memory warnings will kill-off your app as quickly as an uninitialized pointer. Well maybe not – you do get a warning. But in a game there’s not a lot you can do aside from maybe calling the Garbage Collector (if you’re using something like C# with .net, like Unity3D games).

Don’t touch that Bat-channel if you want to hear more….

2.0 and Ready To Go

Posted: April 17, 2013 in News
Tags: , ,

After lots of graphic redesign and performance optimizations for iPhone, Numberheads 2.0 is about to be submitted to the Apple App Store on Friday. Check here again next week for lots of free promo codes…

Numberheads is still the same game, just visually a lot nicer and much more addictive…

Teaser page