├── .github └── FUNDING.yml ├── .gitignore ├── CHANGELOG.md ├── CHANGELOG.md.meta ├── LICENSE.md ├── LICENSE.md.meta ├── README.md ├── README.md.meta ├── Source.meta ├── Source ├── AutoPool.cs ├── AutoPool.cs.meta ├── Demo.meta ├── Demo │ ├── DemoScene.unity │ ├── DemoScene.unity.meta │ ├── Pools.meta │ ├── Pools │ │ ├── DeathFXPool.asset │ │ ├── DeathFXPool.asset.meta │ │ ├── TriggeredPool.asset │ │ └── TriggeredPool.asset.meta │ ├── Prefabs.meta │ ├── Prefabs │ │ ├── DeathFX.prefab │ │ ├── DeathFX.prefab.meta │ │ ├── TriggerCube.prefab │ │ └── TriggerCube.prefab.meta │ ├── QFSW.MOP2.Demo.asmdef │ ├── QFSW.MOP2.Demo.asmdef.meta │ ├── Scripts.meta │ └── Scripts │ │ ├── ReleaseOnCollision.cs │ │ ├── ReleaseOnCollision.cs.meta │ │ ├── TriggerSpawner.cs │ │ └── TriggerSpawner.cs.meta ├── Editor.meta ├── Editor │ ├── EditorHelpers.cs │ ├── EditorHelpers.cs.meta │ ├── MOPInspectorBase.cs │ ├── MOPInspectorBase.cs.meta │ ├── MasterObjectPoolerInspector.cs │ ├── MasterObjectPoolerInspector.cs.meta │ ├── ObjectPoolInspector.cs │ ├── ObjectPoolInspector.cs.meta │ ├── ObjectPoolPostProcessor.cs │ ├── ObjectPoolPostProcessor.cs.meta │ ├── QFSW.MOP2.Editor.asmdef │ └── QFSW.MOP2.Editor.asmdef.meta ├── IPoolable.cs ├── IPoolable.cs.meta ├── MasterObjectPooler.cs ├── MasterObjectPooler.cs.meta ├── ObjectPool.cs ├── ObjectPool.cs.meta ├── PoolableMonoBehaviour.cs ├── PoolableMonoBehaviour.cs.meta ├── PopulateMethod.cs ├── PopulateMethod.cs.meta ├── QFSW.MOP2.asmdef ├── QFSW.MOP2.asmdef.meta ├── Textures.meta └── Textures │ ├── Banner.png │ ├── Banner.png.meta │ ├── BannerCutout.png │ ├── BannerCutout.png.meta │ ├── Pool.png │ └── Pool.png.meta ├── package.json └── package.json.meta /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: QFSW 2 | patreon: QFSW 3 | custom: paypal.me/QFSW 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.blend[1-9] 2 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | V1.0.3 2 | Addition 0002: Scale of objects is now properly reset by the pool 3 | Change 0001: Support for legacy .NET 3.5 has been dropped 4 | 5 | V1.0.2 6 | Bug Fix 0001: Fixed MasterObjectPooler.Destroy 7 | 8 | V1.0.1 9 | Addition 0001: Added GetAllActiveObjects to ObjectPool and MasterObjectPooler 10 | 11 | V1.0.0 12 | Initial release -------------------------------------------------------------------------------- /CHANGELOG.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 4b52b062418dde844bce68fe98ffba5b 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 QFSW 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8d8aa9c49a0d6d1428f4ae8776c3b80d 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 |

5 | 6 | 7 | 8 |

