Hello guys! I’d like to start out by saying I’m not the greatest programmer - I’m an artist but I get by enough. I am trying to combat a lot of GC and performance during functions that I call that do something over a specific time frame (a sword swing that happens in 1 second, for example).
The problem is a lot of GC gets collected over the wait for seconds call, I’m not familiar with the coroutine method and wish to know the most optimized way to structure a simple function that does something over time (like attack)
My method is simply:
function Attack(){
var time: float = 0;
animation.Play();
while (time < 1){ //or yield WaitForSeconds(1);
time += Time.deltaTime;
transform.lookat(enemy);
yield;
}
doDamage(10);
}
The whole coroutine uses 0.7kb though (highlighted in red)- I’m more concerned that the total cpu usage of the function alone is 20% which seems like a lot, wouldn’t that be considered high? I feel like my method is primitive and can be improved on its performance
I think you might be mistaken by what that 20% represents.
It’s not 20% of total CPU usage. It’s 20% of the processing cycle of the game. 20% of what is actually going on is that… if you had more going on, it’d be less, because more things would be taking up stuff.
It’d be like if you had to clean your room, and your room had to have its bed made, the clothes put away, and the floor vaccuumed. The bed making is 33% of the workload. Where as if you added more to the workload, say organize a bookshelf, and dust everything. Now making the bed is 20% of the workload.
You could then compare that to the actual system usage (look in task manager for that), the coroutines activity would be 20% of the overall system usage, which is probably puttering along at some small percentage of total system capacity.
As for the caching, this is useful if you were using a yield instruction like WaitForSeconds. But in your code above you use no yield instructions, you just yield nothing.
And if you want to yield for 0 seconds, like brianasu is showing… yield null. Why even allocate a yield instruction for that? Yielding WaitForSeconds(0) waits 1 frame, which yield null does as well.
It’s literally an empty pointer to an object. How would that get boxed?
Also, they’re not yielding a WaitForSeconds, they’re using a while loop to wait 1 second. They could move to using a WaitForSeconds, in which case they should cache the yield instruction, but as it stands… that while loop uses no garbage. Actually, it’d use less than the WaitForSeconds option since the WaitForSeconds would result in needing to create that object.
As it stands, their ‘Attack’ method is as performant memory wise as it can be. Hence the minimal amount of garbage it has… which is unavoidable. A coroutine is going to create some garbage no matter what, since the coroutine itself is an object!
That is of course barring any garbage created in ‘doDamage’.
Either way though, this is such a poster child case of premature optimization, I sincerely would like to impress upon OP that it’s not a huge concern. I believe they’re misunderstanding what those numbers in the profiler mean, hence my previous post about what that 20% actually represents.
Hmm, I see what you’re saying here. I’m glad to hear that is the most optimal method of an attack cycle function (as I’ve already implemented in several places). I see now what that 20% represents- being an optimized freak early on I like to keep things clean and orderly before it gets out of hand, I know GC is one of those things.