2026-08-24 15:54:44 +02:00
|
|
|
import { Terrain } from "engine/world/Terrain"
|
|
|
|
|
import { Mesh, type Mesh as Geometry } from "engine/scene/Mesh"
|
|
|
|
|
import type { Material } from "engine/render/Material"
|
|
|
|
|
import type { ActorDefinition } from "engine/scene/Actor"
|
|
|
|
|
import { Mob, type MobState } from "game/actors/Mob"
|
2026-08-07 19:11:43 +02:00
|
|
|
import { ellipsoid, nextRand, ovoidZ, wanderHeading, wing } from "./mobkit"
|
|
|
|
|
|
2026-08-24 15:54:44 +02:00
|
|
|
export type Bee = ActorDefinition<MobState, Terrain>
|
2026-08-24 15:17:53 +02:00
|
|
|
|
|
|
|
|
export namespace Bee {
|
|
|
|
|
export function create(material: Material): Bee {
|
|
|
|
|
const mesh = Mesh.create()
|
|
|
|
|
build(mesh)
|
|
|
|
|
return {
|
|
|
|
|
prototype: {
|
|
|
|
|
groups: [{ mesh, material }],
|
|
|
|
|
radius: 0.6,
|
|
|
|
|
minY: -0.5,
|
|
|
|
|
maxY: 1,
|
|
|
|
|
},
|
|
|
|
|
update,
|
|
|
|
|
transform: Mob.transform,
|
|
|
|
|
collider: (state) => Mob.collider(state, 0.5, 0.5, false),
|
|
|
|
|
}
|
|
|
|
|
}
|
2026-08-08 14:15:32 +02:00
|
|
|
}
|
2026-08-07 19:11:43 +02:00
|
|
|
|
|
|
|
|
const LEASH = 6
|
|
|
|
|
const SPEED = 1.7
|
|
|
|
|
const TURN_MIN = 0.4
|
|
|
|
|
const TURN_SPAN = 1
|
|
|
|
|
const HOVER = 1.1
|
|
|
|
|
const BOB_AMP = 0.18
|
|
|
|
|
const BOB_FREQ = 3
|
|
|
|
|
|
2026-08-24 15:17:53 +02:00
|
|
|
function build(mesh: Geometry): void {
|
2026-08-07 19:11:43 +02:00
|
|
|
// Fore-aft ovoid body striped along its length, a dark head at the front, two
|
|
|
|
|
// pale wings. UVs: bee texture is stripe bands (left), head-dark (mid), wing-pale
|
|
|
|
|
// (right); the body maps v along z so the stripes band across it.
|
|
|
|
|
ovoidZ(mesh, -0.4, 0.4, 0.24, 7, 5, 0, 0.54, 0, 1)
|
|
|
|
|
ellipsoid(mesh, 0, 0.02, 0.44, 0.16, 0.16, 0.16, 5, 4, 0.6, 0.79, 0, 1)
|
|
|
|
|
wing(mesh, 1, 0.83, 0.99, 0, 1)
|
|
|
|
|
wing(mesh, -1, 0.83, 0.99, 0, 1)
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-24 15:54:44 +02:00
|
|
|
function update(mob: MobState, dt: number, terrain: Terrain): void {
|
2026-08-07 19:11:43 +02:00
|
|
|
mob.phase += dt
|
|
|
|
|
mob.timer -= dt
|
|
|
|
|
if (mob.timer <= 0) {
|
|
|
|
|
mob.heading = wanderHeading(mob, LEASH, 1.4)
|
|
|
|
|
mob.timer = TURN_MIN + nextRand(mob) * TURN_SPAN
|
|
|
|
|
}
|
|
|
|
|
mob.position.x += Math.sin(mob.heading) * SPEED * dt
|
|
|
|
|
mob.position.z += Math.cos(mob.heading) * SPEED * dt
|
|
|
|
|
const ground = Terrain.height(terrain, mob.position.x, mob.position.z)
|
|
|
|
|
mob.position.y = ground + HOVER + Math.sin(mob.phase * BOB_FREQ) * BOB_AMP
|
|
|
|
|
}
|