- Home /
Decreasing project size by eliminating prefabs and creating everything from code
Hey all,
I've noticed for a game I'm working on, which includes tons of GUITextures (iOS), I've ended up using a lot of prefabs in the Resources folder that are simply a GameObject with a GUITexture component.
In efforts to drastically reduce or completely eliminate all the prefabs in memory, I've taken to instantiating a new GameObject in code and adding any components, changing settings, etc. Is this more efficient? For example:
Originally, it'd be something like:
GameObject deathIconO; GUITexture deathIcon;
void Start()
{
deathIconO = Resources.Load("GUI/Icons/deathIconPrefab") as GameObject;
}
void Update()
{
...
deathIcon = Instantiate(deathIconO.guiTexture) as GUITexture;
...
}
However, this meant for each GUITexture that went up, we'd have a texture in memory AND a prefab. Now, I'm doing:
Texture deathIconTex; GUITexture deathIcon;
void Start()
{
deathIconTex = Resources.Load("GUI/Icons/Texture/deathIconTexture") as Texture;
}
void Update()
{
...
GameObject deathIconO = new GameObject();
deathIconO.AddComponent<GUITexture>();
deathIcon = deathIconO.guiTexture;
deathIcon.texture = deathIconTex;
// adjust size, pixel inset, transform options, etc...
...
}
The reason I bother to store the texture used for each icon in a private variable is because there are lots of menus opened all the time, so it saves a call to Resources.Load every time you open each menu.
Is this more efficient? This way, for each icon we only have NO prefabs in the project, just textures (which were there before). Just curious if this would make sense. Thanks for any input!
Answer by dannyskim · May 01, 2012 at 09:46 PM
It won't help much at all. If you take a look at the Console Editor Log ( 'Open Editor Log' button on the Console Window ), you'll be able to see what exactly your package is comprised off before it hits XCode after you build. Prefabs taking more space than your textures is pretty much not going to be the case 99.9% of the time, nor will doing this have any appreciable effect on your package size.
Simply put, using GUITextures is fairly inefficient in regards to package size. Standard practice in the gaming industry ( and even application design when heavy on UI ) is to atlas your textures ( aka sprite sheet, altas sheet ). At first, most people may think how will combining textures into one bigger sheet help at all?
Well, if you're making pixel perfect textures for your GUI ( which you should be ), then atlas'ing them becomes a much more efficient option because you can cram NPOT ( Non-Power of Two ) textures into an atlas, whereas you can't do that with individual textures ( you can, but they take up approximately 4 times the space of a power of two texture ). In turn, the atlas sheet itself is generated as a POT( power of two ) texture, optimizing your texture sizes by utilizing as much space as possible without wasting memory.
GUITextures is pretty much the most primitive form of GUI that I could possibly recommend using. Have I used them? Yes, but your package size will always suffer unless you design your GUI to be flexible and reusable ( such as sliced sprites, font atlases, etc).
In short, what you're doing isn't going to help at all. I would suggest getting a GUI plug-in such as NGUI ( available on the asset store ), or roll your own GUI system.
Can you elaborate on not how they're stored, because I understand the concepts behind sprite sheets, but how it is actually displayed? Does it use orthographic projection onto the camera, or what?
Just curious, and thank you so much for the response. $$anonymous$$ay have to consider this. :)
It draws the texures directly to the screen, bypassing the camera. Basically, Unity's inbuilt GUI system isn't very good (in general), not least because it has no texture atlassing capabilities whatsoever...
Little anecdote about UnityGUI- I'm currently working on a TD game, and at one point I wanted to display a little bit of debug info above my creeps for some reason. I figured, the simplest way was to just put an OnGUI function on the creep, and draw stuff with that (quick, easy, right?). Turns out, that simply putting an empty OnGUI function in my Creep script, for even a reasonable number of creeps (<200) sent my framerate down by almost a factor of 5. It's really, really not worth it in almost all situations- you'd be best served to just write your own (or if you're happy to fork the money out for them, using one of the many 'advanced UI' packages out there on the Asset Store).
whereas you can't do that with individual textures ( you can, but they take up approximately 4 times the space of a power of two texture )
That's not true at all. A project with two GUI textures, 40x64 and 24x64, uses 12.2$$anonymous$$B in the build for textures, whereas a project with one GUI texture, 64x64, uses 12.1$$anonymous$$B in the build. (As to why there's any difference at all, I would assume because of extra overhead with more than one texture, even if the number of pixels is the same.)
Yes, in the build they take up that much space, but as soon as they get loaded into the graphics card you still have the same problem. I'm not aware of any common graphics cards that support NPOT textures.
As far as I know, most modern graphics card do NPOT; the main reason not to (at least in the past) was because of mipmapping, which you're not using with GUITextures anyway.
Answer by Eric5h5 · May 02, 2012 at 02:51 AM
No, it's not more efficient. You're making things harder on yourself and your project worse for no gain. Why not just do a simple test? Make a test project with a GUITexture prefab, and then replace that with code to create a GUITexture, and compare the two builds. (Hint: the build without the prefab is actually larger.) Also in general I'd suggest using public variables with drag'n'drop instead of using Resources.Load, unless there's a compelling reason not to.
First off, I'm confused by that; one project would have a texture, the other would have a texture AND a prefab. How would it possibly be smaller?
So you would suggest making everything public, and should I make prefabs first or drag'n'drop textures in?
It's smaller because the project with just the texture has more code for generating the object at runtime! Prefabs basically do this already, keep in $$anonymous$$d, except that the code for generating the objects at runtime already exists in the engine, and so not using it only creates unneeded overhead (since you can't avoid including the whole UnityEngine dll in your builds).
I doubt a prefab takes more than a few bytes or so. The code needed to generate the same thing that's in a prefab is more expensive than just using a prefab.
Answer by Comaleaf · May 01, 2012 at 09:52 PM
Edit: Daniel Kim's comment suggests you may want to avoid UnityGUI for performance reasons. Having done some cursory checking that does seem to be the case. My original answer is below, but keep the performance cost in mind. Some info here.
If you use UnityGUI rather than GUI objects, you won't need to use prefabs at all.
For drawing GUI textures, you can use `GUI.DrawTexture`.
If you're worried about performance along with your package size, I would suggest not using UnityGUI (OnGUI, which GUI.DrawTexture resides).
GUI.Repaint is utterly resource intensive on a mobile device, and will slow things down ultimately. If this is a purely UI based application, I would say you could go for it, but if the GUI resides anywhere in parallel with gameplay, do not use it.
Thanks @dannyskim - I did not know about that! $$anonymous$$ay have to now redo a lot of GUI on my own project... I've updated my answer.