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" import { ellipsoid, nextRand, ovoidZ, wanderHeading, wing } from "./mobkit" export type Bee = ActorDefinition 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), } } } 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 function build(mesh: Geometry): void { // 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) } function update(mob: MobState, dt: number, terrain: Terrain): void { 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 }