I’m trying to figure out if the part of my game is a performance killer.
I’m reworking Cubenaut, and I’ve made some pretty big changes under the hood. Previously, I had a “collisionMap” shell around each level. Essentially all the blocks that compose a maze, joined into one mesh with the interior walls deleted. I’ve done away with that and now use raycasts to check for edges. In order to get it to work JUST right though, I’m using 10 (!) raycasts each frame.
I’m having some performance issues, and don’t really know where to look for a culprit. Are my raycasts excessive? Each one is about 2 units in length and positioned and pointing in a different place.
I’ll attach some of the raycast code, I’m also doing a tag comparison, and someone mentioned that those can be expensive… Well I’m doing quite a few of them.
RaycastHit[] hitsLeft;
hitsLeft = Physics.RaycastAll(lineLeft, transform.forward*1.0f, 1.0f);
while (i<hitsLeft.Length)
{
RaycastHit hit = hitsLeft[i];
if (hit.collider.gameObject.tag == "Waypoint")
{
hitColliderLeft = true;
}
i++;
}
I’d really appreciate any advice I can get on performance tweaks. Cubenaut was always playable on my iPod 2g in the past, but now it struggles on larger levels. This doesn’t seem like it should be the case, The geometry is SO simple. A maze is a few dozens of interconnected simple blocks that all share a single material with only a color, no texture.
There are other places I KNOW I can improve performance, but it would mean sacrificing novel new functionality. I’m hoping to fix it in the unseen places first.
If you don’t mind elaborating, why would a single mesh be more performant than multple meshes equaling the same poly-count? I don’t think that’s something I can do without breaking the core mechanics of the game… but I’ll think about how it might work, thank you.
Any ideas on the hit from either the raycasts or the many tag comparisons? How much are those hurting me?
10 raycasts per frame are certainly a bit too much. At least try offsetting them by a couple of frames if possible. String comparisons are always a bad idea. You’d be better off with a layer check. Don’t worry about multiple meshes as long as they are under 300 verts and sharing the same material (they’ll just batch).
Hunting down framerate is going to be a very long process without a profiler. Chances are it’s something you haven’t even thought of, like sound or something.
Thank you for the input. I’ve reworked it so that 2-4 rays are drawn per frame instead of all 10. I’m also checking for the layer number instead of the tag name. I’ll post back if the speed improves.
Yes, but without Pro I don’t have the option of a profiler. I have some ideas where my framerate is going anyway, but I’m hesitant to adjust those features as I am very happy with them.
I may need to make an HD version with some of those extra features though.
lots of separate meshes but with the same polygons will tax the cpu a LOT more than a couple of raycasts
because each separate mesh becomes a draw call, and this is performed on the cpu
An easy fix:
enable static batching
ensure that each block’s scale is 1,1,1
ensure the renderer.sharedMaterial and material of each block is the same
change the uv mapping instead to change the apparence of blocks
This should batch them together without any more fancy tricks and yield a lot less cpu time wasted. Try profiling. Use the profiler in appcontroller.mm. Stop guessing.
Batching isn’t a free process, it’s very good if you have to use it but if you can use a single mesh then there’s no reason not to with the exception of culling but you can then create a mesh for each room which would be better than having rooms made of individual objects
culling is very important do to the game mechanics of cubenaut. You can only see one “slice” of a maze at any given time. When you rotate, you see another slice. each slice is lets say 100,100,1. I have an ortho camera that does not extend past the first slice, so it might not matter…
hippocoder: 1)static batching is enabled by default, is it not? I’ll double check. 2) yes, each block is 1,1,1 3) each block shares the same material, but I’ll have to check out renderer.sharedMaterial… I honestly don’t know about that 4) no problem there, until I decide to put a coat of paint on the game I’m not texturing the maze. It has a very “retro” look, although an artist might simply describe it as boring, lol.
Is there no way to cull any of the shapes using layers. I noticed that you are doing raycastAll rather than simply using the first raycast hit. Do all raycasts need to be cast every frame can you stagger them over 2-3.
aiursrage2k: I think that raycast vs raycastall was the last piece of the puzzle. I started to reply that it had to be raycastall, but realized with the layer changes I did today that was no longer needed. I’ve changed it now, and the worst performant level is definitely better than it was this morning.
Raycast vs raycastall, no tag comparisons, and spacing my raycasts across several frames speeds it up enough that it’s playable on an ipod 2g, albeit slower than on a 4g device.
Thank you all for the suggestions today, I was concerned I would need to abandon the older hardware. I’m not even sure how that would have worked since this is an upgrade rather than a new app.
I realized static batching is pro only, I was thinking dynamic batching was the pro feature. oops.
Physics.Raycast really shouldn’t slow you down at just 10 per frame. We are doing a LOT more than that for ‘cheap’ pathing checks to avoid more expensive re-calculations and I have had way more than 10 per frame with no issues. RaycastAll would be more worrying, especially since you have to loop over them instead of just taking what gets hit first as a single thing. You could also use a single larger collider to cover many objects if that works for your game. For example, you can have a separate game object with no geometry and a big square collider which covers an entire wall of blocks (if that makes sense in the context of your game.)