Converting GameObjects with many children and scripts to Entities

I have a GameObject with a Rigidbody, and 3 scripts attached. That GameObject has hundreds of children, each with a BoxCollider and a MeshRenderer.

One of the 3 scripts in the parent moves and rotates the GameObject in an Update() method. Given that the GameObject has many children, moving and rotating is really expensive and kills my FPS.

  1. Can I apply ECS only to that script and leave the other two as they are?

  2. When I convert the parent GameObject into an Entity, I have to manually convert the children into entities too, right?

  3. If so, how can I make the children entities move according to the parent position and rotation? Do I have to deal with their localPosition and localRotation manually?

  4. Are there any tutorials on doing this? I couldn’t find any.

Thanks in advance!

Unless you are willing to commit to Unity.Physics or Havok Physics, switching to ECS probably isn’t going to get you the gains you want without an extreme amount of extra work. I suspect your performance issue has to do with all those children colliders moving. Might want to check your physics settings.

Thank you for your reply. What physics settings should I check? I am new to Unity and I have no clue.

The main one is to make sure Reuse Collision Callbacks is checked. Besides that, I can’t really say much without knowing the details of your project and seeing your profiling results.

You really should work on GameObjects and your scripts for now, if you new to Unity. DOTS will be far too much to grasp at beginning of dev journey.

IJobParallelForTransform would let you “go wide across all your cores” with the rotations without having to make everything ECS. Along with maybe using Transform.RotateAround() ? But a simple computation on hundreds of simple objects seems like what ECS is ideal for

Not exactly. It’s working by root per thread. If you have TransformA on top of your scene and all another transforms inside this TransformA, it will processind only on one thread.

1 Like

Thank you for all your replies.

Sadly it’s already checked.
Using the profiler I can see that around 70% of the CPU is constantly used in the call.

FixedUpdate.PhysicsFixedUpdate
Physics.Processing
Physics.FetchResults
Physics.UpdateBodies

Does this help at all?

Maybe that’s true, but also maybe this is the only way to deal with my problem. I have been trying to find a solution for days and everyone says I should use ECS/DOTS.

Does this mean I wouldn’t get any gains by changing that part of the project to ECS/DOTS? Also, do you know where I can learn to move and rotate the parent along with their children?

This is something than classic OOP way handles very well, with even few thousands. Unless you collide all objects at once. Which is normally not the case. So in my opinion, you should really focus on solving that challenge in classic way first. It will allow you to understand what causes issues and how to deal with it in future. Also, if this scales into DOTS as well.

Without that, using DOTS is kind of like abusing its performance gain, rather than actual building up performant code.
Chances are, you may be still stuck without an answer. Or you will find some time in future :wink:

Well, any hints on what may be the problem? Each cube belongs to the layer “Enemy” and I already have disabled collisions among GameObjects in that same layer. The code that moves the Enemy is simply a Move Towards and Look at inside an Update.

Two simple things come to mind in terms of Classic Mono/Gameobjects setup :

  • Check if you are not moving any static colliders manually. Meaning Game objects with only Colliders but no Rigid body attached. This can lead to severe overheads for large number of static colliders being translated. Ensure that all collider objects also a have Rigidbody component attached. You can Set Rigidbody as Kinematic if you don’t want it to be affected by physics interactions.
  • Are you using deeply nested hierarchies ? Transforming complex gameobject hierarchies has its own overhead that adds up quickly with increasing depth and count. Try flattening the hierarchy as much possible. Here is some more info regarding this : Unity Blog

As mentioned above , it should be fairly straightforward and quite performant when doing simple translations of this kind , even on scale of thousand units without use of ECS/DOTS

@ramiroagis can you post script(s) here?

Show us please your hierarchy tree.

  • I wasn’t aware of that, thank you! However, I just tried adding Rigidbodies to the cubes and it’s actually lowering my FPS even more. Without using Rigidbodies in the cubes I can handle 11 enemies simultaneously without going below 60 FPS (disabling everything else from the game). Using Rigidbodies I can handle only 7. Is this normal?
  • The enemy hierarchy only has only 2 levels. The root is composed of the “Seeker” script (see below). Then, the root’s children are 223 cubes composed of a Mesh Renderer, a Cube Mesh Filter, the “EnemyPart” script (see below), and a Capsule Collider (I just changed the Box Colliders for Capsules because I found out these are actually less expensive).

I described the hierarchy right above. Here is the code:

using UnityEngine;

public class Seeker : MonoBehaviour
{
    [SerializeField] private float movementSpeed;
    private Transform target;

    private void Start()
    {
        target = GameManager.instance.GetPlayer().transform;
    }

    private void Update()
    {
        transform.LookAt(target.position);
        transform.position = Vector3.MoveTowards(transform.position, target.position, movementSpeed * Time.deltaTime);
    }
}
using UnityEngine;

public class EnemyPart : MonoBehaviour
{
    private void OnCollisionEnter(Collision collision)
    {
        transform.parent = null;
        gameObject.tag = "HarmlessPart";
        Destroy(gameObject, 5f);

        if (gameObject.GetComponent<Rigidbody>() == null)
        {
            gameObject.AddComponent<Rigidbody>();
        }

        Destroy(this);
    }
}

Take into account that the “OnCollisionEnter” is only executed when the player is shooting projectiles to the enemy, but right now I am not shooting, just testing the performance of the movement alone.

Why you cerate RigidBody at runtime?
Create prefabs with all needed components and use these to instantiate all required objects at startup.
Then use pooling mechanism. Don’t use Destroy.
Instantiating and destroying objects is expensive.
Here is your first major bottleneck.

As I mentioned before, OnCollisionEnter is not being executed because I am not shooting to the Enemies. I am just testing Enemy movement.

Anyway, I add a Rigidbody to each collided Cube on runtime because I want them to fall with gravity. I already tried adding Rigidbodies to the cubes in the prefab, but it’s actually lowering my FPS even more. Without using Rigidbodies in the cubes (and adding them at runtime when necessary) I can actually handle more enemies, for some reason I don’t understand.

How can I use a pooling mechanism in this particular case?

@ramiroagis
What is your computer spec?
What is your CPU usage, when run simulation?
With RigidBodies, you shouldn’t be using transform.position.
Either using physics to control movement with RigidBody MovePosition, or AddForce (s).
If you don’t want gravity all the time, disable default one and create own, which you can control.

This thread fits to scripting forum, rahter DOTS.

If you just destroy for testing, to see if is collision and never recreate objects that case may be ok.
Otherwise, you should keep object in array, or list then track, which objects are used in scene and which one are ready to be used.