Skip to main content

Mobs

How can I make a mob of enemies that shoot projectiles at their nearest player?

To make mobs of enemies, Spawn an entity to represent each enemy, and give it a behavior that finds the nearest player and shoots every tick.

Step 1: Spawn some mobs

In this example, our mobs of enemies are called Aliens. We will define what an Alien does in the next step.

    repeat 20 {
Spawn unit {
Alien
}
}

Step 2: Make mobs attack

To make our Alien attack, we have simply given them a behavior that runs every few ticks and finds the nearest player to shoot at.

pub fn unit.Alien() {
// ...

on Tick(2.5s * Random) {
let enemy = QueryNearest(filter=Category:Hero)
if !enemy { continue }
Spawn projectile {
Bullet(heading=Angle(enemy.Pos - Pos), parent=unit)
}
}
}
  • QueryNearest finds the nearest player.
  • The on Tick(2.5s * Random) means it will rerun this block somewhere between every 0s and 2.5s, chosen randomly

Full Code Listing

pub tangible category Category:Hero
pub tangible category Category:Alien
pub tangible category Category:Projectile

pub game fn World.Main() {
TopContent { "Arrow keys to move, click to fire" }

SpawnEachPlayer owner {
Spawn unit {
Hero
}
}

repeat 20 {
Spawn unit {
Alien
}
}
}

pub fn unit.Hero([owner]) {
use body=this, radius=1, shape=Circle
Body(pos=20*RandomVector)
PolygonSprite(ownerColor=true)
PolygonCollider(category=Category:Hero)
DecaySpeed(1)
DecayTurnRate(1)

on BeforePhysics {
Move(0.25 * Joystick)
}

// Shoot towards pointer on click
on ButtonDown(Click) {
Spawn projectile {
Bullet(heading=Angle(Pointer - Pos), parent=unit)
}
}
}

pub fn unit.Alien() {
use body=this, radius=1, shape=Equilateral(numPoints=4)
Body(pos=20*RandomVector)
PolygonSprite(color=#0f0)
PolygonCollider(category=Category:Alien)
DecaySpeed(1)
DecayTurnRate(1)

// Shoot towards nearest hero every so often
on Tick(2.5s * Random) {
let enemy = QueryNearest(filter=Category:Hero)
if !enemy { continue }
Spawn projectile {
Bullet(heading=Angle(enemy.Pos - Pos), parent=unit)
}
}

// Take 50 steps in a random direction every so often
on Tick(0.5s * Random) {
let step = 0.25 * RandomVector
repeat 50 {
Move(step)
await Tick
}
}
}

// Bullet flies towards a target with a speed of 30
pub fn projectile.Bullet(heading, parent) {
use body=this, radius=0.25, shape=Circle
Body(pos=parent.Pos, velocity=30*heading.Direction)
PolygonSprite(color=#fc0)
PolygonCollider(category=Category:Projectile, parent=)

on BeforeCollide that { Expire }
once Tick(1.5s) { Expire }
}
Open in Editor