# horse.ludic - a horse under the stick: a walk, a canter on stamina, hay for every metre; it will # not step into water, and its legs (VehicleLegs) meet the ground and whatever stands in its way # (its numbers are its kind's VehicleSpec: walk, run, acc, turn, the stamina and the hay) function ve_ride_horse(vehicles_st: mut VehiclesState, v: Vehicle, ix: float, iz: float, run: bool, dt: float) -> void { let sp = vehicle_spec(vehicles_st, v.kind) var top = sp.walk if run and v.fuel > sp.run_min { top = sp.run } v.speed = v.speed + Math.clamp(iz * top - v.speed, -sp.acc * dt, sp.acc * dt) # Steering follows SIGNED speed: backing up with the stick left swings the nose right if Math.abs(v.speed) > 0.3 { var rate = Math.clamp(Math.abs(v.speed) / 3.0, 0.4, 1.0) if v.speed < 0.0 { rate = -rate } v.yaw = v.yaw - ix * sp.turn * (dt * rate) } let fx = -Math.sin(v.yaw) let fz = -Math.cos(v.yaw) let d = v.speed * dt let nh = VehicleWorld.ground(v.x + fx * d, v.z + fz * d) if nh < VehicleWorld.water(v.x + fx * d, v.z + fz * d) + 0.4 { v.speed = 0.0 return } ve_legs_walk(vehicles_st, v, fx * v.speed, fz * v.speed, dt) ve_stamina(sp, v, d, dt) } # the legs carry it from where it is; what they covered along its heading is its speed now, never # more than was asked, so a trunk or a rise it cannot take brings it to a stand function ve_legs_walk(vehicles_st: mut VehiclesState, v: Vehicle, vx: float, vz: float, dt: float) -> void { if not VehicleLegs.walk(v.nid, v.x, v.y, v.z, vx, vz, dt) { return } let dx = VehicleLegs.x() - v.x let dz = VehicleLegs.z() - v.z v.x = VehicleLegs.x() v.y = VehicleLegs.y() v.z = VehicleLegs.z() let got = (dx * -Math.sin(v.yaw) + dz * -Math.cos(v.yaw)) / dt if v.speed > 0.0 { v.speed = Math.clamp(got, 0.0, v.speed) } else { v.speed = Math.clamp(got, v.speed, 0.0) } let moved = Math.sqrt(dx * dx + dz * dz) if moved > 0.0 { ve_moved_add(vehicles_st, v, moved) } } # a gallop spends stamina and a walk gives it back; every metre costs hay function ve_stamina(sp: VehicleSpec, v: Vehicle, d: float, dt: float) -> void { if Math.abs(v.speed) > sp.tire_at { v.fuel = Math.max(v.fuel - sp.tire * dt, 0.0) } else { v.fuel = Math.min(v.fuel + sp.rest * dt, 100.0) } v.food = Math.max(v.food - Math.abs(d) * sp.hay_per_m, 0.0) }