- Home /
Is this the best for performance?
Hello,
I need to have health bars above enemies. There is a LOT of enemies in the map and I need the most optimized solution. I want to enable the OnGUI only when the camera is near enough to those objects.
What I did is I attached separate Script to each object, which has only OnGUI with drawing of the healthBar.
What I am doing now is enabling / disabling this component when the object is around like this:
(This function is called only once half a second to optimize it even more)
void updateGUI()
{
GUI_SpaceShip[] script = GameObject.FindObjectsOfType<GUI_SpaceShip>();
foreach(Component ship in script)
{
Vector2 distance = ship.gameObject.transform.position - cameraTransform.position;
if (distance.magnitude < 300)
ship.GetComponent<GUI_SpaceShip>().enabled = true;
else
ship.GetComponent<GUI_SpaceShip>().enabled = false;
}
}
But ofc the thing is there could be even 500+ objects in the scene. Do you think it could be done better way?
Answer by Kiwasi · Nov 17, 2014 at 11:39 PM
This is very bad. Very, very bad. I'll run through some of your performance fails here.
1) From the documentation of FindObjectsOfType:
Please note that this function is very slow. It is not recommended to use this function every frame. In most cases you can use the singleton pattern instead.
Build a single manager script. Have every GUI_SpaceShip register in Awake and deregister in OnDestroy. (Or use OnEnable and OnDisable if you prefer). Then run through your loop.
2) Store the actual components you wish to access. Using GetComponent is relatively slow. Calling GetComponent to get the component you already have is madness. So change your for loop to
foreach(GUI_SpaceShip ship in script)
3) For straight distance comparisons use sqrMagnitude, instead of magnitude. Its cheaper and achieves the identical result. Don't use square roots unless you have to.
@GrahamDunnett's approach of only registering when ready to display is another valid optimisation. Typically you don't display health bars on items with no damage, so that could be further used to optimise.
The other big optimisation would be to abandon OnGUI. OnGUI is notoriously slow and inefficient, and is seldom used on high performance published games.
1) Ah so when the ship is spawned/created it will add itself to some array of the main script right? And when destroyed it will remove it self? - How would I go about removing itself from the array?
2) Very good point. Will surely do that.
3) Ok will try it but I think sqr$$anonymous$$agnitude is multiplied so it isn`t good measure of length.
For those still interested in the following question: "How would I go about removing itself from the array?" You can't. You just use a List ins$$anonymous$$d, then you can use the Add() o Remove() methods.
Answer by Graham-Dunnett · Nov 17, 2014 at 09:30 PM
I think what I would do is have a script which handles the health bar drawing. The spaceships can then individually call this script and tell the script that they are close enough to be drawn, or have moved too far away to be visible. All the health bar script then needs do is iterate over the list of spaceships it contains and draw the health bar for each.
Yes but I can`t "call" GUI. The GUI is and I don`t believe I can pass there parameters as ships health or position.
Or I don`t understand :) Would I then have one GUI script, that loops through each ship and draws the bar, or I would have every ship individually checking distance to player and calling some other function. (But other functions cant draw)
Your answer
Follow this Question
Related Questions
Selecting shader based on video card 1 Answer
How to speed up loading and optimize my game? 1 Answer
Mesh with multiple Material IDs 0 Answers
Optimizing script to improve lag 1 Answer
Function On GUI 2 Answers