11using System ;
22using System . Collections . Generic ;
3+ using UnityEngine ;
4+ using Object = UnityEngine . Object ;
35
46// ReSharper disable once CheckNamespace
57
68namespace GameLovers . Services
79{
810 /// <summary>
9- /// This interface allows pooled objects to be notified when it is spawned
10- /// </summary>
11- public interface IPoolEntitySpawn
12- {
13- /// <summary>
14- /// Invoked when the Entity is spawned
15- /// </summary>
16- void OnSpawn ( ) ;
17- }
18-
19- /// <summary>
20- /// This interface allows pooled objects to be notified when it is despawned
21- /// </summary>
22- public interface IPoolEntityDespawn
23- {
24- /// <summary>
25- /// Invoked when the entity is despawned
26- /// </summary>
27- void OnDespawn ( ) ;
28- }
29-
30- /// <summary>
31- /// Simple pool implementation that can handle any type of entity objects
11+ /// This service allows to manage multiple pools of different types.
12+ /// The service can only a single pool of the same type.
3213 /// </summary>
3314 public interface IPoolService
3415 {
3516 /// <summary>
3617 /// Initializes a new pool with the given <paramref name="initialSize"/>
3718 /// It invokes the <paramref name="instantiator"/> function every time a new entity is created in the pool
3819 /// </summary>
39- void InitPool < T > ( int initialSize , Func < T > instantiator ) ;
20+ void InitPool < T > ( int initialSize , Func < T > instantiator ) where T : new ( ) ;
4021
4122 /// <summary>
4223 /// Initializes a new pool with the given <paramref name="initialSize"/> and a sample entity given back in the <paramref name="instantiator"/>
4324 /// It invokes the <paramref name="instantiator"/> function every time a new entity is created in the pool
4425 /// </summary>
45- void InitPool < T > ( int initialSize , T sampleEntity , Func < T , T > instantiator ) ;
26+ void InitPool < T > ( int initialSize , T sampleEntity , Func < T , T > instantiator ) where T : Object ;
4627
4728 /// <summary>
4829 /// Checks if exists a pool of the given type already exists or needs to be initialized with
@@ -53,65 +34,34 @@ public interface IPoolService
5334 /// <inheritdoc cref="HasPool{T}"/>
5435 bool HasPool ( Type type ) ;
5536
56- /// <summary>
57- /// Spawns and returns an entity of the given type <typeparamref name="T"/>
58- /// This function does not initialize the entity. For that, have the entity implement <see cref="IPoolEntitySpawn"/> or do it externally
59- /// This function throws a <exception cref="StackOverflowException" /> if the pool is empty
60- /// </summary>
37+ /// <inheritdoc cref="IObjectPool{T}.Spawn"/>
6138 T Spawn < T > ( ) ;
6239
63- /// <summary>
64- /// Despawns the given <paramref name="entity"/> and returns it back to the pool to be used again later
65- /// This function does not reset the entity. For that, have the entity implement <see cref="IPoolEntityDespawn"/> or do it externally
66- /// </summary>
40+ /// <inheritdoc cref="IObjectPool{T}.Despawn"/>
6741 void Despawn < T > ( T entity ) ;
6842
69- /// <summary>
70- /// Despawns all active spawned entities of the given type <typeparamref name="T"/> and returns them back to the pool to be used again later
71- /// This function does not reset the entity. For that, have the entity implement <see cref="IPoolEntityDespawn"/> or do it externally
72- /// </summary>
43+ /// <inheritdoc cref="IObjectPool{T}.DespawnAll"/>
7344 void DespawnAll < T > ( ) ;
7445
75- /// <summary>
76- /// Clears the pool of the given type <typeparamref name="T"/>
77- /// It calls <paramref name="clearAction"/> with every entity remaining in the pool and managed by the pool
78- /// </summary>
79- void Clear < T > ( Action < T > clearAction ) ;
46+ /// <inheritdoc cref="IObjectPool{T}.Clear"/>
47+ void Clear < T > ( ) ;
8048 }
8149
8250 /// <inheritdoc />
8351 public class PoolService : IPoolService
8452 {
85- private readonly Dictionary < Type , IPoolStack > pools = new Dictionary < Type , IPoolStack > ( ) ;
53+ private readonly Dictionary < Type , IObjectPool > _pools = new Dictionary < Type , IObjectPool > ( ) ;
8654
8755 /// <inheritdoc />
88- public void InitPool < T > ( int initialSize , Func < T > instantiator )
56+ public void InitPool < T > ( int initialSize , Func < T > instantiator ) where T : new ( )
8957 {
90- InitPool ( initialSize , instantiator . Invoke ( ) , newEntity => instantiator . Invoke ( ) ) ;
58+ _pools . Add ( typeof ( T ) , new ObjectPool < T > ( initialSize , instantiator ) ) ;
9159 }
9260
9361 /// <inheritdoc />
94- public void InitPool < T > ( int initialSize , T sampleEntity , Func < T , T > instantiator )
62+ public void InitPool < T > ( int initialSize , T sampleEntity , Func < T , T > instantiator ) where T : Object
9563 {
96- if ( pools . ContainsKey ( typeof ( T ) ) )
97- {
98- throw new InvalidOperationException ( $ "The pool of type { typeof ( T ) } was already initialized") ;
99- }
100-
101- var pool = new PoolStack < T >
102- {
103- Stack = new Stack < T > ( ) ,
104- SpawnedEntities = new List < T > ( ) ,
105- SampleEntity = sampleEntity ,
106- Instatiator = instantiator
107- } ;
108-
109- pools . Add ( typeof ( T ) , pool ) ;
110-
111- for ( int i = 0 ; i < initialSize ; i ++ )
112- {
113- pool . Stack . Push ( instantiator . Invoke ( sampleEntity ) ) ;
114- }
64+ _pools . Add ( typeof ( T ) , new GameObjectPool < T > ( initialSize , sampleEntity , instantiator ) ) ;
11565 }
11666
11767 /// <inheritdoc />
@@ -123,88 +73,195 @@ public bool HasPool<T>()
12373 /// <inheritdoc />
12474 public bool HasPool ( Type type )
12575 {
126- return pools . ContainsKey ( type ) ;
76+ return _pools . ContainsKey ( type ) ;
12777 }
12878
12979 /// <inheritdoc />
13080 public T Spawn < T > ( )
13181 {
132- var pool = GetPool < T > ( ) ;
133- T entity = pool . Stack . Count == 0 ? pool . Instatiator . Invoke ( pool . SampleEntity ) : pool . Stack . Pop ( ) ;
134- var poolEntity = entity as IPoolEntitySpawn ;
135-
136- pool . SpawnedEntities . Add ( entity ) ;
137- poolEntity ? . OnSpawn ( ) ;
138-
139- return entity ;
82+ return GetPool < T > ( ) . Spawn ( ) ;
14083 }
14184
14285 /// <inheritdoc />
14386 public void Despawn < T > ( T entity )
14487 {
145- var pool = GetPool < T > ( ) ;
146- var poolEntity = entity as IPoolEntityDespawn ;
147-
148- pool . Stack . Push ( entity ) ;
149- pool . SpawnedEntities . Remove ( entity ) ;
150- poolEntity ? . OnDespawn ( ) ;
88+ GetPool < T > ( ) . Despawn ( entity ) ;
15189 }
15290
15391 /// <inheritdoc />
15492 public void DespawnAll < T > ( )
15593 {
156- var pool = GetPool < T > ( ) ;
157-
158- foreach ( T entity in pool . SpawnedEntities )
159- {
160- var poolEntity = entity as IPoolEntityDespawn ;
94+ GetPool < T > ( ) . DespawnAll ( ) ;
95+ }
16196
162- pool . Stack . Push ( entity ) ;
163- poolEntity ? . OnDespawn ( ) ;
97+ /// <inheritdoc />
98+ public void Clear < T > ( )
99+ {
100+ GetPool < T > ( ) . Clear ( ) ;
101+ _pools . Remove ( typeof ( T ) ) ;
102+ }
103+
104+ private IObjectPool < T > GetPool < T > ( )
105+ {
106+ if ( ! _pools . TryGetValue ( typeof ( T ) , out IObjectPool pool ) )
107+ {
108+ throw new ArgumentException ( "The pool was not initialized for the type " + typeof ( T ) ) ;
164109 }
165-
166- pool . SpawnedEntities . Clear ( ) ;
110+
111+ return pool as IObjectPool < T > ;
167112 }
113+ }
114+
115+ /// <summary>
116+ /// This interface allows pooled objects to be notified when it is spawned
117+ /// </summary>
118+ public interface IPoolEntitySpawn
119+ {
120+ /// <summary>
121+ /// Invoked when the Entity is spawned
122+ /// </summary>
123+ void OnSpawn ( ) ;
124+ }
125+
126+ /// <summary>
127+ /// This interface allows pooled objects to be notified when it is despawned
128+ /// </summary>
129+ public interface IPoolEntityDespawn
130+ {
131+ /// <summary>
132+ /// Invoked when the entity is despawned
133+ /// </summary>
134+ void OnDespawn ( ) ;
135+ }
136+
137+ /// <summary>
138+ /// This interface allows pooled objects to be notified when they are cleared from the pool
139+ /// </summary>
140+ public interface IPoolEntityCleared
141+ {
142+ /// <summary>
143+ /// Invoked when the entity is cleared
144+ /// </summary>
145+ void OnCleared ( ) ;
146+ }
147+
148+ /// <summary>
149+ /// Simple object pool implementation that can handle any type of entity objects
150+ /// </summary>
151+ public interface IObjectPool
152+ {
153+ /// <summary>
154+ /// Clears the pool
155+ /// This function does not clear the entity. For that, have the entity implement <see cref="IPoolEntityCleared"/> or do it externally
156+ /// </summary>
157+ void Clear ( ) ;
158+
159+ /// <summary>
160+ /// Despawns all active spawned entities and returns them back to the pool to be used again later
161+ /// This function does not reset the entity. For that, have the entity implement <see cref="IPoolEntityDespawn"/> or do it externally
162+ /// </summary>
163+ void DespawnAll ( ) ;
164+ }
165+
166+ /// <inheritdoc />
167+ public interface IObjectPool < T > : IObjectPool
168+ {
169+ /// <summary>
170+ /// Spawns and returns an entity of the given type <typeparamref name="T"/>
171+ /// This function does not initialize the entity. For that, have the entity implement <see cref="IPoolEntitySpawn"/> or do it externally
172+ /// This function throws a <exception cref="StackOverflowException" /> if the pool is empty
173+ /// </summary>
174+ T Spawn ( ) ;
175+
176+ /// <summary>
177+ /// Despawns the given <paramref name="entity"/> and returns it back to the pool to be used again later
178+ /// This function does not reset the entity. For that, have the entity implement <see cref="IPoolEntityDespawn"/> or do it externally
179+ /// </summary>
180+ void Despawn ( T entity ) ;
181+ }
168182
183+ /// <inheritdoc />
184+ public abstract class ObjectPoolBase < T > : IObjectPool < T >
185+ {
186+ private readonly Stack < T > _stack = new Stack < T > ( ) ;
187+ private readonly IList < T > _spawnedEntities = new List < T > ( ) ;
188+ private readonly Func < T , T > _instantiator ;
189+ private readonly T _sampleEntity ;
190+
191+ protected ObjectPoolBase ( int initSize , T sampleEntity , Func < T , T > instantiator )
192+ {
193+ _sampleEntity = sampleEntity ;
194+ _instantiator = instantiator ;
195+
196+ for ( var i = 0 ; i < initSize ; i ++ )
197+ {
198+ _stack . Push ( instantiator . Invoke ( sampleEntity ) ) ;
199+ }
200+ }
201+
169202 /// <inheritdoc />
170- public void Clear < T > ( Action < T > clearAction )
203+ public void Clear ( )
171204 {
172- var pool = GetPool < T > ( ) ;
173-
174- for ( var i = 0 ; i < pool . Stack . Count ; i ++ )
205+ for ( var i = 0 ; i < _stack . Count ; i ++ )
175206 {
176- T entity = pool . Stack . Pop ( ) ;
207+ var entity = _stack . Pop ( ) as IPoolEntityCleared ;
177208
178- clearAction ? . Invoke ( entity ) ;
209+ entity ? . OnCleared ( ) ;
179210 }
180211
181- pool . SpawnedEntities . Clear ( ) ;
182- pools . Remove ( typeof ( T ) ) ;
212+ _spawnedEntities . Clear ( ) ;
183213 }
184214
185- private PoolStack < T > GetPool < T > ( )
215+ /// <inheritdoc />
216+ public T Spawn ( )
186217 {
187- if ( ! pools . TryGetValue ( typeof ( T ) , out IPoolStack poolStack ) )
188- {
189- throw new ArgumentException ( "The pool was not initialized for the type " + typeof ( T ) ) ;
190- }
218+ var entity = _stack . Count == 0 ? _instantiator . Invoke ( _sampleEntity ) : _stack . Pop ( ) ;
219+ var poolEntity = entity as IPoolEntitySpawn ;
220+
221+ _spawnedEntities . Add ( entity ) ;
222+ poolEntity ? . OnSpawn ( ) ;
223+
224+ return entity ;
225+ }
226+
227+ /// <inheritdoc />
228+ public void Despawn ( T entity )
229+ {
230+ var poolEntity = entity as IPoolEntityDespawn ;
231+
232+ _stack . Push ( entity ) ;
233+ _spawnedEntities . Remove ( entity ) ;
234+ poolEntity ? . OnDespawn ( ) ;
235+ }
191236
192- if ( poolStack is PoolStack < T > pool )
237+ /// <inheritdoc />
238+ public void DespawnAll ( )
239+ {
240+ for ( var i = 0 ; i < _spawnedEntities . Count ; i ++ )
193241 {
194- return pool ;
242+ Despawn ( _spawnedEntities [ i ] ) ;
195243 }
196-
197- throw new ArgumentException ( "The pool was not properly initialized for the type " + typeof ( T ) ) ;
244+
245+ _spawnedEntities . Clear ( ) ;
198246 }
199-
200- private interface IPoolStack { }
247+ }
248+
249+ /// <inheritdoc />
250+ public class ObjectPool < T > : ObjectPoolBase < T > where T : new ( )
251+ {
252+ public ObjectPool ( int initSize , Func < T > instantiator ) : base ( initSize , instantiator ( ) , newEntity => instantiator . Invoke ( ) )
253+ {
254+ }
255+ }
201256
202- private class PoolStack < T > : IPoolStack
257+ /// <inheritdoc />
258+ /// <remarks>
259+ /// <see cref="IObjectPool"/> implementation for objects of type <see cref="Object"/>
260+ /// </remarks>
261+ public class GameObjectPool < T > : ObjectPoolBase < T > where T : Object
262+ {
263+ public GameObjectPool ( int initSize , T sampleEntity , Func < T , T > instantiator ) : base ( initSize , sampleEntity , instantiator )
203264 {
204- public Stack < T > Stack ;
205- public List < T > SpawnedEntities ;
206- public Func < T , T > Instatiator ;
207- public T SampleEntity ;
208265 }
209266 }
210267}
0 commit comments