The Unity script needs the Editor and the setup listed below. The separate C# companion practice runs in SharpRune without UnityEngine.
A prefab asset is a template, not one spawned actor
A prefab asset stores a reusable configured object hierarchy. Instantiate creates a runtime instance from it, and that instance has its own scene lifetime. PrefabSpawner holds an explicit asset reference, creates an instance at the spawner’s pose and schedules that returned object for removal. This does not mean every nested reference in a prefab becomes unrelated data; shared assets can remain shared by design. Distinguish the template, the created GameObject and any referenced configuration before choosing where a spawned actor’s mutable state should live.
Track the returned instance and its name
Create a Cube prefab asset, remove the scene copy, and assign the asset to an active Spawner. In Play mode, Spawn One instantiates it, renames the returned object using an incrementing ID, logs that instance and schedules Destroy with a two-second delay. Calling again creates another instance. The method validates Play mode and a supplied prefab before proceeding. The delayed destruction follows Unity’s scheduling and scaled-time behavior, not a promise of removal at an exact wall-clock timestamp in the presence of pause or frame delays.
The plain factory allocates identity without an engine
The portable EntityFactory keeps a label and next-ID counter. Its first Create returns label Drone with ID one, and its second returns the same template label with ID two. The output is Drone:1 and Drone:2. This tests a simple factory’s distinct identity policy, not native scene instantiation. IDs chosen by this local model are also not Unity GetInstanceID values. A real game needing durable entity identifiers must define their scope and persistence rather than saving an incidental runtime or factory counter without a complete lifetime contract.
An active clone can execute before post-creation configuration
Awake and OnEnable on an active instantiated prefab can run before the next line after Instantiate configures the returned object. Do not assume assigning an owner, resetting health or renaming the instance afterward happened before those callbacks. If activation depends on additional data, use a deliberate inactive creation, configuration and activation workflow. A pool has the same ordering concern. The sample only renames and logs the returned clone, so it does not promise its earlier lifecycle messages already used the final Spawned name.
Practice: observe template and instance separately
Spawn two copies and inspect their names and hierarchy entries while they exist. Change one runtime instance’s Transform and compare it with the prefab asset and the other instance. Next attach the optional LifecycleProbe from lesson three to a prefab copy and compare Awake/OnEnable messages with the spawner’s later name log. Keep this lifecycle extension separate from the basic spawn test so a missing prefab reference, asset import issue or delayed destruction does not obscure the ordering observation you actually wanted.
- Use the prefab asset field rather than accidentally assigning an unrelated scene instance.
- Record timeScale when exploring delayed Destroy instead of inferring a real-time timer guarantee.
Practice: choose the scope of generated identifiers
For an independent C# change, create two separate EntityFactory instances and inspect whether their counters overlap. Decide whether that is correct for a per-factory ID policy or unacceptable for a global persistent identity requirement. Then add an explicit configuration value copied into each entity and mutate only one entity’s runtime state. Keep shared template data and per-instance state separate. The exercise helps define what a factory guarantees without pretending the same small counter is automatically sufficient for networking, saves or Unity object lifetime.
- Test identity uniqueness within the promised scope, not within an unstated universal scope.
- Do not use a successful console factory run as proof of prefab packaging or Player instantiation.
Own creation, activation and teardown deliberately
An understandable spawning design states which asset is used, where the new instance appears, when initialization data is supplied and who removes or returns it. The real Unity script exposes those engine responsibilities, while the portable factory isolates one identity rule. Editor and Player integration still need the actual asset and scene. As spawning grows into pooling, networking or persistence, retain the same explicit lifetime boundaries instead of assuming Instantiate makes every dependency private or that a delayed Destroy proves every related managed reference has immediately disappeared.
- Portable output is Drone:1 then Drone:2.
- The Unity instance is returned after active lifecycle work may already have begun.
- A prefab template, spawned object, shared asset and durable identifier have distinct roles.
Unity Editor example
Set up in Unity 6
- Create a Cube, drag it from Hierarchy into an Assets/Prefabs folder, then remove the scene copy.
- Create an empty Spawner and attach PrefabSpawner.cs; drag the prefab asset into prefab.
- Place the spawner within the camera view, enter Play mode and invoke Spawn One twice.
- Observe distinct scene instances and their delayed removal; inspect the asset separately.
- For a lifecycle experiment, add LifecycleProbe from lesson3 to a copy of the prefab and observe when its callbacks run.
PrefabSpawner.cs
Download Unity script ↗using UnityEngine;
public sealed class PrefabSpawner : MonoBehaviour
{
[SerializeField] private GameObject prefab;
private int nextId = 1;
[ContextMenu("Spawn One")]
public void SpawnOne()
{
if (!Application.isPlaying) { Debug.LogWarning("Enter Play mode first.", this); return; }
if (prefab == null) { Debug.LogError("Assign a prefab asset.", this); return; }
GameObject instance = Instantiate(prefab, transform.position, transform.rotation);
instance.name = "Spawned-" + nextId++;
Debug.Log(instance.name, instance);
Destroy(instance, 2f);
}
}
What to observe in Unity
Two actions create named runtime instances and schedule their removal. The prefab asset remains a template; active-instance callbacks can happen before the returned instance is renamed.
The console practice below isolates the C# logic. It does not run a Unity scene or emulate Unity engine callbacks.
C# companion practice
using System;
using System.Linq;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using System.Text.Json;
using System.Threading;
using System.Threading.Tasks;
var factory = new EntityFactory("Drone");
var first = factory.Create(); var second = factory.Create();
Console.WriteLine($"{first.Label}:{first.Id}"); Console.WriteLine($"{second.Label}:{second.Id}");
sealed class Entity { public string Label { get; } public int Id { get; } public Entity(string label, int id) { Label = label; Id = id; } }
sealed class EntityFactory { private readonly string label; private int next = 1; public EntityFactory(string label) { this.label = label; } public Entity Create() => new Entity(label, next++); }
C# practice output
Drone:1 Drone:2
An active prefab can receive activation callbacks before post-Instantiate configuration.