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

All 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

Factory Asset
Runtime Implementation
Use Case

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 PoolAdapter to minimize allocations.

  • 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 FusionObjectFactory that integrates with Photon Fusion 2.x.

  • Spawns objects via NetworkRunner.Spawn() and manages reuse through FusionPoolObjectProvider.

  • Automatically synchronized across clients; only the Host/Server spawns.

Notes

  • Requires a NetworkRunner configured with FusionPoolObjectProvider.

  • 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 PUNPoolPrefabProvider for 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 IPoolAdapter or IObjectProvider for advanced reuse.


8. Lifecycle Integration

All factories follow the spawner lifecycle automatically.

Spawner Call
Factory Behavior

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

Scenario
Recommended 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