But nothing really stands out at me. I know 30 draw calls is the upper limit of what’s acceptable on the iPhone, but at this point I can’t reduce them without rewriting my game (which is otherwise done, save for optimizing and debugging).
update calls are done by the engine, you can’t make them conditionally.
wouldn’t change much though the problem is your frametime and I guess related the draw calls which spikes up.
find out why and see if you can use static and/or dynamic batching to your favor if you alter / combine textures into a single texture set. Because right now, no batching happens at all
I assume I could replace the Update calls with a function name of my own choosing, and then call them from Update in my Master function… but if there is a better way to go about it, please let me know!
It seems odd that you have 30 draw calls and none of them are batched. I assume your game has static game geometry (i.e. rendered game objects that do not move around). If so, make sure all of these objects are marked as static. The easiest way to do this is to create an empty game object in your scene, drag all the static objects onto that game object in the inspector, and then check the “static” check box on the parent object. That will mark the parent object and all child objects as static and allow Unity to batch their associated draw calls together. (Unity will ask you about marking all of the child objects as static as well when you mark the parent object as static.) Batching draw calls will very significantly increase performance.
With respect to your Update calls, make sure that only things that absolutely must be done there are being done there. All game object references, including references to any transforms you are manipulating should be looked up in your Awake or Start functions (the references typically don’t change so looking them up over and over again is a waste), and make sure all variables are declared outside of the Update function unless there is a very good reason for not doing this. If you want to post your Update function, we can take a look at them and advise as to how to optimize them.
Finally, I see you are using physics but are not updating physics in FixedUpdate. You should not update physics in Update. Updating physics in FixedUpdate will ensure that the updates happen at a a fixed interval rather than every frame. This also allows you to then manipulate the fixed update interval (i.e. how frequently FixedUpdate is called) if necessary. And, of course, you should use physics sparingly as it is relatively expensive. Again, without knowing more about your game, it hard to provide comment on whether what you are doing is appropriate, so if you want more advice, you’ll need to post your Update script(s).
I don’t have Pro, so I can’t use static batching, and I’m downgrading to 1.0.3 so I can’t even use Dynamic.
Besides, I’m doing 2D graphics and wrote my own scripts to handle animating them, so I can’t combine textures into a single file without rewriting the whole game.
Well, I have over 50 scripts, and most of them have update calls! But I might be able to use coroutines instead…
I’m actually not using physics at all, so I guess I just need to make sure all rigid bodies are deleted…
Okay, in that case, make sure you use the combine meshes script where you can on all static objects that use common materials, which will also reduce draw calls where possible. If you built your game geometry by cobbling together primitive game objects in Unity, combining meshes which use the same materials will help greatly. If you created your meshes more monolithically in a 3D graphics tool, then this may help less (depends on whether further mesh combinations are possible).
If you are animating your sprites by manipulating texture offsets, make sure you access them via the sharedMaterial property of the renderer like this:
I don’t follow why you can’t combine your animation textures into one or more texture atlases. This is just cut and paste in Photo Shop or whatever tool you use. You should, if possible, have one (or a few) texture atlas(es) with one material each, and then use that material for all of your sprites.
And definitely remove any rigidbodies that are unnecessary. Just keep in mind that if you are using rigidbodies to impose gravity or drag, or to react to collisions, you are still using physics even if you do not manipulate physics in any script. Obviously getting rid of them will remove this behavior from your game, and you may not want that.
Because I wrote my own 2D animation ‘engine’, and it expects each frame of animation to be a separate material. Basically, I have animation scripts which change the materials every few milliseconds.
Currently each animation script checks the object state and exits the script if a frame change is not needed, but I could probably reduce Update calls if I just enable/disable the scripts as needed.
Understood, but you might want to rethink your approach as it is going to not perform optimally. If you go with a texture atlas then all you are doing in each frame is changing the texture offset which is highly efficient. The rest of your code should still work.
That makes sense definitely. You can always take a look at reworking your approach after you initially publish your game, by making changes incrementally with each update. You’ll find that doing frequent updates is also beneficial in that it makes the game look fresh to all your customers on iTunes.
Rather than start a new thread, I’ll just bump this one…
I solved my problem with sluggish performance by:
Reducing transform.localScale calls.
I was calling this in Update to lengthen an object over time, but scaling must be expensive on the iPhone. I changed my code so it would only perform scale a few times per second, and saw an immediate improvement in performance.
Reducing geometry.
My game is 2D, so I replaced the cylinders in the game with planes. Increased overall frame rate.
Dynamic Batching
Retried my game on Unity iPhone 1.5, this time it worked… so I simplified some of my art to better take advantage of dynamic batching. This reduced draw calls (averages around 21-25 now) and increased overall frame rate.
Depending on your game geometry, you might want to look at swapping out your mesh colliders for box colliders. That should give you a performance gain as well.
But globally, I suggest to reduce Update() use, and build your code architecture around triggers.
With Update(), you’re litterally spamming the machine with instructions that are not guaranteed to be useful. And that’s a horsepower loss.
It will always be better to trigger your events at the right time, only when you need it.
The dark side is that you will have to pass more variables to functions (as there are no more listeners), but at the end it also turns out to make your code clearer, seeing what variables your functions are handling, just in their header.
Also, this trigger state of mind makes coroutines shine even brighter, as they take the new role of parametric mini-Update().
Here is an example, in a behaviour where a player sprints to a goal line, then wave his hand, and then return back to start :
Update() coding logic :
void Update() {
if (_player.position.x <= 40F) _player.Translate(1F,0F,0F);
else if (_player.position.x > 40F !_waveHand) WaveHand();
if (_waveHand) {
_hand.Rotate(5F,0F,0F);
if (_hand.eulerAngles.x > 45F) {
_waveHand = false;
_player.position = new Vector3(0F, 0F, 0F);
}
}
}
void WaveHand(){
_hand.eulerAngles = new Vector3(0F,0F,0F);
_waveHand = true;
}
Here, you spam a lot of tests, which are not necessarly needed.
Now let’s see with Coroutine coding logic :
void Start() {
StartCoroutine(PlayerSprint());
}
IEnumerator PlayerSprintTo(float _goal) {
while (_player.position.x <= _goal) {
_player.Translate(1F,0F,0F);
yield return new WaitForEndOfFrame();
}
yield return StartCoroutine(WaveHand(45F));
_player.position = new Vector3(0F, 0F, 0F);
}
IEnumerator WaveHand(Transform _hand, float _maxAngle) {
_hand.eulerAngles= new Vector3(0F,0F,0F);
while (_hand.eulerAngles.x < 45F) {
_hand.Rotate(5F,0F,0F);
yield return new WaitForEndOfFrame();
}
}
Here, not only you got a cleaner code, but better perfs thanks to avoiding the Update() spam, and cherry on the cake : you can even specify where your goal is, and how much you want your player to wave his hand before returning back to base.