# pick.ludic - one target a frame: the game offers every candidate, and the nearest one the ray enters # that nothing hides is the pick. Near things occlude far ones for free, which is what a # player means by "I am looking at that one". export const AIM_NONE: int = 0 export const AIM_REACH_MIN: float = 3.0 # about as far as a hand goes with a step into it export const AIM_USE_MAX: float = 10.0 # past this the crosshair is for looking, not doing export const AIM_NEVER: float = -1.0 # a reach that is never in reach (an animal without a camera) export state AimState { am_kind: int = 0 am_id: int = -1 am_t: float = 10000.0 am_dist: float = 0.0 am_reach: bool = false am_off: float = 1.0 } # The crosshair decides WHICH; the distance decides only WHETHER. Every reach is lifted to a floor of # AIM_REACH_MIN, because a per-kind reach chosen against its model was never chosen against standing # between two props and looking at one. export function aim_reach_of(reach: float) -> float { return Math.max(reach, AIM_REACH_MIN) } export function aim_begin(aim_st: mut AimState) -> void { aim_st.am_kind = AIM_NONE aim_st.am_id = -1 aim_st.am_t = 10000.0 aim_st.am_dist = 0.0 aim_st.am_reach = false aim_st.am_off = 1.0 } # A candidate of `kind` (the game's own, not AIM_NONE) and `id`: an upright cylinder at (x, z) from y0 # to y1 of radius r, within `far` of the body, in reach within `reach` (floored; AIM_NEVER never). # True when it is now the pick. export function aim_offer(aim_st: mut AimState, kind: int, id: int, x: float, y0: float, y1: float, z: float, r: float, reach: float, far: float) -> bool { let d = aim_range(x, z) if d > far { return false } let rr = r + aim_slack_m(d) let hit = aim_ray_cyl(x, y0, y1, z, rr) if hit < 0.0 or not (hit < aim_st.am_t) { return false } if not aim_clear_at(hit, rr) { return false } aim_st.am_t = hit aim_st.am_off = aim_miss(x, z, rr) aim_st.am_kind = kind aim_st.am_id = id aim_st.am_dist = d aim_st.am_reach = reach >= 0.0 and d < aim_reach_of(reach) return true } export function aim_kind(aim_st: AimState) -> int { return aim_st.am_kind } export function aim_id(aim_st: AimState) -> int { return aim_st.am_id } export function aim_dist(aim_st: AimState) -> float { return aim_st.am_dist } export function aim_in_reach(aim_st: AimState) -> bool { return aim_st.am_reach } export function aim_t(aim_st: AimState) -> float { return aim_st.am_t } # how well centred the pick is: 0 dead centre, 1 at its (forgiven) edge export function aim_off_centre(aim_st: AimState) -> float { return aim_st.am_off }