I have a grass-prefab that instantiates iteself in one of 8 positions around itself after some time creating a grid of prefabs. Currently I check for other grass-prefabs using 8 trigger-colliders per prefab. See screenshot below:
The problem is that unity slows down after instantiating only a bunch of them.
I'm open to any suggestions concerning performance improvements.
Here's my code:
using UnityEngine;
public class GrassController : MonoBehaviour
{
[SerializeField] private float growthRate = 1.1f;
[SerializeField] private float maxSize = 1f;
[SerializeField] private float reproduceEffort = 0.1f;
[SerializeField] private GameObject prefab;
[SerializeField] private GameObject sprite;
[SerializeField] private ReproduceHitBoxController[] reproduceHitBoxes;
[SerializeField] private float size = 0f;
private float initialSize = 0.1f;
private void Awake()
{
size = initialSize;
ApplyGrowth();
}
private void FixedUpdate()
{
if (size < maxSize) Grow();
else Reproduce();
}
private void Grow()
{
size *= growthRate;
if (size >= maxSize) size = maxSize;
ApplyGrowth();
}
private void ApplyGrowth()
{
sprite.transform.localScale = new Vector3(size, size, sprite.transform.position.z);
}
private void Reproduce()
{
var reproduceHitBox = reproduceHitBoxes[Random.Range(0, reproduceHitBoxes.Length)];
if (reproduceHitBox.tagInCollider == true) return;
Instantiate(prefab, reproduceHitBox.transform.position, Quaternion.identity);
size -= reproduceEffort;
}
}
Edit: Seems like the main drag on performance are all the physics-checks. Are there ways to check for other gameObjects in a certain area that are more performant?
Solution: I ended up creating a Dictionary<Vector3,GrassController>
to save all objects by their position so I only have to iterate over the adjacent positions for each check I make. Note that this approach has some potential issues as
CodePudding user response:
What I'm currently seeing in the profiler.
Physics
is a very broad term of Unity, that tells you that Nvidia Physx is in use. It is responsible for "Performant*" collision checks, and this is what you are currently seeing.
Because on how Physx works, for objects that are "close-by" you are doing basically check "each-with-each" on each FixedUpdate
.
There is more information in the profiler on which subsystems of Physix is currently taking 800ms this given frames span.
How to fix this issue
Stop using collision, colliders, and triggers for everything that will never be moved by Unity Physics. Instead use clever data structures to make check for "if the grass is next to the object" without doing check "each-with-each"
- Keep reference of each grown grass nearby and use list of such objects to check if there is a grass nearby (Tricky to implement but very optimal) NOTE: You should never have more then 8 objects in such list.
- Implement a "Grid" based system or so-called Chunks. Then check for grass in each of the Grid Cells if the given cell is occupied. This will only work if you have everything in equal distance from each other, but can be adapted to work without this restriction - (this is the most universal solution that you should use, also easiest o implement.)
- Use Quadtree (Octree for 3D). This will create contant-size nested "Chunks" of increased resolution that will give you O(LogN) performance for checking if something is next to you. (This is best for confined space games, that you know have limits on map size). NOTE: This is what Physx uses under the hood, but it's bloated for 3D and Physics movement
- BRUTE FORCE METHOD If you know that you will never have more then let's say 1000 grass objects and you know that the "Grow" method will be used less than once per frame, you can have a Controler with a list of all of Grass objects. Iteration over 1000 elements in a list will take 0.01-0.05ish milliseconds depending on the platform. So I would say the bearable cost to live with.
Personally, I would go with number 4 for now, and expand to number 2 or 3 when the cost of Grow will generate a lag-spikes for low-end platforms. (3-5ms or more)
CodePudding user response:
disable the plant rendering component. which are not appearing on the screen.