Enemy Spawn Factory
enemy-spawn.ts contains factory functions that create fully-composed ECS entities for each enemy type.
Spawn Functions
| Function | Entity | Key Components |
|---|---|---|
spawnFlowerTrap() | Hostile flower | Position, EnemyState, IsHostile, PetalColors, ChunkBounds |
spawnNeutralFlowerTrap() | Passive flower | Same minus IsHostile |
spawnPathMonster() | Path sweeper | PatrolNodes, SweepDirection, DespawnAtNodeIndex |
spawnTreeBranchSnatcher() | Drop attacker | SpawnPosition (returns to perch), BoundingRadius |
spawnRootSnare() | Ground trap | IsLethal, BoundingRadius (3 studs) |
spawnNeutralRootSnare() | Visible trap | Same minus IsLethal |
spawnGigglingBush() | 50/50 gamble | IsLethal (random), BoundingRadius |
spawnWatcher() | Boss | TargetPlayer, PatrolNodes |
spawnLostQuirkymal() | Rescue target | DownedUntil (30s timer), OwnerPlayer |
spawnMimic() | Fake quirkymal | IsMimicEntity tag, appears as LostQuirkymal |
Entity Assembly Pattern
Each spawn function follows the same pattern:
export function spawnFlowerTrap(
position: CFrame,
chunkBounds: { min: Vector3; max: Vector3 },
petalColors: Color3[],
): Entity {
const entity = world.entity();
// Core components
world.set(entity, Position, position);
world.set(entity, SpawnPosition, position);
world.set(entity, EnemyType, "FlowerTrap");
world.set(entity, EnemyState, "Idle");
world.set(entity, StateSince, os.clock());
// Type-specific components
world.set(entity, IsHostile, true);
world.set(entity, PetalColors, petalColors);
world.set(entity, ChunkBounds, chunkBounds);
// Network sync
world.set(entity, NetworkId, HttpService.GenerateGUID());
world.add(entity, NeedsSync);
world.add(entity, IsFlowerTrap);
world.add(entity, IsEnemy);
// Clone and attach model
const model = cloneEnemyModel("FlowerTrap");
world.set(entity, ModelRef, model);
return entity;
}
NetworkId Generation
Each entity gets a unique HttpService.GenerateGUID() used for:
- Client ↔ server entity identification
- Rescue requests (Lost Quirkymal)
- Despawn targeting
Model Cloning
Models are cloned from ReplicatedStorage.Assets.Enemies.[TypeName] and positioned at the entity's spawn CFrame. The ModelRef component holds the reference for behavior systems to animate.
Despawn
export function despawnEnemy(entity: Entity) {
const model = world.get(entity, ModelRef);
if (model) model.Destroy();
world.delete(entity);
}