#"Synced GameObject" Pooling

1 messages · Page 1 of 1 (latest)

cedar flax
#

Hi there! Fairly new to DOTS so please bare with me. I'm trying to convert some critical aspects of my game over to DOTS. The game currently uses heavy object pooling to get as far as it can (performance wise), but I've decided to start storing and manipulating some of the most performance critical data using ECS with an eye towards possibly moving some subsets of these GameObjects fully into Entities.

As a starting point, a "GameObject Sync" approach, as demonstrated in the HelloCube sample seems like a reasonable approach to start manipulating the vital data (i.e just the transforms to start) in ECS without rewriting the whole game.

In the HelloCube "GameObjectSync" example, we Instantiate (and associate) GameObjects using a given a prefab defined in the "Directory" per entity- but this raises concerns of possibly accruing substantial GC since the game will be adding and removing a substantial number of these. Formerly, the GameObjects (which are now Entities represented by a synced GameObject) were being pooled heavily to minimize GC.

To keep the question simple- is it common to "pool" the representative "synced" GameObjects of Entities as they are added and removed? Is it simply a matter of hooking up my existing GameObject pooling system into the System controlling adding and removing entities? The HelloCube example shows an example of simply Instantiating and syncing a single Entity, but what's the best approach if they are going to be frequently added and removed from the scene. If there are any examples and/or patterns I could use as a basis for this it would be helpful.

I'm also completely open to any other suggestions, so please feel free to tell me that I'm way off the mark here. Any other examples / resources that fit my use case of getting some portions of critical data from MonoBehaviour classes into ECS to transmute (and subsequently drive logic in the existing MonoBehaviour) would be extremely helpful as well. Thanks for reading!

limber nova
#

mixing game objects and entities - bad idea.
Instead you can just utilize jobs and burst

#

basically, just jobify your performance critical logic

#

but still be part of game objects

cedar flax
#

Heya! Thanks for responding :). I started down this road- but the problem I ran into was that I had to reference the actual transforms constantly within the jobs and it was a huge bottleneck

#

there are two very large logical groupings of transforms interacting with each other, so iterating through those and getting them into a native array was by far the biggest hit on performance- and the actual parallelized job was barely anything while profiling

limber nova
cedar flax
#

Oh wow, must have missed that :x

limber nova
#

it lets you thread and burst transform related modifications

cedar flax
#

thanks so much!

#

i think i will still convert one of those sets of objects fully into entities. i should be able to mix and match entity component data with the game object transforms within a job?

limber nova
#

think of entities as particles

#

you'll have exact same problem of attaching particle to game object

#

nvm, bad example

#

the point is - converting game object projects to entities = x3 time of redoing whole project as entities from scratch

#

as well as going through absolute hell

cedar flax
#

hmmm point well taken.

limber nova
#

so just jobifying logic will give you much better results in much shorter time

cedar flax
#

well thanks very much for your input. seems like i have to rethink the approach 😛

hidden reef
#

possibly moving some subsets of these GameObjects fully into Entities

#

Dont do this, if you're going to do this, better remake the project in ECS as a whole, not a subset.

#

(minus UI stuffs)

#

But you can always make it a hybrid ECS: entity with a GameObject presenter.

#

You can design a pool for your GameObject presenter, utilizing GameObject.InstantiateGameObjects to instantiate them in batch.

#

After instantiating, add them to a TransformAccessArray and use indices of this array to link the entity with its intended gameobject.

#

The entities with GameObject presenter will have a component (e.g TransformIndex) to store this index

#

One tip: add an empty gameobject at the first index of the array, so index=0 always means "null" or default.

#

To use IJobParallelForTransform, you should maintain 3 lists (for position, rotation and scale), whenever you add more items to the TransformAccessArray, these lists should also be expanded to match the array.

hidden reef
#
[BurstCompile]
private partial struct SyncTransformJob : IJobParallelForTransform
{
    [ReadOnly] public NativeArray<float3> positions;
    [ReadOnly] public NativeArray<Optional<quaternion>> rotations;
    [ReadOnly] public NativeArray<Optional<float3>> scales;

    [BurstCompile]
    public void Execute(int index, TransformAccess transform)
    {
        transform.position = positions[index];

        var rotation = rotations[index];
        var scale = scales[index];

        if (rotation.HasValue)
        {
            transform.rotation = rotation.Value;
        }

        if (scale.HasValue)
        {
            transform.localScale = scale.Value;
        }
    }
}
#

Usage:

var syncJob = new SyncTransformJob {
    positions = positions.AsDeferredJobArray(),
    rotations = rotations.AsDeferredJobArray(),
    scales = scales.AsDeferredJobArray(),
};

state.Dependency = syncJob.ScheduleByRef(transformAccessArray, state.Dependency);
limber nova
#

You have to run transform job in any case

#

See no much reason to optimize it much

#

In fact, not even sure if that way is faster

#

You run 2 jobs vs 1

hidden reef
#

Yeah, you're right, I might forget something about this part of the project. Why did I design it like that? 🤔

#

Oh I remember now the why: because each type of entity has a different logic to compose their transform data.

#

It's not a 1:1 copy

#

But yeah, now my design seems to be overcomplicated.

#

All of my pools write to only 1 transform access array.

#

But each pool should have an array of its own.

cedar flax
#

thanks very much @hidden reef appreciate the input! yes, the plan was to use hybrid objects. and infact, i'm still going with that approach 🙂