9 | 10 | Master Object Pooler 2 is a high performance, flexible and easy to use object pooling solution that can fit into any Unity project. 11 | 12 | [Full Documentation and API Reference](https://www.qfsw.co.uk/docs/MOP2) 13 | 14 | [Unity Asset Store](https://assetstore.unity.com/packages/tools/utilities/master-object-pooler-2-146525) 15 | 16 | ### Getting Started 17 | 18 | In order to get started, create an `ObjectPool` for your desired object. 19 | 20 | - Use `Create -> Master Object Pooler 2 -> Object Pool` to create it at edit time 21 | - Use `ObjectPool.CreateInstance()` to create one at runtime 22 | 23 | Once you have an `ObjectPool`, use `pool.GetObject()` and `pool.Release()` in place of all `Instantiate` and `Destroy` calls. This means objects will be recycled through the pool, reducing GC and greatly improving efficiency. 24 | 25 | Using a `MasterObjectPooler` can greatly ease the use of managing multiple pools. Pools can be added to it either in the inspector, or at runtime with `AddPool`. Once added to the pool, you can use all of the normal pool functions (or retrieve the pool) with a string reference. 26 | 27 | ### Extras 28 | 29 | `AutoPool` is a script that can be added to any object to make it automatically pool itself after a surpassed amount of time. The parent pool is injected to the pool via the `IPoolable` component, so you do not need to do it yourself 30 | 31 | You can make your own scripts that use the parent pool by implementing `IPoolable` 32 | 33 | Any script deriving from or using `PoolableMonoBehaviour` will have a new `Release` method, allowing you to release the object without needing a reference to its pool 34 | 35 | MOP2 also provides `GetObjectComponent`, a GC free method of getting the object component. This should be used whenever possible to improve efficiency. 36 | 37 | ### Installing via Package Manager 38 | #### 2019.3+ 39 | Starting with Unity 2019.3, the package manager UI has support for git packages 40 | 41 | Click the `+` to add a new git package and add `https://github.com/QFSW/MasterObjectPooler2.git` as the source 42 | 43 | #### 2018.3 - 2019.2 44 | To install via package manager, add the file `Packages/manifest.json` and add the following line to the `"dependencies"` 45 | ``` 46 | "com.qfsw.mop2": "https://github.com/QFSW/MasterObjectPooler2.git" 47 | ``` 48 | Your file should end up like this 49 | ``` 50 | { 51 | "dependencies": { 52 | "com.qfsw.mop2": "https://github.com/QFSW/MasterObjectPooler2.git", 53 | ... 54 | }, 55 | } 56 | ``` 57 | 58 | #### Install via OpenUPM 59 | The package is available on the [openupm registry](https://openupm.com). It's recommended to install it via [openupm-cli](https://github.com/openupm/openupm-cli). 60 | 61 | ``` 62 | openupm add com.qfsw.mop2 63 | ``` 64 | 65 | Thanks to [`caprapaul`](https://github.com/caprapaul) for logo work. 66 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c99400b1d9040774dac36259ed0ed45f 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Source.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 9fe5e859fef53264087690e8591abe68 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Source/AutoPool.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace QFSW.MOP2 4 | { 5 | /// 6 | /// Automatically releases an object after the specified amount of time has surpassed. 7 | /// 8 | [DisallowMultipleComponent] 9 | public class AutoPool : PoolableMonoBehaviour 10 | { 11 | [Tooltip("The duration of time to wait before releasing the object to the pool.")] 12 | [SerializeField] private float _poolTimer = 1; 13 | 14 | [Tooltip("Whether to use scaled or unscaled time.")] 15 | [SerializeField] private bool _scaledTime = true; 16 | 17 | private float _elapsedTime; 18 | 19 | private void OnEnable() 20 | { 21 | _elapsedTime = 0; 22 | } 23 | 24 | private void Update() 25 | { 26 | if (_scaledTime) { _elapsedTime += Time.deltaTime; } 27 | else { _elapsedTime += Time.unscaledDeltaTime; } 28 | 29 | if (_elapsedTime > _poolTimer && PoolReady) { Release(); } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /Source/AutoPool.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c1d21e76924a1114e9b72179a8c1bde7 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Source/Demo.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cb6b8dfacb5303b4c998c664aab97d7b 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Source/Demo/DemoScene.unity: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!29 &1 4 | OcclusionCullingSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_OcclusionBakeSettings: 8 | smallestOccluder: 5 9 | smallestHole: 0.25 10 | backfaceThreshold: 100 11 | m_SceneGUID: 00000000000000000000000000000000 12 | m_OcclusionCullingData: {fileID: 0} 13 | --- !u!104 &2 14 | RenderSettings: 15 | m_ObjectHideFlags: 0 16 | serializedVersion: 9 17 | m_Fog: 0 18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} 19 | m_FogMode: 3 20 | m_FogDensity: 0.01 21 | m_LinearFogStart: 0 22 | m_LinearFogEnd: 300 23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} 24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} 25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} 26 | m_AmbientIntensity: 1 27 | m_AmbientMode: 0 28 | m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} 29 | m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} 30 | m_HaloStrength: 0.5 31 | m_FlareStrength: 1 32 | m_FlareFadeSpeed: 3 33 | m_HaloTexture: {fileID: 0} 34 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} 35 | m_DefaultReflectionMode: 0 36 | m_DefaultReflectionResolution: 128 37 | m_ReflectionBounces: 1 38 | m_ReflectionIntensity: 1 39 | m_CustomReflection: {fileID: 0} 40 | m_Sun: {fileID: 0} 41 | m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} 42 | m_UseRadianceAmbientProbe: 0 43 | --- !u!157 &3 44 | LightmapSettings: 45 | m_ObjectHideFlags: 0 46 | serializedVersion: 11 47 | m_GIWorkflowMode: 1 48 | m_GISettings: 49 | serializedVersion: 2 50 | m_BounceScale: 1 51 | m_IndirectOutputScale: 1 52 | m_AlbedoBoost: 1 53 | m_EnvironmentLightingMode: 0 54 | m_EnableBakedLightmaps: 1 55 | m_EnableRealtimeLightmaps: 1 56 | m_LightmapEditorSettings: 57 | serializedVersion: 12 58 | m_Resolution: 2 59 | m_BakeResolution: 40 60 | m_AtlasSize: 1024 61 | m_AO: 0 62 | m_AOMaxDistance: 1 63 | m_CompAOExponent: 1 64 | m_CompAOExponentDirect: 0 65 | m_ExtractAmbientOcclusion: 0 66 | m_Padding: 2 67 | m_LightmapParameters: {fileID: 0} 68 | m_LightmapsBakeMode: 1 69 | m_TextureCompression: 1 70 | m_FinalGather: 0 71 | m_FinalGatherFiltering: 1 72 | m_FinalGatherRayCount: 256 73 | m_ReflectionCompression: 2 74 | m_MixedBakeMode: 2 75 | m_BakeBackend: 1 76 | m_PVRSampling: 1 77 | m_PVRDirectSampleCount: 32 78 | m_PVRSampleCount: 512 79 | m_PVRBounces: 2 80 | m_PVREnvironmentSampleCount: 256 81 | m_PVREnvironmentReferencePointCount: 2048 82 | m_PVRFilteringMode: 1 83 | m_PVRDenoiserTypeDirect: 1 84 | m_PVRDenoiserTypeIndirect: 1 85 | m_PVRDenoiserTypeAO: 1 86 | m_PVRFilterTypeDirect: 0 87 | m_PVRFilterTypeIndirect: 0 88 | m_PVRFilterTypeAO: 0 89 | m_PVREnvironmentMIS: 1 90 | m_PVRCulling: 1 91 | m_PVRFilteringGaussRadiusDirect: 1 92 | m_PVRFilteringGaussRadiusIndirect: 5 93 | m_PVRFilteringGaussRadiusAO: 2 94 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5 95 | m_PVRFilteringAtrousPositionSigmaIndirect: 2 96 | m_PVRFilteringAtrousPositionSigmaAO: 1 97 | m_ShowResolutionOverlay: 1 98 | m_ExportTrainingData: 0 99 | m_LightingDataAsset: {fileID: 0} 100 | m_UseShadowmask: 1 101 | --- !u!196 &4 102 | NavMeshSettings: 103 | serializedVersion: 2 104 | m_ObjectHideFlags: 0 105 | m_BuildSettings: 106 | serializedVersion: 2 107 | agentTypeID: 0 108 | agentRadius: 0.5 109 | agentHeight: 2 110 | agentSlope: 45 111 | agentClimb: 0.4 112 | ledgeDropHeight: 0 113 | maxJumpAcrossDistance: 0 114 | minRegionArea: 2 115 | manualCellSize: 0 116 | cellSize: 0.16666667 117 | manualTileSize: 0 118 | tileSize: 256 119 | accuratePlacement: 0 120 | debug: 121 | m_Flags: 0 122 | m_NavMeshData: {fileID: 0} 123 | --- !u!1 &258284261 124 | GameObject: 125 | m_ObjectHideFlags: 0 126 | m_CorrespondingSourceObject: {fileID: 0} 127 | m_PrefabInstance: {fileID: 0} 128 | m_PrefabAsset: {fileID: 0} 129 | serializedVersion: 6 130 | m_Component: 131 | - component: {fileID: 258284264} 132 | - component: {fileID: 258284263} 133 | - component: {fileID: 258284262} 134 | m_Layer: 0 135 | m_Name: EventSystem 136 | m_TagString: Untagged 137 | m_Icon: {fileID: 0} 138 | m_NavMeshLayer: 0 139 | m_StaticEditorFlags: 0 140 | m_IsActive: 1 141 | --- !u!114 &258284262 142 | MonoBehaviour: 143 | m_ObjectHideFlags: 0 144 | m_CorrespondingSourceObject: {fileID: 0} 145 | m_PrefabInstance: {fileID: 0} 146 | m_PrefabAsset: {fileID: 0} 147 | m_GameObject: {fileID: 258284261} 148 | m_Enabled: 1 149 | m_EditorHideFlags: 0 150 | m_Script: {fileID: 1077351063, guid: f70555f144d8491a825f0804e09c671c, type: 3} 151 | m_Name: 152 | m_EditorClassIdentifier: 153 | m_HorizontalAxis: Horizontal 154 | m_VerticalAxis: Vertical 155 | m_SubmitButton: Submit 156 | m_CancelButton: Cancel 157 | m_InputActionsPerSecond: 10 158 | m_RepeatDelay: 0.5 159 | m_ForceModuleActive: 0 160 | --- !u!114 &258284263 161 | MonoBehaviour: 162 | m_ObjectHideFlags: 0 163 | m_CorrespondingSourceObject: {fileID: 0} 164 | m_PrefabInstance: {fileID: 0} 165 | m_PrefabAsset: {fileID: 0} 166 | m_GameObject: {fileID: 258284261} 167 | m_Enabled: 1 168 | m_EditorHideFlags: 0 169 | m_Script: {fileID: -619905303, guid: f70555f144d8491a825f0804e09c671c, type: 3} 170 | m_Name: 171 | m_EditorClassIdentifier: 172 | m_FirstSelected: {fileID: 0} 173 | m_sendNavigationEvents: 1 174 | m_DragThreshold: 10 175 | --- !u!4 &258284264 176 | Transform: 177 | m_ObjectHideFlags: 0 178 | m_CorrespondingSourceObject: {fileID: 0} 179 | m_PrefabInstance: {fileID: 0} 180 | m_PrefabAsset: {fileID: 0} 181 | m_GameObject: {fileID: 258284261} 182 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 183 | m_LocalPosition: {x: 0, y: 0, z: 0} 184 | m_LocalScale: {x: 1, y: 1, z: 1} 185 | m_Children: [] 186 | m_Father: {fileID: 0} 187 | m_RootOrder: 5 188 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 189 | --- !u!1 &319436628 190 | GameObject: 191 | m_ObjectHideFlags: 0 192 | m_CorrespondingSourceObject: {fileID: 0} 193 | m_PrefabInstance: {fileID: 0} 194 | m_PrefabAsset: {fileID: 0} 195 | serializedVersion: 6 196 | m_Component: 197 | - component: {fileID: 319436630} 198 | - component: {fileID: 319436629} 199 | m_Layer: 0 200 | m_Name: MOP 201 | m_TagString: Untagged 202 | m_Icon: {fileID: 0} 203 | m_NavMeshLayer: 0 204 | m_StaticEditorFlags: 0 205 | m_IsActive: 1 206 | --- !u!114 &319436629 207 | MonoBehaviour: 208 | m_ObjectHideFlags: 0 209 | m_CorrespondingSourceObject: {fileID: 0} 210 | m_PrefabInstance: {fileID: 0} 211 | m_PrefabAsset: {fileID: 0} 212 | m_GameObject: {fileID: 319436628} 213 | m_Enabled: 1 214 | m_EditorHideFlags: 0 215 | m_Script: {fileID: 11500000, guid: ae7d75d4e54c16b42b11bb89b17dc809, type: 3} 216 | m_Name: 217 | m_EditorClassIdentifier: 218 | _pools: 219 | - {fileID: 11400000, guid: fda3ff401ed679a42b9bfa77cd0e5e9e, type: 2} 220 | --- !u!4 &319436630 221 | Transform: 222 | m_ObjectHideFlags: 0 223 | m_CorrespondingSourceObject: {fileID: 0} 224 | m_PrefabInstance: {fileID: 0} 225 | m_PrefabAsset: {fileID: 0} 226 | m_GameObject: {fileID: 319436628} 227 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 228 | m_LocalPosition: {x: -1.3635218, y: -1.9983577, z: -1.1701345} 229 | m_LocalScale: {x: 1, y: 1, z: 1} 230 | m_Children: [] 231 | m_Father: {fileID: 0} 232 | m_RootOrder: 4 233 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 234 | --- !u!1 &565502365 235 | GameObject: 236 | m_ObjectHideFlags: 0 237 | m_CorrespondingSourceObject: {fileID: 0} 238 | m_PrefabInstance: {fileID: 0} 239 | m_PrefabAsset: {fileID: 0} 240 | serializedVersion: 6 241 | m_Component: 242 | - component: {fileID: 565502366} 243 | - component: {fileID: 565502367} 244 | m_Layer: 0 245 | m_Name: TriggerSpawner 246 | m_TagString: Untagged 247 | m_Icon: {fileID: 0} 248 | m_NavMeshLayer: 0 249 | m_StaticEditorFlags: 0 250 | m_IsActive: 1 251 | --- !u!4 &565502366 252 | Transform: 253 | m_ObjectHideFlags: 0 254 | m_CorrespondingSourceObject: {fileID: 0} 255 | m_PrefabInstance: {fileID: 0} 256 | m_PrefabAsset: {fileID: 0} 257 | m_GameObject: {fileID: 565502365} 258 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 259 | m_LocalPosition: {x: 0, y: 4, z: 0} 260 | m_LocalScale: {x: 1, y: 1, z: 1} 261 | m_Children: [] 262 | m_Father: {fileID: 0} 263 | m_RootOrder: 3 264 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 265 | --- !u!114 &565502367 266 | MonoBehaviour: 267 | m_ObjectHideFlags: 0 268 | m_CorrespondingSourceObject: {fileID: 0} 269 | m_PrefabInstance: {fileID: 0} 270 | m_PrefabAsset: {fileID: 0} 271 | m_GameObject: {fileID: 565502365} 272 | m_Enabled: 1 273 | m_EditorHideFlags: 0 274 | m_Script: {fileID: 11500000, guid: b15da39ad248b4348b731fd31367dd7c, type: 3} 275 | m_Name: 276 | m_EditorClassIdentifier: 277 | _triggerPool: {fileID: 11400000, guid: e683e348e50fc3b469897aaad3d5c342, type: 2} 278 | _spawnRate: 8 279 | _spawnSpeed: 3 280 | _spawnAngularSpeed: 6 281 | --- !u!1 &1183111172 282 | GameObject: 283 | m_ObjectHideFlags: 0 284 | m_CorrespondingSourceObject: {fileID: 0} 285 | m_PrefabInstance: {fileID: 0} 286 | m_PrefabAsset: {fileID: 0} 287 | serializedVersion: 6 288 | m_Component: 289 | - component: {fileID: 1183111176} 290 | - component: {fileID: 1183111175} 291 | - component: {fileID: 1183111174} 292 | - component: {fileID: 1183111173} 293 | m_Layer: 0 294 | m_Name: Floor 295 | m_TagString: Untagged 296 | m_Icon: {fileID: 0} 297 | m_NavMeshLayer: 0 298 | m_StaticEditorFlags: 0 299 | m_IsActive: 1 300 | --- !u!65 &1183111173 301 | BoxCollider: 302 | m_ObjectHideFlags: 0 303 | m_CorrespondingSourceObject: {fileID: 0} 304 | m_PrefabInstance: {fileID: 0} 305 | m_PrefabAsset: {fileID: 0} 306 | m_GameObject: {fileID: 1183111172} 307 | m_Material: {fileID: 0} 308 | m_IsTrigger: 0 309 | m_Enabled: 1 310 | serializedVersion: 2 311 | m_Size: {x: 1, y: 1, z: 1} 312 | m_Center: {x: 0, y: 0, z: 0} 313 | --- !u!23 &1183111174 314 | MeshRenderer: 315 | m_ObjectHideFlags: 0 316 | m_CorrespondingSourceObject: {fileID: 0} 317 | m_PrefabInstance: {fileID: 0} 318 | m_PrefabAsset: {fileID: 0} 319 | m_GameObject: {fileID: 1183111172} 320 | m_Enabled: 1 321 | m_CastShadows: 1 322 | m_ReceiveShadows: 1 323 | m_DynamicOccludee: 1 324 | m_MotionVectors: 1 325 | m_LightProbeUsage: 1 326 | m_ReflectionProbeUsage: 1 327 | m_RenderingLayerMask: 1 328 | m_RendererPriority: 0 329 | m_Materials: 330 | - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} 331 | m_StaticBatchInfo: 332 | firstSubMesh: 0 333 | subMeshCount: 0 334 | m_StaticBatchRoot: {fileID: 0} 335 | m_ProbeAnchor: {fileID: 0} 336 | m_LightProbeVolumeOverride: {fileID: 0} 337 | m_ScaleInLightmap: 1 338 | m_PreserveUVs: 0 339 | m_IgnoreNormalsForChartDetection: 0 340 | m_ImportantGI: 0 341 | m_StitchLightmapSeams: 1 342 | m_SelectedEditorRenderState: 3 343 | m_MinimumChartSize: 4 344 | m_AutoUVMaxDistance: 0.5 345 | m_AutoUVMaxAngle: 89 346 | m_LightmapParameters: {fileID: 0} 347 | m_SortingLayerID: 0 348 | m_SortingLayer: 0 349 | m_SortingOrder: 0 350 | --- !u!33 &1183111175 351 | MeshFilter: 352 | m_ObjectHideFlags: 0 353 | m_CorrespondingSourceObject: {fileID: 0} 354 | m_PrefabInstance: {fileID: 0} 355 | m_PrefabAsset: {fileID: 0} 356 | m_GameObject: {fileID: 1183111172} 357 | m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} 358 | --- !u!4 &1183111176 359 | Transform: 360 | m_ObjectHideFlags: 0 361 | m_CorrespondingSourceObject: {fileID: 0} 362 | m_PrefabInstance: {fileID: 0} 363 | m_PrefabAsset: {fileID: 0} 364 | m_GameObject: {fileID: 1183111172} 365 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 366 | m_LocalPosition: {x: 0, y: 0, z: 0} 367 | m_LocalScale: {x: 30, y: 1, z: 30} 368 | m_Children: [] 369 | m_Father: {fileID: 0} 370 | m_RootOrder: 2 371 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 372 | --- !u!1 &1568048506 373 | GameObject: 374 | m_ObjectHideFlags: 0 375 | m_CorrespondingSourceObject: {fileID: 0} 376 | m_PrefabInstance: {fileID: 0} 377 | m_PrefabAsset: {fileID: 0} 378 | serializedVersion: 6 379 | m_Component: 380 | - component: {fileID: 1568048508} 381 | - component: {fileID: 1568048507} 382 | m_Layer: 0 383 | m_Name: Directional Light 384 | m_TagString: Untagged 385 | m_Icon: {fileID: 0} 386 | m_NavMeshLayer: 0 387 | m_StaticEditorFlags: 0 388 | m_IsActive: 1 389 | --- !u!108 &1568048507 390 | Light: 391 | m_ObjectHideFlags: 0 392 | m_CorrespondingSourceObject: {fileID: 0} 393 | m_PrefabInstance: {fileID: 0} 394 | m_PrefabAsset: {fileID: 0} 395 | m_GameObject: {fileID: 1568048506} 396 | m_Enabled: 1 397 | serializedVersion: 9 398 | m_Type: 1 399 | m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} 400 | m_Intensity: 1 401 | m_Range: 10 402 | m_SpotAngle: 30 403 | m_InnerSpotAngle: 21.80208 404 | m_CookieSize: 10 405 | m_Shadows: 406 | m_Type: 2 407 | m_Resolution: -1 408 | m_CustomResolution: -1 409 | m_Strength: 1 410 | m_Bias: 0.05 411 | m_NormalBias: 0.4 412 | m_NearPlane: 0.2 413 | m_CullingMatrixOverride: 414 | e00: 1 415 | e01: 0 416 | e02: 0 417 | e03: 0 418 | e10: 0 419 | e11: 1 420 | e12: 0 421 | e13: 0 422 | e20: 0 423 | e21: 0 424 | e22: 1 425 | e23: 0 426 | e30: 0 427 | e31: 0 428 | e32: 0 429 | e33: 1 430 | m_UseCullingMatrixOverride: 0 431 | m_Cookie: {fileID: 0} 432 | m_DrawHalo: 0 433 | m_Flare: {fileID: 0} 434 | m_RenderMode: 0 435 | m_CullingMask: 436 | serializedVersion: 2 437 | m_Bits: 4294967295 438 | m_RenderingLayerMask: 1 439 | m_Lightmapping: 4 440 | m_LightShadowCasterMode: 0 441 | m_AreaSize: {x: 1, y: 1} 442 | m_BounceIntensity: 1 443 | m_ColorTemperature: 6570 444 | m_UseColorTemperature: 0 445 | m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} 446 | m_UseBoundingSphereOverride: 0 447 | m_ShadowRadius: 0 448 | m_ShadowAngle: 0 449 | --- !u!4 &1568048508 450 | Transform: 451 | m_ObjectHideFlags: 0 452 | m_CorrespondingSourceObject: {fileID: 0} 453 | m_PrefabInstance: {fileID: 0} 454 | m_PrefabAsset: {fileID: 0} 455 | m_GameObject: {fileID: 1568048506} 456 | m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} 457 | m_LocalPosition: {x: 0, y: 3, z: 0} 458 | m_LocalScale: {x: 1, y: 1, z: 1} 459 | m_Children: [] 460 | m_Father: {fileID: 0} 461 | m_RootOrder: 1 462 | m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} 463 | --- !u!1 &1761232578 464 | GameObject: 465 | m_ObjectHideFlags: 0 466 | m_CorrespondingSourceObject: {fileID: 0} 467 | m_PrefabInstance: {fileID: 0} 468 | m_PrefabAsset: {fileID: 0} 469 | serializedVersion: 6 470 | m_Component: 471 | - component: {fileID: 1761232581} 472 | - component: {fileID: 1761232580} 473 | - component: {fileID: 1761232579} 474 | m_Layer: 0 475 | m_Name: Main Camera 476 | m_TagString: MainCamera 477 | m_Icon: {fileID: 0} 478 | m_NavMeshLayer: 0 479 | m_StaticEditorFlags: 0 480 | m_IsActive: 1 481 | --- !u!81 &1761232579 482 | AudioListener: 483 | m_ObjectHideFlags: 0 484 | m_CorrespondingSourceObject: {fileID: 0} 485 | m_PrefabInstance: {fileID: 0} 486 | m_PrefabAsset: {fileID: 0} 487 | m_GameObject: {fileID: 1761232578} 488 | m_Enabled: 1 489 | --- !u!20 &1761232580 490 | Camera: 491 | m_ObjectHideFlags: 0 492 | m_CorrespondingSourceObject: {fileID: 0} 493 | m_PrefabInstance: {fileID: 0} 494 | m_PrefabAsset: {fileID: 0} 495 | m_GameObject: {fileID: 1761232578} 496 | m_Enabled: 1 497 | serializedVersion: 2 498 | m_ClearFlags: 2 499 | m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} 500 | m_projectionMatrixMode: 1 501 | m_GateFitMode: 2 502 | m_FOVAxisMode: 0 503 | m_SensorSize: {x: 36, y: 24} 504 | m_LensShift: {x: 0, y: 0} 505 | m_FocalLength: 50 506 | m_NormalizedViewPortRect: 507 | serializedVersion: 2 508 | x: 0 509 | y: 0 510 | width: 1 511 | height: 1 512 | near clip plane: 0.3 513 | far clip plane: 1000 514 | field of view: 60 515 | orthographic: 0 516 | orthographic size: 5 517 | m_Depth: -1 518 | m_CullingMask: 519 | serializedVersion: 2 520 | m_Bits: 4294967295 521 | m_RenderingPath: -1 522 | m_TargetTexture: {fileID: 0} 523 | m_TargetDisplay: 0 524 | m_TargetEye: 3 525 | m_HDR: 1 526 | m_AllowMSAA: 1 527 | m_AllowDynamicResolution: 0 528 | m_ForceIntoRT: 0 529 | m_OcclusionCulling: 1 530 | m_StereoConvergence: 10 531 | m_StereoSeparation: 0.022 532 | --- !u!4 &1761232581 533 | Transform: 534 | m_ObjectHideFlags: 0 535 | m_CorrespondingSourceObject: {fileID: 0} 536 | m_PrefabInstance: {fileID: 0} 537 | m_PrefabAsset: {fileID: 0} 538 | m_GameObject: {fileID: 1761232578} 539 | m_LocalRotation: {x: 0.084186025, y: 0.25783423, z: -0.02255758, w: 0.9622502} 540 | m_LocalPosition: {x: -5.3, y: 2.52, z: -3.69} 541 | m_LocalScale: {x: 1, y: 1, z: 1} 542 | m_Children: [] 543 | m_Father: {fileID: 0} 544 | m_RootOrder: 0 545 | m_LocalEulerAnglesHint: {x: 10, y: 30, z: 0} 546 | -------------------------------------------------------------------------------- /Source/Demo/DemoScene.unity.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 1c8dfb90e965eda48ab238ea9ffb482d 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Source/Demo/Pools.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cf62e450cd52c594fae99d9eb05978aa 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Source/Demo/Pools/DeathFXPool.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: 5ad40add42ecce646952aaa9475056c8, type: 3} 13 | m_Name: DeathFXPool 14 | m_EditorClassIdentifier: 15 | _name: DeathFX 16 | _template: {fileID: 3826700234699233003, guid: fe040d82f7e1e9d499f8ac16d09a9489, 17 | type: 3} 18 | _defaultSize: 5 19 | _maxSize: -1 20 | _incrementalInstanceNames: 0 21 | -------------------------------------------------------------------------------- /Source/Demo/Pools/DeathFXPool.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fda3ff401ed679a42b9bfa77cd0e5e9e 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 11400000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Source/Demo/Pools/TriggeredPool.asset: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!114 &11400000 4 | MonoBehaviour: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | m_GameObject: {fileID: 0} 10 | m_Enabled: 1 11 | m_EditorHideFlags: 0 12 | m_Script: {fileID: 11500000, guid: 5ad40add42ecce646952aaa9475056c8, type: 3} 13 | m_Name: TriggeredPool 14 | m_EditorClassIdentifier: 15 | _name: Triggered 16 | _template: {fileID: 1761364006608128336, guid: 31b9b4976e28c8d4f8da076b3cc39ae6, 17 | type: 3} 18 | _defaultSize: 4 19 | _maxSize: -1 20 | _incrementalInstanceNames: 1 21 | -------------------------------------------------------------------------------- /Source/Demo/Pools/TriggeredPool.asset.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e683e348e50fc3b469897aaad3d5c342 3 | NativeFormatImporter: 4 | externalObjects: {} 5 | mainObjectFileID: 11400000 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Source/Demo/Prefabs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 13799146d655c7e45bbec54b42625657 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Source/Demo/Prefabs/DeathFX.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fe040d82f7e1e9d499f8ac16d09a9489 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Source/Demo/Prefabs/TriggerCube.prefab: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!1 &1761364006608128336 4 | GameObject: 5 | m_ObjectHideFlags: 0 6 | m_CorrespondingSourceObject: {fileID: 0} 7 | m_PrefabInstance: {fileID: 0} 8 | m_PrefabAsset: {fileID: 0} 9 | serializedVersion: 6 10 | m_Component: 11 | - component: {fileID: 1761364006608128332} 12 | - component: {fileID: 1761364006608128333} 13 | - component: {fileID: 1761364006608128334} 14 | - component: {fileID: 1761364006608128335} 15 | - component: {fileID: 1761364006608128330} 16 | - component: {fileID: 1761364006608128331} 17 | m_Layer: 2 18 | m_Name: TriggerCube 19 | m_TagString: Untagged 20 | m_Icon: {fileID: 0} 21 | m_NavMeshLayer: 0 22 | m_StaticEditorFlags: 0 23 | m_IsActive: 1 24 | --- !u!4 &1761364006608128332 25 | Transform: 26 | m_ObjectHideFlags: 0 27 | m_CorrespondingSourceObject: {fileID: 0} 28 | m_PrefabInstance: {fileID: 0} 29 | m_PrefabAsset: {fileID: 0} 30 | m_GameObject: {fileID: 1761364006608128336} 31 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 32 | m_LocalPosition: {x: -0.7161716, y: 1.1577829, z: 0} 33 | m_LocalScale: {x: 0.25, y: 0.25, z: 0.25} 34 | m_Children: [] 35 | m_Father: {fileID: 0} 36 | m_RootOrder: 0 37 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 38 | --- !u!33 &1761364006608128333 39 | MeshFilter: 40 | m_ObjectHideFlags: 0 41 | m_CorrespondingSourceObject: {fileID: 0} 42 | m_PrefabInstance: {fileID: 0} 43 | m_PrefabAsset: {fileID: 0} 44 | m_GameObject: {fileID: 1761364006608128336} 45 | m_Mesh: {fileID: 10202, guid: 0000000000000000e000000000000000, type: 0} 46 | --- !u!23 &1761364006608128334 47 | MeshRenderer: 48 | m_ObjectHideFlags: 0 49 | m_CorrespondingSourceObject: {fileID: 0} 50 | m_PrefabInstance: {fileID: 0} 51 | m_PrefabAsset: {fileID: 0} 52 | m_GameObject: {fileID: 1761364006608128336} 53 | m_Enabled: 1 54 | m_CastShadows: 1 55 | m_ReceiveShadows: 1 56 | m_DynamicOccludee: 1 57 | m_MotionVectors: 1 58 | m_LightProbeUsage: 1 59 | m_ReflectionProbeUsage: 1 60 | m_RenderingLayerMask: 1 61 | m_RendererPriority: 0 62 | m_Materials: 63 | - {fileID: 10303, guid: 0000000000000000f000000000000000, type: 0} 64 | m_StaticBatchInfo: 65 | firstSubMesh: 0 66 | subMeshCount: 0 67 | m_StaticBatchRoot: {fileID: 0} 68 | m_ProbeAnchor: {fileID: 0} 69 | m_LightProbeVolumeOverride: {fileID: 0} 70 | m_ScaleInLightmap: 1 71 | m_PreserveUVs: 0 72 | m_IgnoreNormalsForChartDetection: 0 73 | m_ImportantGI: 0 74 | m_StitchLightmapSeams: 1 75 | m_SelectedEditorRenderState: 3 76 | m_MinimumChartSize: 4 77 | m_AutoUVMaxDistance: 0.5 78 | m_AutoUVMaxAngle: 89 79 | m_LightmapParameters: {fileID: 0} 80 | m_SortingLayerID: 0 81 | m_SortingLayer: 0 82 | m_SortingOrder: 0 83 | --- !u!65 &1761364006608128335 84 | BoxCollider: 85 | m_ObjectHideFlags: 0 86 | m_CorrespondingSourceObject: {fileID: 0} 87 | m_PrefabInstance: {fileID: 0} 88 | m_PrefabAsset: {fileID: 0} 89 | m_GameObject: {fileID: 1761364006608128336} 90 | m_Material: {fileID: 0} 91 | m_IsTrigger: 0 92 | m_Enabled: 1 93 | serializedVersion: 2 94 | m_Size: {x: 1, y: 1, z: 1} 95 | m_Center: {x: 0, y: 0, z: 0} 96 | --- !u!54 &1761364006608128330 97 | Rigidbody: 98 | m_ObjectHideFlags: 0 99 | m_CorrespondingSourceObject: {fileID: 0} 100 | m_PrefabInstance: {fileID: 0} 101 | m_PrefabAsset: {fileID: 0} 102 | m_GameObject: {fileID: 1761364006608128336} 103 | serializedVersion: 2 104 | m_Mass: 1 105 | m_Drag: 0 106 | m_AngularDrag: 0.05 107 | m_UseGravity: 1 108 | m_IsKinematic: 0 109 | m_Interpolate: 0 110 | m_Constraints: 0 111 | m_CollisionDetection: 0 112 | --- !u!114 &1761364006608128331 113 | MonoBehaviour: 114 | m_ObjectHideFlags: 0 115 | m_CorrespondingSourceObject: {fileID: 0} 116 | m_PrefabInstance: {fileID: 0} 117 | m_PrefabAsset: {fileID: 0} 118 | m_GameObject: {fileID: 1761364006608128336} 119 | m_Enabled: 1 120 | m_EditorHideFlags: 0 121 | m_Script: {fileID: 11500000, guid: 6df570c2ded90594da9e95f6ce518553, type: 3} 122 | m_Name: 123 | m_EditorClassIdentifier: 124 | _parentPool: {fileID: 11400000, guid: e683e348e50fc3b469897aaad3d5c342, type: 2} 125 | _collisionLayer: 126 | serializedVersion: 2 127 | m_Bits: 1 128 | _deathFX: {fileID: 11400000, guid: fda3ff401ed679a42b9bfa77cd0e5e9e, type: 2} 129 | -------------------------------------------------------------------------------- /Source/Demo/Prefabs/TriggerCube.prefab.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 31b9b4976e28c8d4f8da076b3cc39ae6 3 | PrefabImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Source/Demo/QFSW.MOP2.Demo.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "QFSW.MOP2.Demo", 3 | "references": [ 4 | "QFSW.MOP2" 5 | ], 6 | "optionalUnityReferences": [], 7 | "includePlatforms": [], 8 | "excludePlatforms": [], 9 | "allowUnsafeCode": false, 10 | "overrideReferences": false, 11 | "precompiledReferences": [], 12 | "autoReferenced": true, 13 | "defineConstraints": [] 14 | } -------------------------------------------------------------------------------- /Source/Demo/QFSW.MOP2.Demo.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 486a1a47e7ab42b42b7d6a63fe61df55 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Source/Demo/Scripts.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c882f024cd3c20e4ea7c5ebb7097b222 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Source/Demo/Scripts/ReleaseOnCollision.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace QFSW.MOP2.Demo 4 | { 5 | [RequireComponent(typeof(Collider))] 6 | public class ReleaseOnCollision : PoolableMonoBehaviour 7 | { 8 | [SerializeField] private LayerMask _collisionLayer = 0; 9 | [SerializeField] private ObjectPool _deathFX = null; 10 | 11 | private void OnCollisionEnter(Collision collision) 12 | { 13 | if ((_collisionLayer.value & 1 << collision.gameObject.layer) != 0) 14 | { 15 | Release(); 16 | if (_deathFX) 17 | { 18 | _deathFX.GetObject(transform.position); 19 | } 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Source/Demo/Scripts/ReleaseOnCollision.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6df570c2ded90594da9e95f6ce518553 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Source/Demo/Scripts/TriggerSpawner.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace QFSW.MOP2.Demo 4 | { 5 | public class TriggerSpawner : MonoBehaviour 6 | { 7 | [SerializeField] ObjectPool _triggerPool = null; 8 | [SerializeField] float _spawnRate = 2; 9 | [SerializeField] float _spawnSpeed = 3; 10 | [SerializeField] float _spawnAngularSpeed = 6; 11 | 12 | private bool ShouldSpawn => Time.time > _lastSpawned + 1 / _spawnRate; 13 | 14 | private float _lastSpawned; 15 | 16 | private void Start() 17 | { 18 | _triggerPool.Initialize(); 19 | _triggerPool.ObjectParent.parent = transform; 20 | } 21 | 22 | private void Update() 23 | { 24 | if (ShouldSpawn) 25 | { 26 | _lastSpawned = Time.time; 27 | Rigidbody rb = _triggerPool.GetObjectComponent(transform.position); 28 | rb.angularVelocity = new Vector3(Random.Range(-1, 1), Random.Range(-1, 1), Random.Range(-1, 1)) * _spawnAngularSpeed; 29 | rb.velocity = new Vector3(Random.Range(-1, 1), Random.Range(-1, 1), Random.Range(-1, 1)) * _spawnSpeed; 30 | } 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Source/Demo/Scripts/TriggerSpawner.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: b15da39ad248b4348b731fd31367dd7c 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Source/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: e70e922606f708648b8c4670db309c10 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Source/Editor/EditorHelpers.cs: -------------------------------------------------------------------------------- 1 | using System.Collections; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | 5 | namespace QFSW.MOP2.Editor 6 | { 7 | public static class EditorHelpers 8 | { 9 | public static void DrawBanner(Texture2D banner, float sizeMultiplier = 1f) 10 | { 11 | if (banner) 12 | { 13 | sizeMultiplier = Mathf.Clamp01(sizeMultiplier); 14 | 15 | Rect bannerRect = GUILayoutUtility.GetRect(0.0f, 0.0f); 16 | bannerRect.height = Screen.width * banner.height / banner.width; 17 | bannerRect.x += bannerRect.width * (1 - sizeMultiplier) / 2; 18 | bannerRect.width *= sizeMultiplier; 19 | bannerRect.height *= sizeMultiplier; 20 | 21 | GUILayout.Space(bannerRect.height); 22 | GUI.Label(bannerRect, banner); 23 | } 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Source/Editor/EditorHelpers.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 36bca9ccd1104134ba547ed7558b57ee 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Source/Editor/MOPInspectorBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Linq; 4 | using UnityEditor; 5 | using UnityEngine; 6 | 7 | namespace QFSW.MOP2.Editor 8 | { 9 | public class MOPInspectorBase : UnityEditor.Editor 10 | { 11 | const string ROOT_PATH = "Source"; 12 | protected string BannerName => "Banner.png"; 13 | protected Texture2D Banner { get; private set; } 14 | 15 | protected T LoadAssetInSource(string assetName, string root) where T : UnityEngine.Object 16 | { 17 | MonoScript src = MonoScript.FromScriptableObject(this); 18 | string srcPath = AssetDatabase.GetAssetPath(src); 19 | string dirPath = Path.GetDirectoryName(srcPath); 20 | string[] pathParts = dirPath.Split(new string[] { root }, StringSplitOptions.None); 21 | string rootPath = $"{string.Join(root, pathParts.Reverse().Skip(1).Reverse())}{root}"; 22 | string[] files = Directory.GetFiles(rootPath, assetName, SearchOption.AllDirectories); 23 | 24 | if (files.Length > 0) 25 | { 26 | string bannerPath = files[0]; 27 | return AssetDatabase.LoadAssetAtPath(bannerPath); 28 | } 29 | 30 | return null; 31 | } 32 | 33 | protected virtual void OnEnable() 34 | { 35 | if (!Banner) 36 | { 37 | Banner = LoadAssetInSource(BannerName, ROOT_PATH); 38 | } 39 | } 40 | 41 | public override void OnInspectorGUI() 42 | { 43 | EditorHelpers.DrawBanner(Banner); 44 | base.OnInspectorGUI(); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /Source/Editor/MOPInspectorBase.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a9e1f820b15245943b7144babbc642a5 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Source/Editor/MasterObjectPoolerInspector.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace QFSW.MOP2.Editor 5 | { 6 | [CustomEditor(typeof(MasterObjectPooler))] 7 | public class MasterObjectPoolerInspector : MOPInspectorBase 8 | { 9 | 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Source/Editor/MasterObjectPoolerInspector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: af407970fcb3c1f4d87b6bef69df368d 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: 7 | - _banner: {fileID: 2800000, guid: c7f059f3dce2784499e881a7f8462d56, type: 3} 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Source/Editor/ObjectPoolInspector.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEngine; 3 | 4 | namespace QFSW.MOP2.Editor 5 | { 6 | [CustomEditor(typeof(ObjectPool))] 7 | public class ObjectPoolInspector : MOPInspectorBase 8 | { 9 | private ObjectPool _objectPool; 10 | 11 | protected override void OnEnable() 12 | { 13 | base.OnEnable(); 14 | 15 | _objectPool = (ObjectPool)target; 16 | } 17 | 18 | public override void OnInspectorGUI() 19 | { 20 | EditorHelpers.DrawBanner(Banner); 21 | 22 | if (Application.isPlaying) 23 | { 24 | if (!_objectPool.Initialized) 25 | { 26 | EditorGUILayout.HelpBox("Pool has not been initialized: if you attempt to use the pool before initializing it, unintended behaviour may occur", MessageType.Warning); 27 | } 28 | } 29 | 30 | DrawDefaultInspector(); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Source/Editor/ObjectPoolInspector.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 8f957eafbb005ad428e2e97c39220e6f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: 7 | - _banner: {fileID: 2800000, guid: c7f059f3dce2784499e881a7f8462d56, type: 3} 8 | executionOrder: 0 9 | icon: {instanceID: 0} 10 | userData: 11 | assetBundleName: 12 | assetBundleVariant: 13 | -------------------------------------------------------------------------------- /Source/Editor/ObjectPoolPostProcessor.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using UnityEditor; 3 | 4 | namespace QFSW.MOP2.Editor 5 | { 6 | public class ObjectPoolPostProcessor : AssetPostprocessor 7 | { 8 | static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths) 9 | { 10 | foreach (string assetPath in importedAssets) 11 | { 12 | if (Path.GetExtension(assetPath) == ".asset") 13 | { 14 | ObjectPool pool = AssetDatabase.LoadAssetAtPath(assetPath); 15 | if (pool) 16 | { 17 | pool.AutoFillName(); 18 | } 19 | } 20 | } 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /Source/Editor/ObjectPoolPostProcessor.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 3d25de96d6ca99742a1255966e0f1941 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Source/Editor/QFSW.MOP2.Editor.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "QFSW.MOP2.Editor", 3 | "references": [ 4 | "QFSW.MOP2" 5 | ], 6 | "optionalUnityReferences": [], 7 | "includePlatforms": [ 8 | "Editor" 9 | ], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": false, 12 | "overrideReferences": false, 13 | "precompiledReferences": [], 14 | "autoReferenced": true, 15 | "defineConstraints": [] 16 | } -------------------------------------------------------------------------------- /Source/Editor/QFSW.MOP2.Editor.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f024c38aac696874d9516e4d7e340c9c 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Source/IPoolable.cs: -------------------------------------------------------------------------------- 1 | namespace QFSW.MOP2 2 | { 3 | /// 4 | /// Allows the object to receive information about the pool that it is a part of. 5 | /// 6 | public interface IPoolable 7 | { 8 | /// 9 | /// Initializes the template object with the parent pool. 10 | /// 11 | /// The pool that this template belongs to. 12 | void InitializeTemplate(ObjectPool pool); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Source/IPoolable.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: bcdc0715b8261ff4fa0320e4d875e617 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Source/MasterObjectPooler.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEngine; 4 | using Object = UnityEngine.Object; 5 | 6 | namespace QFSW.MOP2 7 | { 8 | /// 9 | /// MasterObjectPooler manages various ObjectPools. By using a MasterObjectPooler, you can perform a large variety of pool operations with a named string reference 10 | /// instead of requiring an object reference to the ObjectPool. Furthermore, initialization of the pools is handled by the MOP. 11 | /// Pools can be added either via the inspector or at runtime. 12 | /// 13 | public class MasterObjectPooler : MonoBehaviour 14 | { 15 | [Tooltip("Forces the MOP into singleton mode. This means the MOP will be made scene persistent and will not be destroyed when new scenes are loaded.")] 16 | [SerializeField] private bool _singletonMode = false; 17 | [SerializeField] private ObjectPool[] _pools = new ObjectPool[0]; 18 | 19 | /// 20 | /// Singleton reference to the MOP. Only valid and set if the singleton option is enabled for the MOP. 21 | /// 22 | public static MasterObjectPooler Instance { get; private set; } 23 | 24 | private readonly Dictionary _poolTable = new Dictionary(); 25 | 26 | #region Initialization 27 | private void Awake() 28 | { 29 | if (_singletonMode) 30 | { 31 | if (Instance == null) 32 | { 33 | Instance = this; 34 | 35 | if (transform.parent == null) 36 | { 37 | DontDestroyOnLoad(gameObject); 38 | } 39 | else 40 | { 41 | Debug.LogWarning($"Singleton mode enabled for the Master Object Pooler '{name}' which is not a root GameObject; this means it cannot be made scene persistent"); 42 | } 43 | } 44 | else 45 | { 46 | Object.Destroy(gameObject); 47 | } 48 | } 49 | } 50 | 51 | private void Start() 52 | { 53 | foreach (ObjectPool pool in _pools) 54 | { 55 | AddPool(pool); 56 | } 57 | } 58 | #endregion 59 | 60 | #region Internal 61 | private void DestroyPoolInternal(ObjectPool pool) 62 | { 63 | pool.Purge(); 64 | Object.Destroy(pool.ObjectParent.gameObject); 65 | } 66 | #endregion 67 | 68 | #region PoolManagement 69 | /// 70 | /// Adds an ObjectPool to the MasterObjectPooler and initializes it. 71 | /// 72 | /// The ObjectPool to add to the MasterObjectPooler. 73 | public void AddPool(ObjectPool pool) { AddPool(pool.PoolName, pool); } 74 | 75 | /// 76 | /// Adds an ObjectPool to the MasterObjectPooler and initializes it. 77 | /// 78 | /// Override for the named string reference to use for this pool. By default uses the ObjectPool's name. 79 | /// The ObjectPool to add to the MasterObjectPooler. 80 | public void AddPool(string poolName, ObjectPool pool) 81 | { 82 | pool.Initialize(); 83 | pool.ObjectParent.parent = transform; 84 | 85 | if (_poolTable.ContainsKey(poolName)) 86 | { 87 | Debug.LogWarning($"{poolName} could not be added to the pool table as a pool with the same name already exists"); 88 | } 89 | else 90 | { 91 | _poolTable.Add(poolName, pool); 92 | } 93 | } 94 | 95 | /// 96 | /// Retrieves a pool. 97 | /// 98 | /// The name of the pool to retrieve. 99 | /// The retrieved pool. 100 | public ObjectPool GetPool(string poolName) 101 | { 102 | if (_poolTable.ContainsKey(poolName)) 103 | { 104 | return _poolTable[poolName]; 105 | } 106 | 107 | throw new ArgumentException($"Cannot get pool {poolName} as it is not present in the pool table"); 108 | } 109 | 110 | /// 111 | /// Retrieves/adds a pool. 112 | /// 113 | /// The name of the pool to retrieve/add. 114 | /// The retrieved pool. 115 | public ObjectPool this[string poolName] 116 | { 117 | get => GetPool(poolName); 118 | set 119 | { 120 | _poolTable.Remove(poolName); 121 | AddPool(poolName, value); 122 | } 123 | } 124 | 125 | /// 126 | /// Destroys every pool, purging all of their contents then removing them from the MasterObjectPooler. 127 | /// 128 | public void DestroyAllPools() 129 | { 130 | foreach (ObjectPool pool in _poolTable.Values) 131 | { 132 | DestroyPoolInternal(pool); 133 | } 134 | 135 | _poolTable.Clear(); 136 | } 137 | 138 | /// 139 | /// Destroys a specified pool, purging its contents and removing it from the MasterObjectPooler. 140 | /// 141 | /// The pool to destroy. 142 | public void DestroyPool(string poolName) 143 | { 144 | ObjectPool pool = GetPool(poolName); 145 | DestroyPoolInternal(pool); 146 | _poolTable.Remove(poolName); 147 | } 148 | #endregion 149 | 150 | #region GetObject/Component 151 | /// 152 | /// Gets an object from the specified pool. 153 | /// 154 | /// The name of the pool to get an object from. 155 | /// The retrieved object. 156 | public GameObject GetObject(string poolName) 157 | { 158 | return GetPool(poolName).GetObject(); 159 | } 160 | 161 | /// 162 | /// Gets an object from the specified pool. 163 | /// 164 | /// The name of the pool to get an object from. 165 | /// The position to set the object to. 166 | /// The retrieved object. 167 | public GameObject GetObject(string poolName, Vector3 position) 168 | { 169 | return GetPool(poolName).GetObject(position); 170 | } 171 | 172 | /// 173 | /// Gets an object from the specified pool. 174 | /// 175 | /// The name of the pool to get an object from. 176 | /// The position to set the object to. 177 | /// The rotation to set the object to. 178 | /// The retrieved object. 179 | public GameObject GetObject(string poolName, Vector3 position, Quaternion rotation) 180 | { 181 | return GetPool(poolName).GetObject(position, rotation); 182 | } 183 | 184 | /// 185 | /// Gets an object from the specified pool, and then retrieves the specified component using a cache to improve performance. 186 | /// Note: this should not be used if multiple components of the same type exist on the object, or if the component will be dynamically removed/added at runtime. 187 | /// 188 | /// The component type to get. 189 | /// The name of the pool to get the component from. 190 | /// The retrieved component. 191 | public T GetObjectComponent(string poolName) where T : class 192 | { 193 | return GetPool(poolName).GetObjectComponent(); 194 | } 195 | 196 | /// 197 | /// Gets an object from the specified pool, and then retrieves the specified component using a cache to improve performance. 198 | /// Note: this should not be used if multiple components of the same type exist on the object, or if the component will be dynamically removed/added at runtime. 199 | /// 200 | /// The component type to get. 201 | /// The name of the pool to get the component from. 202 | /// The position to set the object to. 203 | /// The retrieved component. 204 | public T GetObjectComponent(string poolName, Vector3 position) where T : class 205 | { 206 | return GetPool(poolName).GetObjectComponent(position); 207 | } 208 | 209 | /// 210 | /// Gets an object from the specified pool, and then retrieves the specified component using a cache to improve performance. 211 | /// Note: this should not be used if multiple components of the same type exist on the object, or if the component will be dynamically removed/added at runtime. 212 | /// 213 | /// The component type to get. 214 | /// The name of the pool to get the component from. 215 | /// The position to set the object to. 216 | /// The rotation to set the object to. 217 | /// The retrieved component. 218 | public T GetObjectComponent(string poolName, Vector3 position, Quaternion rotation) where T : class 219 | { 220 | return GetPool(poolName).GetObjectComponent(position, rotation); 221 | } 222 | #endregion 223 | 224 | #region Release/Destroys 225 | /// 226 | /// Releases an object and returns it back to the specified pool, effectively 'destroying' it from the scene. 227 | /// Pool equivalent of Destroy. 228 | /// 229 | /// The object to release. 230 | /// The name of the pool to return the object to. 231 | public void Release(GameObject obj, string poolName) 232 | { 233 | GetPool(poolName).Release(obj); 234 | } 235 | 236 | /// 237 | /// Releases a collection of objects and returns them back to the specified pool, effectively 'destroying' them from the scene. 238 | /// 239 | /// the objects to release. 240 | /// The name of the pool to return the objects to. 241 | public void Release(IEnumerable objs, string poolName) 242 | { 243 | GetPool(poolName).Release(objs); 244 | } 245 | 246 | /// 247 | /// Releases every active object in the specified pool. 248 | /// 249 | /// The name of the pool. 250 | public void ReleaseAll(string poolName) 251 | { 252 | GetPool(poolName).ReleaseAll(); 253 | } 254 | 255 | /// 256 | /// Forcibly destroys the object and does not return it to a pool. 257 | /// 258 | /// The object to destroy. 259 | public void Destroy(GameObject obj) { Destroy(obj, obj.name); } 260 | 261 | /// 262 | /// Forcibly destroys the object and does not return it to a pool. 263 | /// 264 | /// The object to destroy. 265 | /// The name of the pool that the object belonged to. 266 | public void Destroy(GameObject obj, string poolName) 267 | { 268 | ObjectPool pool = GetPool(poolName); 269 | if (pool) { pool.Destroy(obj); } 270 | else { Object.Destroy(obj); } 271 | } 272 | 273 | /// 274 | /// Forcibly destroys a collection of objects and does not return them to a pool. 275 | /// 276 | /// The objects to destroy. 277 | /// The name of the pool that the objects belonged to. 278 | public void Destroy(IEnumerable objs, string poolName) 279 | { 280 | ObjectPool pool = GetPool(poolName); 281 | if (pool) { pool.Destroy(objs); } 282 | else 283 | { 284 | foreach (GameObject obj in objs) 285 | { 286 | Object.Destroy(obj); 287 | } 288 | } 289 | } 290 | 291 | /// 292 | /// Releases every active object in every pool. 293 | /// 294 | public void ReleaseAllInAllPools() 295 | { 296 | foreach (ObjectPool pool in _poolTable.Values) 297 | { 298 | pool.ReleaseAll(); 299 | } 300 | } 301 | #endregion 302 | 303 | #region Miscellaneous 304 | /// 305 | /// Populates the specified pool with the specified number of objects, so that they do not need instantiating later. 306 | /// 307 | /// The name of the pool to populate. 308 | /// The number of objects to populate it with. 309 | /// The population mode. 310 | public void Populate(string poolName, int quantity, PopulateMethod method = PopulateMethod.Set) 311 | { 312 | GetPool(poolName).Populate(quantity, method); 313 | } 314 | 315 | /// 316 | /// Destroys every object in the specified pool, both alive and pooled. 317 | /// 318 | /// The name of the pool to populate. 319 | public void Purge(string poolName) 320 | { 321 | GetPool(poolName).Purge(); 322 | } 323 | 324 | /// 325 | /// Destroys every object in every pool, both alive and pooled. 326 | /// 327 | public void PurgeAll() 328 | { 329 | foreach (ObjectPool pool in _poolTable.Values) 330 | { 331 | pool.Purge(); 332 | } 333 | } 334 | 335 | /// 336 | /// Gets all active objects in the specified pool. 337 | /// 338 | /// The name of the pool to populate. 339 | /// The active objects. 340 | public IEnumerable GetAllActiveObjects(string poolName) 341 | { 342 | return GetPool(poolName).GetAllActiveObjects(); 343 | } 344 | #endregion 345 | } 346 | } 347 | -------------------------------------------------------------------------------- /Source/MasterObjectPooler.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ae7d75d4e54c16b42b11bb89b17dc809 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Source/ObjectPool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text.RegularExpressions; 5 | using UnityEngine; 6 | using UnityEngine.SceneManagement; 7 | using Object = UnityEngine.Object; 8 | 9 | [assembly: System.Runtime.CompilerServices.InternalsVisibleTo("QFSW.MOP2.Editor")] 10 | 11 | namespace QFSW.MOP2 12 | { 13 | /// 14 | /// Object pool containing several copies of a template object (usually a prefab). Using the pool with GetObject and Release 15 | /// provides a high speed alternative to repeatedly calling Instantiate and Destroy. 16 | /// 17 | [CreateAssetMenu(fileName = "Untitled Pool", menuName = "Master Object Pooler 2/Object Pool", order = 0)] 18 | public class ObjectPool : ScriptableObject 19 | { 20 | [Tooltip("The name of the pool. Used for identification and as the key when using a MasterObjectPooler.")] 21 | [SerializeField] private string _name = string.Empty; 22 | 23 | [Tooltip("The template object to center the pool on. All objects in the pool will be a copy of this object.")] 24 | [SerializeField] private GameObject _template = null; 25 | 26 | [Tooltip("The default number of objects to create in this pool when initializing it.")] 27 | [SerializeField] private int _defaultSize; 28 | 29 | [Tooltip("The maximum number of objects that can be kept in this pool. If it is exceeded, objects will be destroyed instead of pooled when returned. Set to -1 for no limit.")] 30 | [SerializeField] private int _maxSize = -1; 31 | 32 | [Tooltip("If enabled, object instances will be renamed to ObjectName#XXX where XXX is the instance number. This is useful if you want them all to be uniquely named.")] 33 | [SerializeField] private bool _incrementalInstanceNames = false; 34 | 35 | [Tooltip("Auto initializes the pool. In the editor this occurs when play-mode is entered. In builds, this occurs on startup")] 36 | [SerializeField] private bool _autoInitialize = false; 37 | 38 | [Tooltip("Repopulate the pool with objects when the scene changes to replace objects that were unloaded/destroyed.")] 39 | [SerializeField] private bool _repopulateOnSceneChange = false; 40 | 41 | /// 42 | /// If enabled, object instances will be renamed to ObjectName#XXX where XXX is the instance number. This is useful if you want them all to be uniquely named. 43 | /// 44 | public bool IncrementalInstanceNames 45 | { 46 | get => _incrementalInstanceNames; 47 | set => _incrementalInstanceNames = value; 48 | } 49 | 50 | /// 51 | /// The name of the pool. Used for identification and as the key when using a MasterObjectPooler. 52 | /// 53 | public string PoolName => _name; 54 | 55 | /// 56 | /// Parent transform for all pooled objects. 57 | /// 58 | public Transform ObjectParent 59 | { 60 | get 61 | { 62 | if (!_objectParent) 63 | { 64 | _objectParent = new GameObject($"{_name} Pool").transform; 65 | } 66 | 67 | return _objectParent; 68 | } 69 | } 70 | private Transform _objectParent; 71 | 72 | private bool HasMaxSize => _maxSize > 0; 73 | private bool HasPooledObjects => _pooledObjects.Count > 0; 74 | public bool Initialized { get; private set; } 75 | 76 | private int _instanceCounter = 0; 77 | private readonly Regex _poolRegex = new Regex("[_ ]*[Pp]ool"); 78 | 79 | #region Caches 80 | private readonly List _pooledObjects = new List(); 81 | private readonly Dictionary _aliveObjects = new Dictionary(); 82 | 83 | private readonly List _releaseAllBuffer = new List(); 84 | private readonly Dictionary<(int id, Type type), object> _componentCache = new Dictionary<(int id, Type type), object>(); 85 | #endregion 86 | 87 | #region Initialization/Creation 88 | private ObjectPool() { } 89 | 90 | /// 91 | /// Creates an ObjectPool. 92 | /// 93 | /// The template object to center the pool on. All objects in the pool will be a copy of this object. 94 | /// The default number of objects to create in this pool when initializing it. 95 | /// The maximum number of objects that can be kept in this pool. If it is exceeded, objects will be destroyed instead of pooled when returned. Set to -1 for no limit. 96 | /// The created ObjectPool. 97 | public static ObjectPool Create(GameObject template, int defaultSize = 0, int maxSize = -1) 98 | { 99 | return Create(template, template.name, defaultSize, maxSize); 100 | } 101 | 102 | /// 103 | /// Creates an ObjectPool. 104 | /// 105 | /// The template object to center the pool on. All objects in the pool will be a copy of this object. 106 | /// The name of the pool. Used for identification and as the key when using a MasterObjectPooler. 107 | /// The default number of objects to create in this pool when initializing it. 108 | /// The maximum number of objects that can be kept in this pool. If it is exceeded, objects will be destroyed instead of pooled when returned. Set to -1 for no limit. 109 | /// The created ObjectPool. 110 | public static ObjectPool Create(GameObject template, string name, int defaultSize = 0, int maxSize = -1) 111 | { 112 | ObjectPool pool = CreateInstance(); 113 | pool._name = name; 114 | pool._template = template; 115 | pool._defaultSize = defaultSize; 116 | pool._maxSize = maxSize; 117 | 118 | return pool; 119 | } 120 | 121 | /// 122 | /// Creates an ObjectPool and initializes it. 123 | /// 124 | /// The template object to center the pool on. All objects in the pool will be a copy of this object. 125 | /// The default number of objects to create in this pool when initializing it. 126 | /// The maximum number of objects that can be kept in this pool. If it is exceeded, objects will be destroyed instead of pooled when returned. Set to -1 for no limit. 127 | /// The created ObjectPool. 128 | public static ObjectPool CreateAndInitialize(GameObject template, int defaultSize = 0, int maxSize = -1) 129 | { 130 | ObjectPool pool = Create(template, defaultSize, maxSize); 131 | pool.Initialize(); 132 | 133 | return pool; 134 | } 135 | 136 | /// 137 | /// Creates an ObjectPool and initializes it. 138 | /// 139 | /// The template object to center the pool on. All objects in the pool will be a copy of this object. 140 | /// The name of the pool. Used for identification and as the key when using a MasterObjectPooler. 141 | /// The default number of objects to create in this pool when initializing it. 142 | /// The maximum number of objects that can be kept in this pool. If it is exceeded, objects will be destroyed instead of pooled when returned. Set to -1 for no limit. 143 | /// The created ObjectPool. 144 | public static ObjectPool CreateAndInitialize(GameObject template, string name, int defaultSize = 0, int maxSize = -1) 145 | { 146 | ObjectPool pool = Create(template, name, defaultSize, maxSize); 147 | pool.Initialize(); 148 | 149 | return pool; 150 | } 151 | 152 | private void OnEnable() 153 | { 154 | _instanceCounter = 0; 155 | SceneManager.sceneUnloaded += OnSceneUnload; 156 | #if UNITY_EDITOR 157 | UnityEditor.EditorApplication.playModeStateChanged += OnPlayModeStateChange; 158 | #endif 159 | } 160 | 161 | private void OnDisable() 162 | { 163 | SceneManager.sceneUnloaded -= OnSceneUnload; 164 | #if UNITY_EDITOR 165 | UnityEditor.EditorApplication.playModeStateChanged -= OnPlayModeStateChange; 166 | #endif 167 | } 168 | 169 | /// 170 | /// Initializes the ObjectPool. 171 | /// 172 | public void Initialize(bool forceReinitialization = false) 173 | { 174 | if (!Initialized || forceReinitialization) 175 | { 176 | Initialized = true; 177 | 178 | AutoFillName(); 179 | InitializeIPoolables(); 180 | Populate(_defaultSize, PopulateMethod.Set); 181 | } 182 | } 183 | 184 | internal void AutoFillName() 185 | { 186 | if (string.IsNullOrWhiteSpace(_name)) 187 | { 188 | _name = _poolRegex.Replace(name, string.Empty); 189 | ObjectParent.name = _name; 190 | } 191 | else if (string.IsNullOrWhiteSpace(name)) 192 | { 193 | name = _name; 194 | } 195 | } 196 | 197 | private void InitializeIPoolables() 198 | { 199 | foreach (IPoolable poolable in _template.GetComponentsInChildren()) 200 | { 201 | poolable.InitializeTemplate(this); 202 | } 203 | } 204 | #endregion 205 | 206 | #region Internal 207 | private GameObject CreateNewObject() { return CreateNewObject(_template.transform.position, _template.transform.rotation); } 208 | private GameObject CreateNewObject(Vector3 position, Quaternion rotation) 209 | { 210 | GameObject newObj = Instantiate(_template, position, rotation); 211 | newObj.transform.SetParent(ObjectParent, false); 212 | 213 | if (_incrementalInstanceNames) 214 | { 215 | newObj.name = string.Format("{0}#{1:000}", _template.name, _instanceCounter); 216 | } 217 | else 218 | { 219 | newObj.name = _template.name; 220 | } 221 | 222 | _instanceCounter++; 223 | return newObj; 224 | } 225 | 226 | private void CleanseInternal() 227 | { 228 | if (!_objectParent) 229 | { 230 | _pooledObjects.Clear(); 231 | _aliveObjects.Clear(); 232 | _componentCache.Clear(); 233 | } 234 | else 235 | { 236 | _pooledObjects.RemoveAll(x => !x); 237 | } 238 | } 239 | #endregion 240 | 241 | #region GetObject/Component 242 | /// 243 | /// Gets an object from the pool. 244 | /// 245 | /// The retrieved object. 246 | public GameObject GetObject() { return GetObject(_template.transform.position); } 247 | 248 | /// 249 | /// Gets an object from the pool. 250 | /// 251 | /// The position to set the object to. 252 | /// The retrieved object. 253 | public GameObject GetObject(Vector3 position) { return GetObject(position, _template.transform.rotation); } 254 | 255 | /// 256 | /// Gets an object from the pool. 257 | /// 258 | /// The position to set the object to. 259 | /// The rotation to set the object to. 260 | /// The retrieved object. 261 | public GameObject GetObject(Vector3 position, Quaternion rotation) 262 | { 263 | GameObject obj; 264 | if (HasPooledObjects) 265 | { 266 | obj = _pooledObjects[_pooledObjects.Count - 1]; 267 | _pooledObjects.RemoveAt(_pooledObjects.Count - 1); 268 | 269 | if (!obj) 270 | { 271 | Debug.LogWarning($"Object in pool '{_name}' was null or destroyed; it may have been destroyed externally. Attempting to retrieve a new object"); 272 | return GetObject(position, rotation); 273 | } 274 | 275 | obj.transform.SetPositionAndRotation(position, rotation); 276 | obj.transform.localScale = _template.transform.localScale; 277 | } 278 | else 279 | { 280 | obj = CreateNewObject(position, rotation); 281 | } 282 | 283 | obj.SetActive(true); 284 | 285 | _aliveObjects.Add(obj.GetInstanceID(), obj); 286 | return obj; 287 | } 288 | 289 | /// 290 | /// Gets an object from the pool, and then retrieves the specified component using a cache to improve performance. 291 | /// 292 | /// The component type to get. 293 | /// The retrieved component. 294 | public T GetObjectComponent() where T : class 295 | { 296 | return GetObjectComponent(_template.transform.position); 297 | } 298 | 299 | /// 300 | /// Gets an object from the pool, and then retrieves the specified component using a cache to improve performance. 301 | /// 302 | /// The component type to get. 303 | /// The position to set the object to. 304 | /// The retrieved component. 305 | public T GetObjectComponent(Vector3 position) where T : class 306 | { 307 | return GetObjectComponent(position, _template.transform.rotation); 308 | } 309 | 310 | /// 311 | /// Gets an object from the pool, and then retrieves the specified component using a cache to improve performance. 312 | /// 313 | /// The component type to get. 314 | /// The position to set the object to. 315 | /// The rotation to set the object to. 316 | /// The retrieved component. 317 | public T GetObjectComponent(Vector3 position, Quaternion rotation) where T : class 318 | { 319 | GameObject obj = GetObject(position, rotation); 320 | return GetObjectComponent(obj); 321 | } 322 | 323 | /// 324 | /// Retrieves the specified component from an object using a cache to improve performance. 325 | /// 326 | /// The component type to get. 327 | /// The object to get the component from. 328 | /// The retrieved component. 329 | public T GetObjectComponent(GameObject obj) where T : class 330 | { 331 | (int id, Type type) key = (obj.GetInstanceID(), typeof(T)); 332 | T component; 333 | 334 | if (_componentCache.ContainsKey(key)) 335 | { 336 | component = _componentCache[key] as T; 337 | if (component == null) { _componentCache.Remove(key); } 338 | else { return component; } 339 | } 340 | 341 | component = obj.GetComponent(); 342 | if (component != null) { _componentCache[key] = component; } 343 | return component; 344 | } 345 | #endregion 346 | 347 | #region Release/Destroy 348 | /// 349 | /// Releases an object and returns it back to the pool, effectively 'destroying' it from the scene. 350 | /// Pool equivalent of Destroy. 351 | /// 352 | /// The object to release. 353 | public void Release(GameObject obj) 354 | { 355 | if (!_aliveObjects.Remove(obj.GetInstanceID())) 356 | { 357 | Debug.LogWarning($"Object '{obj}' could not be found in pool '{_name}'; it may have already been released."); 358 | return; 359 | } 360 | 361 | if (obj) 362 | { 363 | if (HasMaxSize && _pooledObjects.Count >= _maxSize) 364 | { 365 | Object.Destroy(obj); 366 | } 367 | else 368 | { 369 | _pooledObjects.Add(obj); 370 | obj.SetActive(false); 371 | obj.transform.SetParent(ObjectParent, false); 372 | } 373 | } 374 | } 375 | 376 | /// 377 | /// Releases a collection of objects and returns them back to the pool, effectively 'destroying' them from the scene. 378 | /// 379 | /// the objects to release. 380 | public void Release(IEnumerable objs) 381 | { 382 | foreach (GameObject obj in objs) 383 | { 384 | Release(obj); 385 | } 386 | } 387 | 388 | /// 389 | /// Releases every active object in this pool. 390 | /// 391 | public void ReleaseAll() 392 | { 393 | _releaseAllBuffer.Clear(); 394 | _releaseAllBuffer.AddRange(_aliveObjects.Values); 395 | Release(_releaseAllBuffer); 396 | } 397 | 398 | /// 399 | /// Forcibly destroys the object and does not return it to the pool. 400 | /// 401 | /// The object to destroy. 402 | public void Destroy(GameObject obj) 403 | { 404 | _aliveObjects.Remove(obj.GetInstanceID()); 405 | Object.Destroy(obj); 406 | } 407 | 408 | /// 409 | /// Forcibly destroys a collection of objects and does not return them to the pool. 410 | /// 411 | /// The objects to destroy. 412 | public void Destroy(IEnumerable objs) 413 | { 414 | foreach (GameObject obj in objs) 415 | { 416 | Destroy(obj); 417 | } 418 | } 419 | #endregion 420 | 421 | #region Miscellaneous 422 | /// 423 | /// Populates the pool with the specified number of objects, so that they do not need instantiating later. 424 | /// 425 | /// The number of objects to populate it with. 426 | /// The population mode. 427 | public void Populate(int quantity, PopulateMethod method = PopulateMethod.Set) 428 | { 429 | int newObjCount; 430 | switch (method) 431 | { 432 | case PopulateMethod.Set: newObjCount = quantity - _pooledObjects.Count; break; 433 | case PopulateMethod.Add: newObjCount = quantity; break; 434 | default: newObjCount = 0; break; 435 | } 436 | 437 | if (HasMaxSize) { newObjCount = Mathf.Min(newObjCount, _maxSize - _pooledObjects.Count); } 438 | if (newObjCount < 0) { newObjCount = 0; } 439 | 440 | for (int i = 0; i < newObjCount; i++) 441 | { 442 | GameObject newObj = CreateNewObject(); 443 | newObj.SetActive(false); 444 | _pooledObjects.Add(newObj); 445 | } 446 | } 447 | 448 | /// 449 | /// Destroys every object in the pool, both alive and pooled. 450 | /// 451 | public void Purge() 452 | { 453 | foreach (GameObject obj in _pooledObjects) { Object.Destroy(obj); } 454 | foreach (GameObject obj in _aliveObjects.Values) { Object.Destroy(obj); } 455 | _pooledObjects.Clear(); 456 | _aliveObjects.Clear(); 457 | _componentCache.Clear(); 458 | } 459 | 460 | /// 461 | /// Gets all active objects in the pool. 462 | /// 463 | /// The active objects. 464 | public IEnumerable GetAllActiveObjects() 465 | { 466 | return _aliveObjects.Values 467 | .Where(x => x); 468 | } 469 | #endregion 470 | 471 | #region Callbacks 472 | private void Awake() 473 | { 474 | Initialized = false; 475 | 476 | #if !UNITY_EDITOR 477 | if (_autoInitialize) 478 | { 479 | Initialize(); 480 | } 481 | #endif 482 | } 483 | 484 | private void OnSceneUnload(Scene scene) 485 | { 486 | CleanseInternal(); 487 | 488 | if (_repopulateOnSceneChange) 489 | { 490 | Populate(_defaultSize, PopulateMethod.Set); 491 | } 492 | } 493 | 494 | #if UNITY_EDITOR 495 | private void OnPlayModeStateChange(UnityEditor.PlayModeStateChange state) 496 | { 497 | if (state == UnityEditor.PlayModeStateChange.EnteredPlayMode) 498 | { 499 | _instanceCounter = 0; 500 | Initialized = false; 501 | CleanseInternal(); 502 | 503 | if (_autoInitialize) 504 | { 505 | Initialize(); 506 | } 507 | } 508 | } 509 | #endif 510 | #endregion 511 | } 512 | } 513 | -------------------------------------------------------------------------------- /Source/ObjectPool.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 5ad40add42ecce646952aaa9475056c8 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {fileID: 2800000, guid: 20484e3aa77c0634dafa269c9ad3ca1b, type: 3} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Source/PoolableMonoBehaviour.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | 3 | namespace QFSW.MOP2 4 | { 5 | /// 6 | /// MonoBehaviour that has a reference to its parent pool, and can thus be released to the pool without the user needing a reference to its pool, making it self contained. 7 | /// Usable either as a standalone component or as a base class for other components. 8 | /// 9 | public class PoolableMonoBehaviour : MonoBehaviour, IPoolable 10 | { 11 | /// 12 | /// If its parent pool has been initialized yet. 13 | /// 14 | public bool PoolReady => _parentPool; 15 | 16 | [SerializeField] 17 | [HideInInspector] 18 | private ObjectPool _parentPool; 19 | 20 | void IPoolable.InitializeTemplate(ObjectPool pool) 21 | { 22 | _parentPool = pool; 23 | } 24 | 25 | /// 26 | /// Releases the object and returns it back to its pool, effectively 'destroying' it from the scene. 27 | /// 28 | public void Release() 29 | { 30 | _parentPool.Release(gameObject); 31 | } 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Source/PoolableMonoBehaviour.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 7821b7230681c6f4d94a8fa7f8825ac2 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Source/PopulateMethod.cs: -------------------------------------------------------------------------------- 1 | namespace QFSW.MOP2 2 | { 3 | /// 4 | /// Determines how many objects are needed when populating a pool. 5 | /// 6 | public enum PopulateMethod 7 | { 8 | /// If set is used, then populate will ensure the final population is the specified count. 9 | Set = 0, 10 | 11 | /// If add is used, then populate will add the specified count to the current population. 12 | Add = 1 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /Source/PopulateMethod.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 307ba4f079a9a7244b4509f5e19d821f 3 | MonoImporter: 4 | externalObjects: {} 5 | serializedVersion: 2 6 | defaultReferences: [] 7 | executionOrder: 0 8 | icon: {instanceID: 0} 9 | userData: 10 | assetBundleName: 11 | assetBundleVariant: 12 | -------------------------------------------------------------------------------- /Source/QFSW.MOP2.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "QFSW.MOP2", 3 | "references": [], 4 | "optionalUnityReferences": [], 5 | "includePlatforms": [], 6 | "excludePlatforms": [], 7 | "allowUnsafeCode": false, 8 | "overrideReferences": false, 9 | "precompiledReferences": [], 10 | "autoReferenced": true, 11 | "defineConstraints": [] 12 | } -------------------------------------------------------------------------------- /Source/QFSW.MOP2.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: adb0f400804b2c0448682f502e5eb39b 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /Source/Textures.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f137be7750778694fb3fcdcdb5aea9a8 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /Source/Textures/Banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QFSW/MasterObjectPooler2/5a9129f1f1a6a3c0031573ac9b0933ed64de811f/Source/Textures/Banner.png -------------------------------------------------------------------------------- /Source/Textures/Banner.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c7f059f3dce2784499e881a7f8462d56 3 | TextureImporter: 4 | fileIDToRecycleName: {} 5 | externalObjects: {} 6 | serializedVersion: 9 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: 2 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 1 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 2 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 4096 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 2 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | - serializedVersion: 2 73 | buildTarget: Standalone 74 | maxTextureSize: 4096 75 | resizeAlgorithm: 0 76 | textureFormat: -1 77 | textureCompression: 2 78 | compressionQuality: 50 79 | crunchedCompression: 0 80 | allowsAlphaSplitting: 0 81 | overridden: 0 82 | androidETC2FallbackOverride: 0 83 | - serializedVersion: 2 84 | buildTarget: Windows Store Apps 85 | maxTextureSize: 2048 86 | resizeAlgorithm: 0 87 | textureFormat: -1 88 | textureCompression: 1 89 | compressionQuality: 50 90 | crunchedCompression: 0 91 | allowsAlphaSplitting: 0 92 | overridden: 0 93 | androidETC2FallbackOverride: 0 94 | - serializedVersion: 2 95 | buildTarget: Android 96 | maxTextureSize: 2048 97 | resizeAlgorithm: 0 98 | textureFormat: -1 99 | textureCompression: 1 100 | compressionQuality: 50 101 | crunchedCompression: 0 102 | allowsAlphaSplitting: 0 103 | overridden: 0 104 | androidETC2FallbackOverride: 0 105 | - serializedVersion: 2 106 | buildTarget: WebGL 107 | maxTextureSize: 2048 108 | resizeAlgorithm: 0 109 | textureFormat: -1 110 | textureCompression: 1 111 | compressionQuality: 50 112 | crunchedCompression: 0 113 | allowsAlphaSplitting: 0 114 | overridden: 0 115 | androidETC2FallbackOverride: 0 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 4c884f7d4f2f0784ca8758e0b62946fc 123 | vertices: [] 124 | indices: 125 | edges: [] 126 | weights: [] 127 | spritePackingTag: 128 | pSDRemoveMatte: 0 129 | pSDShowRemoveMatteOption: 0 130 | userData: 131 | assetBundleName: 132 | assetBundleVariant: 133 | -------------------------------------------------------------------------------- /Source/Textures/BannerCutout.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QFSW/MasterObjectPooler2/5a9129f1f1a6a3c0031573ac9b0933ed64de811f/Source/Textures/BannerCutout.png -------------------------------------------------------------------------------- /Source/Textures/BannerCutout.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0077622ae1b3e8040bd798043be536da 3 | TextureImporter: 4 | fileIDToRecycleName: {} 5 | externalObjects: {} 6 | serializedVersion: 9 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: 2 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 1 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 2 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 4096 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 2 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | - serializedVersion: 2 73 | buildTarget: Standalone 74 | maxTextureSize: 4096 75 | resizeAlgorithm: 0 76 | textureFormat: -1 77 | textureCompression: 2 78 | compressionQuality: 50 79 | crunchedCompression: 0 80 | allowsAlphaSplitting: 0 81 | overridden: 0 82 | androidETC2FallbackOverride: 0 83 | - serializedVersion: 2 84 | buildTarget: Windows Store Apps 85 | maxTextureSize: 2048 86 | resizeAlgorithm: 0 87 | textureFormat: -1 88 | textureCompression: 1 89 | compressionQuality: 50 90 | crunchedCompression: 0 91 | allowsAlphaSplitting: 0 92 | overridden: 0 93 | androidETC2FallbackOverride: 0 94 | - serializedVersion: 2 95 | buildTarget: Android 96 | maxTextureSize: 2048 97 | resizeAlgorithm: 0 98 | textureFormat: -1 99 | textureCompression: 1 100 | compressionQuality: 50 101 | crunchedCompression: 0 102 | allowsAlphaSplitting: 0 103 | overridden: 0 104 | androidETC2FallbackOverride: 0 105 | - serializedVersion: 2 106 | buildTarget: WebGL 107 | maxTextureSize: 2048 108 | resizeAlgorithm: 0 109 | textureFormat: -1 110 | textureCompression: 1 111 | compressionQuality: 50 112 | crunchedCompression: 0 113 | allowsAlphaSplitting: 0 114 | overridden: 0 115 | androidETC2FallbackOverride: 0 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 0755d778ef45dc84fa397370a99aabb2 123 | vertices: [] 124 | indices: 125 | edges: [] 126 | weights: [] 127 | spritePackingTag: 128 | pSDRemoveMatte: 0 129 | pSDShowRemoveMatteOption: 0 130 | userData: 131 | assetBundleName: 132 | assetBundleVariant: 133 | -------------------------------------------------------------------------------- /Source/Textures/Pool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/QFSW/MasterObjectPooler2/5a9129f1f1a6a3c0031573ac9b0933ed64de811f/Source/Textures/Pool.png -------------------------------------------------------------------------------- /Source/Textures/Pool.png.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 20484e3aa77c0634dafa269c9ad3ca1b 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 10 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | isReadable: 0 24 | streamingMipmaps: 0 25 | streamingMipmapsPriority: 0 26 | grayScaleToAlpha: 0 27 | generateCubemap: 6 28 | cubemapConvolution: 0 29 | seamlessCubemap: 0 30 | textureFormat: 1 31 | maxTextureSize: 2048 32 | textureSettings: 33 | serializedVersion: 2 34 | filterMode: -1 35 | aniso: 1 36 | mipBias: -100 37 | wrapU: 1 38 | wrapV: 1 39 | wrapW: -1 40 | nPOTScale: 0 41 | lightmap: 0 42 | compressionQuality: 50 43 | spriteMode: 0 44 | spriteExtrude: 1 45 | spriteMeshType: 1 46 | alignment: 0 47 | spritePivot: {x: 0.5, y: 0.5} 48 | spritePixelsToUnits: 100 49 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 50 | spriteGenerateFallbackPhysicsShape: 1 51 | alphaUsage: 1 52 | alphaIsTransparency: 1 53 | spriteTessellationDetail: -1 54 | textureType: 2 55 | textureShape: 1 56 | singleChannelComponent: 0 57 | maxTextureSizeSet: 0 58 | compressionQualitySet: 0 59 | textureFormatSet: 0 60 | platformSettings: 61 | - serializedVersion: 2 62 | buildTarget: DefaultTexturePlatform 63 | maxTextureSize: 2048 64 | resizeAlgorithm: 0 65 | textureFormat: -1 66 | textureCompression: 2 67 | compressionQuality: 50 68 | crunchedCompression: 0 69 | allowsAlphaSplitting: 0 70 | overridden: 0 71 | androidETC2FallbackOverride: 0 72 | - serializedVersion: 2 73 | buildTarget: Standalone 74 | maxTextureSize: 2048 75 | resizeAlgorithm: 0 76 | textureFormat: -1 77 | textureCompression: 2 78 | compressionQuality: 50 79 | crunchedCompression: 0 80 | allowsAlphaSplitting: 0 81 | overridden: 0 82 | androidETC2FallbackOverride: 0 83 | - serializedVersion: 2 84 | buildTarget: Windows Store Apps 85 | maxTextureSize: 2048 86 | resizeAlgorithm: 0 87 | textureFormat: -1 88 | textureCompression: 2 89 | compressionQuality: 50 90 | crunchedCompression: 0 91 | allowsAlphaSplitting: 0 92 | overridden: 0 93 | androidETC2FallbackOverride: 0 94 | - serializedVersion: 2 95 | buildTarget: Android 96 | maxTextureSize: 2048 97 | resizeAlgorithm: 0 98 | textureFormat: -1 99 | textureCompression: 2 100 | compressionQuality: 50 101 | crunchedCompression: 0 102 | allowsAlphaSplitting: 0 103 | overridden: 0 104 | androidETC2FallbackOverride: 0 105 | - serializedVersion: 2 106 | buildTarget: WebGL 107 | maxTextureSize: 2048 108 | resizeAlgorithm: 0 109 | textureFormat: -1 110 | textureCompression: 2 111 | compressionQuality: 50 112 | crunchedCompression: 0 113 | allowsAlphaSplitting: 0 114 | overridden: 0 115 | androidETC2FallbackOverride: 0 116 | spriteSheet: 117 | serializedVersion: 2 118 | sprites: [] 119 | outline: [] 120 | physicsShape: [] 121 | bones: [] 122 | spriteID: 123 | internalID: 0 124 | vertices: [] 125 | indices: 126 | edges: [] 127 | weights: [] 128 | secondaryTextures: [] 129 | spritePackingTag: 130 | pSDRemoveMatte: 0 131 | pSDShowRemoveMatteOption: 0 132 | userData: 133 | assetBundleName: 134 | assetBundleVariant: 135 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.qfsw.mop2", 3 | "displayName": "Master Object Pooler 2", 4 | "author": "QFSW", 5 | "description": "Master Object Pooler 2 is a high performance, flexible and easy to use object pooling solution that can fit into any project.", 6 | "bugs": { 7 | "email": "support@qfsw.co.uk", 8 | "url": "https://github.com/QFSW/MasterObjectPooler2/issues" 9 | }, 10 | "version": "1.0.3", 11 | "unity": "2018.4", 12 | "license": "LICENSE.md", 13 | "readme": "README.md" 14 | } 15 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 58fc6d79371bc73458edfc66080955ec 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------