logo
By Lawrence

5 minutes

Spawn Waves of Enemies

One enemy you can kill is a target, not a game. You need a lot of them, and there's a wrong way to get them: call new for a fresh enemy on every spawn, then throw it away when it dies. That is how an arcade game stutters — the garbage collector wakes up in the middle of a fight and drops a frame. So the waves come from a pool instead: build a fixed set of enemies once, then hand them out and take them back, over and over.

The pool you already built

Across Lessons 5 and 6 you built that fixed set: the Enemies pool. Its Pool blueprint carries the whole enemy — the TwinStickEnemy brain, its LineOfSight, Health, Shadow, the Mesh GLB, and the SkeletonAnimator, all riding a collision-proxy MeshPrimitive. Sixteen copies were stamped out and parked offstage the instant the scene loaded, fully equipped but dormant, because nothing has spawned one yet. Here is the blueprint your src/scenes/TwinStickArena.json already carries:

src/scenes/TwinStickArena.json
"Enemies": {
  "tags": ["enemy"],
  "components": {
    "Pool": { "size": 16, "name": "enemy" },
    "MeshPrimitive": {
      "primitive": "sphere",
      "diameter": 1.2,
      "segments": 16,
      "material": { "diffuseColor": [0.85, 0.25, 0.35], "emissiveColor": [0.255, 0.075, 0.105] }
    },
    "TwinStickEnemy": {
      "arenaHalfWidth": 19,
      "arenaHalfDepth": 19,
      "wanderSpeed": 1.8,
      "wanderInterval": 2,
      "walkClip": "Walking",
      "attackClip": "Punch",
      "attackRangeHysteresis": 1.6,
      "fallBackClips": ["Shot_and_Blown_Back", "Walking_Blow_Back"],
      "fallForwardClips": ["Fall_Forward"]
    },
    "LineOfSight": {
      "targetTag": "player",
      "fov": 220,
      "range": 32,
      "rayCount": 3,
      "blockRadius": 0.6,
      "interval": 1.5
    },
    "Health": { "hp": 2, "maxHp": 2 },
    "Shadow": { "castShadow": true, "receiveShadow": false },
    "Mesh": {
      "src": "/shooter-shooter-bot-1/shooter-bot-1.glb",
      "instanced": true,
      "follow": true,
      "faceMode": "proxy",
      "scale": 1,
      "yawOffset": 0,
      "position": [0, 0, 0],
      "autoLoad": true,
      "lockRootMotion": true
    },
    "SkeletonAnimator": {}
  }
},

Pool is a marker that draws nothing and moves nothing. It flags this entity as a blueprint: a template the pool stamps onto every slot, so every other component on Enemies is the set each pooled enemy carries. It's the component block from Lesson 5, rounded out with the health and line-of-sight pieces from Lesson 6, pasted in as ordinary keys. No nesting.

Continue reading

Unlock the Full Course

Every lesson, the runnable examples, and the finished build — yours to keep.

$9one-time

Was this page helpful?

We read every note — tell us what's working and what isn't.

↑↓ NavigateEnter SelectEsc CloseCtrl+K Open Search