Factory System Overview
The Factory System defines how the Runtime Spawner creates, reuses, and destroys game objects. It abstracts the method of instantiation (local, pooled, or networked) from the logic of spawning, allowing the same spawner setup to function across both single-player and multiplayer contexts.
Factories are configured through ScriptableObject assets derived from ObjectFactoryAsset.
At runtime, these assets produce a concrete IObjectFactory instance that the spawner uses internally.
1. Concept
When the Runtime Spawner performs a spawn, it doesn’t call Instantiate() directly - instead, it delegates the task to its assigned Object Factory.
// inside SpawnExecutor
activeFactory.Spawn(entry, position, rotation);This approach lets you swap the underlying creation logic - for example, from a simple pooled spawn in single-player to a networked spawn in Fusion or PUN - without altering any scene or wave configuration.
2. Base Class: ObjectFactoryAsset
ObjectFactoryAssetAll runtime factories derive from the abstract ObjectFactoryAsset base class.
public abstract class ObjectFactoryAsset : ScriptableObject
{
public abstract IObjectFactory Create();
}At runtime, the RuntimeSpawner calls factoryAsset.Create() to obtain the active IObjectFactory implementation.
This instance handles all spawn/despawn requests for the duration of the session.
Each subclass defines how and where instances are created - for example, in local memory or over the network.
3. Built-In Factory Assets
SinglePlayerPoolFactoryAsset
SinglePlayerPoolFactory
Local or offline gameplay using pooled instantiation
FusionFactoryAsset
FusionObjectFactory
Photon Fusion 2.x multiplayer
PUNFactoryAsset
PUNObjectFactory
Photon PUN 2+ multiplayer
All assets are created from the Unity menu:
Create → Megacrush → Spawner → Factories → [Factory Type]Assign one of these assets to the Factory field of your RuntimeSpawner.
4. Example: Single-Player Pool Factory
using UnityEngine;
namespace MegaCrush.Spawner
{
/// <summary>
/// ScriptableObject factory asset that creates a <see cref="SinglePlayerPoolFactory"/> instance.
/// </summary>
[CreateAssetMenu(menuName = EditorMenuPaths.Factories + "Single Player Pool Factory")]
public sealed class SinglePlayerPoolFactoryAsset : ObjectFactoryAsset
{
public override IObjectFactory Create()
{
// Uses the shared PoolAdapter from the Object Pool package.
return new SinglePlayerPoolFactory(new PoolAdapter());
}
}
}Description
Provides local instantiation and despawning through the Object Pool package.
Ideal for single-player, offline, or editor testing contexts.
Implements efficient reuse via
PoolAdapterto minimize allocations.
Recommended Setup
Assign to any Runtime Spawner in single-player projects.
Works seamlessly with the Spawn Hint, Region, and Wave systems.
Requires the Megacrush Object Pool package (installed automatically).
5. Example: Photon Fusion Factory
[CreateAssetMenu(menuName = EditorMenuPaths.Factories + "Photon Fusion Factory")]
public sealed class FusionFactoryAsset : ObjectFactoryAsset
{
public override IObjectFactory Create()
{
return new FusionObjectFactory();
}
}Description
Produces a
FusionObjectFactorythat integrates with Photon Fusion 2.x.Spawns objects via
NetworkRunner.Spawn()and manages reuse throughFusionPoolObjectProvider.Automatically synchronized across clients; only the Host/Server spawns.
Notes
Requires a
NetworkRunnerconfigured withFusionPoolObjectProvider.Works with the provided Fusion Bootstrap Sample Scene.
Fully supports the Runtime Spawner lifecycle (
Init,Pause,End).
6. Example: Photon PUN 2+ Factory
[CreateAssetMenu(menuName = EditorMenuPaths.Factories + "Photon PUN 2+ Factory")]
public sealed class PUNFactoryAsset : ObjectFactoryAsset
{
public override IObjectFactory Create()
{
return new PUNObjectFactory();
}
}Description
Integrates the spawner with Photon PUN 2+ using
PhotonNetwork.Instantiate().Works with
PUNPoolPrefabProviderfor pooled instantiation.The Master Client runs the spawner; other clients receive updates automatically.
Notes
Supports automatic prefab registration through
PUNPrefabRegistrar.Tested with the included PUN Sample Scene.
Handles master transfer gracefully - the new master automatically restarts spawner flow.
7. Custom Factory Assets
You can extend the system by deriving your own ObjectFactoryAsset.
For example, to support Addressables or a custom pooling backend:
[CreateAssetMenu(menuName = EditorMenuPaths.Factories + "Addressable Factory")]
public sealed class AddressableFactoryAsset : ObjectFactoryAsset
{
public override IObjectFactory Create()
{
return new AddressableFactory();
}
}Your corresponding runtime implementation might look like:
public class AddressableFactory : IObjectFactory
{
public async Task<GameObject> Spawn(SpawnEntry entry, Vector3 pos, Quaternion rot)
{
var handle = Addressables.InstantiateAsync(entry.prefabRef, pos, rot);
return await handle.Task;
}
public void Despawn(GameObject instance)
{
Addressables.ReleaseInstance(instance);
}
}Guidelines
Keep factories stateless; create transient runtime instances from assets.
If using asynchronous creation (like Addressables), integrate with deferred spawn logic.
You can attach a custom
IPoolAdapterorIObjectProviderfor advanced reuse.
8. Lifecycle Integration
All factories follow the spawner lifecycle automatically.
Init()
Factory initializes internal pools or providers.
Pause() / Resume()
Temporarily halts or resumes spawn execution.
End()
Cleanly despawns all active instances and disposes of providers.
When you transition between game states (e.g., mission start/end, network join/leave), the factory’s lifecycle methods are automatically invoked in sync with the spawner.
9. Debugging & Diagnostics
Enable Verbose Logs in the RuntimeSpawner inspector or through the Spawner Diagnostics HUD to trace which factory is being used at runtime.
Example log output:
[RuntimeSpawner] Using FusionFactoryAsset (networked mode)
[FusionObjectFactory] Spawned Enemy_Trooper (NetworkID 34)
[ObjectPool] Returned Enemy_Trooper to pool (active=12)You can also confirm correct lifecycle operation via logs like:
[RuntimeSpawner] Factory.End() called – released 42 instances.10. Choosing a Factory
Offline / local game
SinglePlayerPoolFactoryAsset
Deterministic co-op using Fusion
FusionFactoryAsset
Lightweight peer-to-peer
PUNFactoryAsset
Cloud / streaming / ECS / custom
Custom subclass of ObjectFactoryAsset
Switching is as simple as assigning a different asset in the inspector.
spawner.Factory = myFactoryAsset;At runtime, the spawner will automatically instantiate the correct factory via factoryAsset.Create().
✅ Summary
The Factory System provides a unified abstraction for all spawn and despawn behavior:
Editor-friendly configuration via ScriptableObject assets
Flexible runtime backend (local pool, Fusion, PUN, custom)
Consistent lifecycle integration with pause, resume, and end states
Zero scene changes required when switching between modes
In short: Factories define how your world spawns - while the Runtime Spawner continues to define what and when.
Last updated