Skip to content

Removing Boiler Plate for Spawning Prefabs. #78

@SimonNordon4

Description

@SimonNordon4

Right now it's a lot of setup to just spawn a prefab.

The class looks like this:

public class Before : MonoBehaviour, IPoolable<IMemoryPool>, IDisposable
        {
            private IMemoryPool _pool;
            
            public void OnDespawned()
            {
                _pool = null;
            }

            public void OnSpawned(IMemoryPool p1)
            {
                _pool = p1;
            }

            public void Dispose()
            {
                _pool.Despawn(this);
            }
            
            public class Factory : PlaceholderFactory<Before>
            { }
            public class Pool : MonoPoolableMemoryPool<IMemoryPool, Before>
            { }
        }

        public class AfterInstaller : MonoInstaller
        {
            public After prefab;
            
            public override void InstallBindings()
            {
                Extensions.BindPoolable<After>(Container,
                    c => c.WithInitialSize(5)
                        .FromComponentInNewPrefab(prefab)
                        .UnderTransformGroup("After")
                        .AsCached());
            }
        }
        
        public class After : PoolableMonoBehaviour<After>
        {
      
        }

and the binding looks like this

        public class BeforeInstaller : MonoInstaller
        {
            public Before prefab;
            
            public override void InstallBindings()
            {
                Container.BindFactory<Before, Before.Factory>()
                    .FromPoolableMemoryPool<Before, Before.Pool>(pool => pool
                        .WithInitialSize(5)
                        .FromComponentInNewPrefab(prefab)
                        .UnderTransformGroup("Before")
                        .AsCached());
            }
        }

I wrote a wrapper class for this kind of thing.

        public abstract class PoolableMonoBehaviour<T> : MonoBehaviour, IPoolable<IMemoryPool>, IDisposable where T : PoolableMonoBehaviour<T>
        {
            protected IMemoryPool _pool;

            public void OnSpawned(IMemoryPool pool)
            {
                _pool = pool;
                OnSpawnedInternal();
            }

            public virtual void OnSpawnedInternal()
            {
                
            }

            public void OnDespawned()
            {
                OnDespawnedInternal();
            }

            public virtual void OnDespawnedInternal()
            {
                
            }
            

            public virtual void Dispose() => _pool.Despawn(this);
            
            public class Factory : PlaceholderFactory<T>
            { }
            
            public class Pool : MonoPoolableMemoryPool<IMemoryPool, T>
            { }
        }

Right now it doesn't support parameters, but that would be easy to do, just duplicate the class and add TParam infront of Every IMermoryPool.

I also wrote an extension method for binding

namespace Zenject.Extensions  
{
    public static class Extensions
    {
        public static ArgConditionCopyNonLazyBinder BindPoolable<TPoolable>
            (DiContainer container,Action<MemoryPoolInitialSizeMaxSizeBinder<TPoolable>> poolBinder)
        where TPoolable : PoolableMonoBehaviour<TPoolable>
        {
            var x = container
                .BindFactory<TPoolable, PoolableMonoBehaviour<TPoolable>.Factory>()
                .FromPoolableMemoryPool<TPoolable, PoolableMonoBehaviour<TPoolable>.Pool>
                    (poolBinder);
            return x;
        }
    }
}

With these new scripts, the code goes from looking like it did at the top to this:

        public class AfterInstaller : MonoInstaller
        {
            public After prefab;
            
            public override void InstallBindings()
            {
                Extensions.BindPoolable<After>(Container,
                    c => c.WithInitialSize(5)
                        .FromComponentInNewPrefab(prefab)
                        .UnderTransformGroup("After")
                        .AsCached());
            }
        }
        
        public class After : PoolableMonoBehaviour<After>
        {
      
        }

This makes it mech easier to for a gameobject to return itself to the pool

        public class After : PoolableMonoBehaviour<After>
        {
            private float lifetime = 1f;
            public override void OnSpawnedInternal()
            {
                lifetime = 1f;
            }
            
            private void Update()
            {
                lifetime -= Time.deltaTime;
                if (lifetime <= 0)
                {
                    Dispose();
                }
            }
        }

This isn't really an issue, just now that Extenject isn't being supported I thought it would be useful for people trying to wrap their heads around prefab spawning.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions