import { Terrain } from "../../Terrain" import type { Mesh } from "../../../engine/scene/Mesh" import type { Mob } from "../Mob" import type { Entity } from "../../../engine/scene/Actor" import { ellipsoid, nextRand, wanderHeading } from "./mobkit" // Everything about the frog: squat, ground-bound, sits then springs a ballistic hop. export const frog: Entity = { name: "frog", build, update, boundingRadius: 0.7, bodyHeight: 0.6, } const LEASH = 5 const REST_MIN = 0.7 const REST_SPAN = 1.8 const HOP_SPEED = 1.6 const HOP_IMPULSE = 3.2 const GRAVITY = 14 function build(mesh: Mesh): void { // Wide squat body, two eye bumps on the top-front, two hind haunches. UVs: // the frog texture is green skin on the left, a dark eye tone on the right. ellipsoid(mesh, 0, 0.26, 0, 0.5, 0.28, 0.52, 6, 4, 0, 0.68, 0, 1) ellipsoid(mesh, 0.24, 0.5, 0.26, 0.13, 0.13, 0.13, 4, 3, 0.75, 0.98, 0, 1) ellipsoid(mesh, -0.24, 0.5, 0.26, 0.13, 0.13, 0.13, 4, 3, 0.75, 0.98, 0, 1) ellipsoid(mesh, 0.3, 0.2, -0.26, 0.2, 0.2, 0.26, 4, 3, 0, 0.68, 0, 1) ellipsoid(mesh, -0.3, 0.2, -0.26, 0.2, 0.2, 0.26, 4, 3, 0, 0.68, 0, 1) } function update(mob: Mob, dt: number, terrain: Terrain): void { if (mob.grounded) { mob.timer -= dt mob.position.y = Terrain.height(terrain, mob.position.x, mob.position.z) if (mob.timer > 0) { return } // Launch a hop: pick a heading (pulled homeward past the leash), then convert // it into a forward+upward ballistic velocity. mob.heading = wanderHeading(mob, LEASH, 0.9) mob.vx = Math.sin(mob.heading) * HOP_SPEED mob.vz = Math.cos(mob.heading) * HOP_SPEED mob.vy = HOP_IMPULSE mob.grounded = false return } mob.vy -= GRAVITY * dt mob.position.x += mob.vx * dt mob.position.y += mob.vy * dt mob.position.z += mob.vz * dt const ground = Terrain.height(terrain, mob.position.x, mob.position.z) if (mob.position.y <= ground && mob.vy < 0) { mob.position.y = ground mob.vx = 0 mob.vy = 0 mob.vz = 0 mob.grounded = true mob.timer = REST_MIN + nextRand(mob) * REST_SPAN } }