灵符lingfu

lingdev

↓ 0 downloads

LingDev: a Godot / Unity-style game editor written in Ling. 2-D and 3-D scenes, Flash-style timeline and cutscenes, HUDs over 3-D, Ling scripting, audio / music / MIDI, builds for Windows, Linux, macOS, web, Raspberry Pi and LingOS. Ships with Ling Agent (an N64-style spy FPS), Ling Breaker (a 3-D breakout) and Moko's Picture Book (a kawaii storybook platformer).

Windows · x86-64Linux · x86-64LingOS · x86-64LingOS · Pi 5 ARM64Web · WASM
Keywords game-engine, editor, 3d, 2d, cutscene, timeline, ling, lingos, raspberry-pi
lingfu install lingdev
LicenseApache-2.0 OR MIT
Authorsling-lin
READMECode / FilesVersionsDependency GraphDependentsSecurityBuildsSettings

Code / Files (136)

ling/rt/rt_ai.ling
# rt_ai.ling - small, deterministic game-AI helpers for scripts: steering, patrols, distances,
# plus a thin pass-through to the engine's behaviour trees on the desktop runtime.

fn ai_dist(i, j) {
    bind a = nd_world_pos(i)
    bind b = nd_world_pos(j)
    bind dx = list_get(a, 0) - list_get(b, 0)
    bind dy = list_get(a, 1) - list_get(b, 1)
    bind dz = list_get(a, 2) - list_get(b, 2)
    return sqrt(dx * dx + dy * dy + dz * dz)
}
fn ai_dist_xz(i, j) {
    bind a = nd_world_pos(i)
    bind b = nd_world_pos(j)
    bind dx = list_get(a, 0) - list_get(b, 0)
    bind dz = list_get(a, 2) - list_get(b, 2)
    return sqrt(dx * dx + dz * dz)
}
# turn node i to face node j (yaw only)
fn ai_look_at(i, j) {
    bind a = nd_world_pos(i)
    bind b = nd_world_pos(j)
    nd_set(i, "ry", atan2(list_get(b, 0) - list_get(a, 0), list_get(b, 2) - list_get(a, 2)))
}
# move node i toward (tx, tz) at `speed` units/s; returns the remaining distance
fn ai_seek(i, tx, tz, speed, dt) {
    bind x = nd_get(i, "px")
    bind z = nd_get(i, "pz")
    bind dx = tx - x
    bind dz = tz - z
    bind d = sqrt(dx * dx + dz * dz)
    if d < 0.001 { return 0.0 }
    bind step = min(d, speed * dt)
    nd_set(i, "px", x + dx / d * step)
    nd_set(i, "pz", z + dz / d * step)
    nd_set(i, "ry", atan2(dx, dz))
    return d - step
}
# move away from (tx, tz)
fn ai_flee(i, tx, tz, speed, dt) {
    bind x = nd_get(i, "px")
    bind z = nd_get(i, "pz")
    bind dx = x - tx
    bind dz = z - tz
    bind d = sqrt(dx * dx + dz * dz)
    if d < 0.001 { bind dx = 1.0  bind d = 1.0 }
    nd_set(i, "px", x + dx / d * speed * dt)
    nd_set(i, "pz", z + dz / d * speed * dt)
    nd_set(i, "ry", atan2(dx, dz))
}
# follow a list of points [x0,z0, x1,z1, ...] in a loop
fn ai_patrol(i, pts, speed, dt) {
    bind n = floor(len(pts) / 2.0)
    if n < 1.0 { return 0.0 }
    bind key = "ai_pt_" + num_str(nd_id(i))
    bind k = st_get(key, 0.0)
    if k >= n { bind k = 0.0 }
    bind rem = ai_seek(i, list_get(pts, k * 2.0), list_get(pts, k * 2.0 + 1.0), speed, dt)
    if rem < 0.05 { st_set(key, (k + 1.0) % n) }
    return rem
}
# wander around a home point (new random target every few seconds)
fn ai_wander(i, hx, hz, radius, speed, dt) {
    bind key = "ai_wt_" + num_str(nd_id(i))
    bind tkey = "ai_wn_" + num_str(nd_id(i))
    bind now = st_get("game_t", 0.0)
    if st_has(key) < 0.5 || now > st_get(tkey, 0.0) {
        bind ang = rand() * 6.2831853
        bind r = rand() * radius
        st_set(key, [hx + cos(ang) * r, hz + sin(ang) * r])
        st_set(tkey, now + 2.0 + rand() * 3.0)
    }
    bind tgt = st_get(key, [hx, hz])
    return ai_seek(i, list_get(tgt, 0), list_get(tgt, 1), speed, dt)
}
# chase the player when within `sight`, otherwise wander; returns true while chasing
fn ai_guard(i, sight, speed, dt) {
    bind p = game_player()
    if p >= 0.0 && ai_dist_xz(i, p) < sight {
        bind pp = nd_world_pos(p)
        ai_seek(i, list_get(pp, 0), list_get(pp, 2), speed, dt)
        return true
    }
    bind home = st_get("ai_home_" + num_str(nd_id(i)), [])
    if len(home) < 2.0 {
        bind home = [nd_get(i, "px"), nd_get(i, "pz")]
        st_set("ai_home_" + num_str(nd_id(i)), home)
    }
    ai_wander(i, list_get(home, 0), list_get(home, 1), 4.0, speed * 0.5, dt)
    return false
}
# behaviour tree helpers (desktop engine; returns "" where unavailable)
fn ai_bt(i, src) {
    bind key = "ai_bt_" + num_str(nd_id(i))
    if st_has(key) < 0.5 { st_set(key, plat_bt_build(src)) }
    return st_get(key, 0.0 - 1.0)
}
fn ai_bt_tick(i, k, v) {
    bind h = st_get("ai_bt_" + num_str(nd_id(i)), 0.0 - 1.0)
    if h < 0.0 { return "" }
    plat_bt_set(h, k, v)
    return plat_bt_tick(h)
}

← Back to index