灵符lingfu

soul-symphony-ling

↓ 0 downloads

Soul Symphony — Ling Edition. A spiritual 3D adventure in the soul realm: collect the letters of the world-song, clear the monster lattice, and duel in the arcade arena. Wind Waker-style toon renderer with volumetric light pools, SSAO, bloom and oil-slick tilt-shift — all ling-lang vectors.

Keywords game, 3d, toon, music, soul-symphony
lingfu install soul-symphony-ling
AuthorsLing Lin <taellinglin@gmail.com>
READMECode / FilesVersionsDependency GraphDependentsSecurityBuildsSettings

Code / Files (1947)

game/level.ling
# ────────────────────────────────────────────────────────────────────────────
# level.ling — มหาวิหารยักษ์: ฮับ + 4 ปีก, เพดานสูงมาก, ห้องกว้าง/ลึกมาก
#   พื้น Y=3.0 · เพดาน Y=-171 (สูง 174) · ห้อง ±256 · ทางเดินแกน (ประตู ±40)
#   ปีกลึกถึง z=±960 · ขอบเขต ±960 · พื้นครึ่ง 1000 · ชน union 9 กล่อง
#   กล่องทางเดินซ้อนเข้าห้อง +30 → ไม่มีรอยต่อตัน (ข้ามได้ทุกทิศ)
# ────────────────────────────────────────────────────────────────────────────

bind LVL_F = 3.0
bind LVL_C = 0.0 - 171.0
bind ประตู = 40.0
bind พื้นครึ่ง = 1000.0

# ── ผนัง: กระเบื้องกริด — แผ่นใหญ่ขึ้น (ห้องยักษ์) เพื่อ FPS ───────────────────
ฟังก์ชัน วาดผนังเต็ม(ax, az, bx, bz) {
    bind dx = bx - ax;  bind dz = bz - az
    bind len = รากที่สอง(dx*dx + dz*dz)
    bind nseg = ปัดลง(len / 56.0) + 1
    bind nrow = 4
    bind i = 0
    ขณะที่ i < nseg {
        bind u0 = i / nseg;  bind u1 = (i + 1) / nseg
        bind x0 = ax + dx*u0;  bind z0 = az + dz*u0
        bind x1 = ax + dx*u1;  bind z1 = az + dz*u1
        bind j = 0
        ขณะที่ j < nrow {
            bind y0 = LVL_F + (LVL_C - LVL_F) * (j / nrow)
            bind y1 = LVL_F + (LVL_C - LVL_F) * ((j + 1) / nrow)
            ถ้า (i + j) % 2 == 0 { สีดินสอ(12, 16, 46) }
            มิฉะนั้น { สีดินสอ(28, 34, 82) }
            draw_quad_3d(x0, y0, z0,  x1, y0, z1,  x1, y1, z1,  x0, y1, z0)
            bind j = j + 1
        }
        bind i = i + 1
    }
}

ฟังก์ชัน วาดห้องกล่อง(x0, x1, z0, z1, dN, dS, dE, dW) {
    ถ้า dN == 1 { วาดผนังเต็ม(x0, z0, 0.0-ประตู, z0)  วาดผนังเต็ม(ประตู, z0, x1, z0) }
    มิฉะนั้น { วาดผนังเต็ม(x0, z0, x1, z0) }
    ถ้า dS == 1 { วาดผนังเต็ม(x0, z1, 0.0-ประตู, z1)  วาดผนังเต็ม(ประตู, z1, x1, z1) }
    มิฉะนั้น { วาดผนังเต็ม(x0, z1, x1, z1) }
    ถ้า dW == 1 { วาดผนังเต็ม(x0, z0, x0, 0.0-ประตู)  วาดผนังเต็ม(x0, ประตู, x0, z1) }
    มิฉะนั้น { วาดผนังเต็ม(x0, z0, x0, z1) }
    ถ้า dE == 1 { วาดผนังเต็ม(x1, z0, x1, 0.0-ประตู)  วาดผนังเต็ม(x1, ประตู, x1, z1) }
    มิฉะนั้น { วาดผนังเต็ม(x1, z0, x1, z1) }
}

ฟังก์ชัน วาดเสา(cx, cz) {
    bind w = 14.0
    สีดินสอ(40, 30, 70)
    วาดผนังเต็ม(cx-w, cz-w, cx+w, cz-w)
    วาดผนังเต็ม(cx+w, cz-w, cx+w, cz+w)
    วาดผนังเต็ม(cx+w, cz+w, cx-w, cz+w)
    วาดผนังเต็ม(cx-w, cz+w, cx-w, cz-w)
}

ฟังก์ชัน วาดทางเดิน(ax, az, bx, bz) {
    วาดผนังเต็ม(ax, az, bx, bz)
}

# ── คบไฟ: ขาแขวน + เปลวไฟวับ ๆ (additive) ที่ตำแหน่งผนัง ─────────────────────
bind คบY = 0.0 - 45.0
ฟังก์ชัน วาดคบไฟ(x, z, t, seed) {
    bind fl = 0.86 + ไซน์(t*9.0 + seed)*0.08 + ไซน์(t*15.0 + seed*2.0)*0.04
    สีดินสอ(70, 50, 30)
    วาดเส้น3มิติ(x, คบY+3.0, z, x, คบY-1.0, z)
    อนุภาคทรงกลม(x, คบY-3.0, z, 1.8, 16, t*1.4+seed, floor(255*fl), floor(126*fl), floor(30*fl))
    อนุภาคทรงกลม(x, คบY-1.5, z, 1.1, 8, t*1.7+seed, floor(255*fl), floor(178*fl), floor(72*fl))
}

# ── โคมระย้า: โซ่ห้อยจากเพดาน + วงเทียน 6 ดวง (additive) ─────────────────────
ฟังก์ชัน วาดโคมระย้า(cx, cz, t) {
    bind hy = 0.0 - 121.0
    สีดินสอ(55, 55, 65)
    วาดเส้น3มิติ(cx, LVL_C, cz, cx, hy, cz)
    bind k = 0
    ขณะที่ k < 6 {
        bind a = k * 1.0472 + t*0.25
        bind rx = cx + โคไซน์(a)*10.0
        bind rz = cz + ไซน์(a)*10.0
        สีดินสอ(55, 55, 65);  วาดเส้น3มิติ(cx, hy, cz, rx, hy, rz)
        bind fl = 0.7 + ไซน์(t*10.0 + k*1.7)*0.3
        อนุภาคทรงกลม(rx, hy-1.0, rz, 1.0, 8, t*2.0+k, 255, floor(210*fl), floor(120*fl))
        bind k = k + 1
    }
}

# ภาพคบไฟ 4 ผนัง + โคมระย้า ของห้อง [x0,x1,z0,z1]
#   + โวลูเมตริก: แอ่งแสงอุ่นใต้คบไฟ + ลำแสง/แอ่งทองใต้โคมระย้า
#   (เกรเดียนต์บวกขอบนุ่ม โปร่งแสง — เห็นสี/รัศมีไฟสาดสะท้อนบนพื้น)
ฟังก์ชัน วาดของห้อง(x0, x1, z0, z1, t) {
    bind mx = (x0+x1)*0.5;  bind mz = (z0+z1)*0.5
    วาดคบไฟ(x0+7.0, mz, t, 0.0)
    วาดคบไฟ(x1-7.0, mz, t, 1.3)
    วาดคบไฟ(mx, z0+7.0, t, 2.6)
    วาดคบไฟ(mx, z1-7.0, t, 3.9)
    วาดโคมระย้า(mx, mz, t)
    bind fl = 0.86 + ไซน์(t*7.0)*0.08                                  # วูบตามเปลวไฟ
    แอ่งแสง(x0+7.0, LVL_F, mz, 15.0, 255, 150, 58, 0.34*fl)
    แอ่งแสง(x1-7.0, LVL_F, mz, 15.0, 255, 150, 58, 0.34*fl)
    แอ่งแสง(mx, LVL_F, z0+7.0, 15.0, 255, 150, 58, 0.34*fl)
    แอ่งแสง(mx, LVL_F, z1-7.0, 15.0, 255, 150, 58, 0.34*fl)
    ลำแสงไฟ(mx, 0.0-121.0, mz, LVL_F, 24.0, 255, 210, 120, 0.16)      # ลำแสงโคมระย้า
    แอ่งแสง(mx, LVL_F, mz, 30.0, 255, 210, 120, 0.30)
}

# แสงของห้อง: คบไฟ 4 + โคมระย้า (จุดแสงจริง — ต้องเรียกก่อนวาด geometry)
ฟังก์ชัน แสงห้อง(x0, x1, z0, z1, t) {
    bind mx = (x0+x1)*0.5;  bind mz = (z0+z1)*0.5
    เพิ่มแสง(x0+7.0, คบY, mz, 1.0,0.48,0.16, 1.18, 220.0)
    เพิ่มแสง(x1-7.0, คบY, mz, 1.0,0.48,0.16, 1.18, 220.0)
    เพิ่มแสง(mx, คบY, z0+7.0, 1.0,0.48,0.16, 1.18, 220.0)
    เพิ่มแสง(mx, คบY, z1-7.0, 1.0,0.48,0.16, 1.18, 220.0)
    เพิ่มแสง(mx, 0.0-121.0, mz, 1.0,0.82,0.52, 1.4, 300.0)
}

ฟังก์ชัน แสงสีเลเวล1(cx, cz, t) {
    bind p = 0.55 + ไซน์(t*1.8)*0.10
    เพิ่มแสง(0.0, 0.0-96.0, 0.0, 0.38, 0.78, 0.86, 1.05+p, 420.0)
    เพิ่มแสง(0.0-176.0, 0.0-52.0, 176.0, 0.86, 0.22, 0.38, 0.95+p*0.35, 300.0)
    เพิ่มแสง(176.0, 0.0-52.0, 0.0-176.0, 0.32, 0.62, 0.86, 0.95+p*0.35, 300.0)
    เพิ่มแสง(176.0, 0.0-74.0, 176.0, 0.66, 0.34, 0.86, 0.90+p*0.25, 280.0)
    เพิ่มแสง(0.0-176.0, 0.0-74.0, 0.0-176.0, 0.86, 0.74, 0.28, 0.90+p*0.25, 280.0)

    ถ้า cx*cx + (cz+704.0)*(cz+704.0) < 640000.0 {
        เพิ่มแสง(0.0, 0.0-88.0, 0.0-704.0, 0.28, 0.86, 0.68, 1.15, 360.0)
        เพิ่มแสง(0.0-140.0, 0.0-42.0, 0.0-704.0, 0.82, 0.30, 0.86, 0.85, 260.0)
        เพิ่มแสง(140.0, 0.0-42.0, 0.0-704.0, 0.22, 0.48, 0.86, 0.85, 260.0)
    }
    ถ้า cx*cx + (cz-704.0)*(cz-704.0) < 640000.0 {
        เพิ่มแสง(0.0, 0.0-88.0, 704.0, 0.86, 0.38, 0.26, 1.15, 360.0)
        เพิ่มแสง(0.0-140.0, 0.0-42.0, 704.0, 0.86, 0.64, 0.24, 0.85, 260.0)
        เพิ่มแสง(140.0, 0.0-42.0, 704.0, 0.34, 0.78, 0.86, 0.85, 260.0)
    }
    ถ้า (cx-704.0)*(cx-704.0) + cz*cz < 640000.0 {
        เพิ่มแสง(704.0, 0.0-88.0, 0.0, 0.48, 0.38, 0.86, 1.15, 360.0)
        เพิ่มแสง(704.0, 0.0-42.0, 0.0-140.0, 0.86, 0.26, 0.54, 0.85, 260.0)
        เพิ่มแสง(704.0, 0.0-42.0, 140.0, 0.36, 0.86, 0.46, 0.85, 260.0)
    }
    ถ้า (cx+704.0)*(cx+704.0) + cz*cz < 640000.0 {
        เพิ่มแสง(0.0-704.0, 0.0-88.0, 0.0, 0.22, 0.78, 0.86, 1.15, 360.0)
        เพิ่มแสง(0.0-704.0, 0.0-42.0, 0.0-140.0, 0.82, 0.38, 0.86, 0.85, 260.0)
        เพิ่มแสง(0.0-704.0, 0.0-42.0, 140.0, 0.86, 0.70, 0.32, 0.85, 260.0)
    }
}

# จุดแสงทั้งเลเวล (ล้าง+เพิ่ม) — เรียกก่อนวาดพื้น/ผนัง; cull ตามระยะลูก
ฟังก์ชัน ตั้งแสงเลเวล(cx, cz, t) {
    ล้างแสง()
    แสงห้อง(0.0-64.0, 64.0, 0.0-64.0, 64.0, t)
    แสงสีเลเวล1(cx, cz, t)
    ถ้า cx*cx + (cz+352.0)*(cz+352.0) < 250000.0 {
        เพิ่มแสง(0.0-36.0, คบY, 0.0-352.0, 1.0,0.5,0.18, 1.1, 220.0)
        เพิ่มแสง(36.0, คบY, 0.0-352.0, 1.0,0.5,0.18, 1.1, 220.0)
    }
    ถ้า cx*cx + (cz-352.0)*(cz-352.0) < 250000.0 {
        เพิ่มแสง(0.0-36.0, คบY, 352.0, 1.0,0.5,0.18, 1.1, 220.0)
        เพิ่มแสง(36.0, คบY, 352.0, 1.0,0.5,0.18, 1.1, 220.0)
    }
    ถ้า (cx-352.0)*(cx-352.0) + cz*cz < 250000.0 {
        เพิ่มแสง(352.0, คบY, 0.0-36.0, 1.0,0.5,0.18, 1.1, 220.0)
        เพิ่มแสง(352.0, คบY, 36.0, 1.0,0.5,0.18, 1.1, 220.0)
    }
    ถ้า (cx+352.0)*(cx+352.0) + cz*cz < 250000.0 {
        เพิ่มแสง(0.0-352.0, คบY, 0.0-36.0, 1.0,0.5,0.18, 1.1, 220.0)
        เพิ่มแสง(0.0-352.0, คบY, 36.0, 1.0,0.5,0.18, 1.1, 220.0)
    }
    ถ้า cx*cx + (cz+704.0)*(cz+704.0) < 360000.0 { แสงห้อง(0.0-64.0,64.0,0.0-960.0,0.0-448.0,t) }
    ถ้า cx*cx + (cz-704.0)*(cz-704.0) < 360000.0 { แสงห้อง(0.0-64.0,64.0,448.0,960.0,t) }
    ถ้า (cx-704.0)*(cx-704.0) + cz*cz < 360000.0 { แสงห้อง(448.0,960.0,0.0-64.0,64.0,t) }
    ถ้า (cx+704.0)*(cx+704.0) + cz*cz < 360000.0 { แสงห้อง(0.0-960.0,0.0-448.0,0.0-64.0,64.0,t) }
}

# ── พื้น: กระเบื้องเติม (vector texture) แน่น ๆ รอบลูก (snap กับกริด ไม่ไหล) ──
#   ลาย/สีต่างจากผนัง (เขียวอมเทา) + เส้นกริดถี่
# คืน 1 ถ้ามุมทั้ง 4 ของกระเบื้อง (x0..x1, z0..z1 ที่ความสูง y) อยู่หน้า near plane
# ฉาย3มิติ คืน sx = -99999 เมื่อจุดอยู่ที่/หลัง near plane → ถ้ามุมใดหลังกล้องให้ข้าม
# กันอาการ "fan" (จุดยอดหลังกล้องโปรเจกต์พลิกข้ามจอ) ตอนกล้องอยู่ใกล้/ต่ำกับพื้น
ฟังก์ชัน กระเบื้องหน้ากล้อง(x0, y, z0, x1, z1) {
    # project the tile CENTRE only (1 projection vs 4 corners → 4× cheaper cull).
    # Tiles straddling the near plane still draw and get engine-clipped; a flat
    # floor makes the slight edge difference invisible. (Tutorial floor was the
    # #1 frame cost: ~800 tiles/frame × 4 projections.)
    bind cxm = (x0 + x1) * 0.5;  bind czm = (z0 + z1) * 0.5
    ถ้า list_get(ฉาย3มิติ(cxm, y, czm), 0) <= 0.0 - 99998.0 { คืน 0 }
    คืน 1
}

ฟังก์ชัน วาดพื้น(cx, cz) {
    bind S = 18.0
    bind n = 15                                          # รัศมีกริด = 15×18 = 270 ≈ ระยะหมอก (เลยนั้นมองไม่เห็น)
    bind bx = ปัดลง(cx / S)
    bind bz = ปัดลง(cz / S)
    โหมดผสม(0)
    set_alpha(1.0)
    set_normal_override(0.0, 0.0 - 1.0, 0.0)
    # พื้นด้าน (matte): ปิดสเปกคูลาร์/เคลียร์โค้ต — ไม่มีชีนวาว/รอยขาวสาดบนพื้น
    set_material("roughness", 0.85)
    set_material("specular", 0.05)
    set_material("specular_tint", 0.0)
    set_material("clearcoat", 0.0)
    set_material("clearcoat_roughness", 0.08)
    set_material("toon_bands", 4.0)
    set_material("shadow_softness", 0.08)
    bind i = 0 - n
    ขณะที่ i <= n {
        bind j = 0 - n
        ขณะที่ j <= n {
            bind ti = bx + i;  bind tj = bz + j
            bind x0 = ti * S;  bind z0 = tj * S
            bind x1 = x0 + S;  bind z1 = z0 + S
            # ── cull ระยะ (ถูก, ไม่เรียกฟังก์ชัน): ข้ามกระเบื้องเลยหมอก → ตัดมุมกริด ──
            bind ddx = (x0 + 9.0) - cx;  bind ddz = (z0 + 9.0) - cz
            ถ้า ddx*ddx + ddz*ddz < 73000.0 {                # ภายใน ~270 หน่วย
            ถ้า กระเบื้องหน้ากล้อง(x0, LVL_F, z0, x1, z1) == 1 {
                bind par = ti + tj
                bind par2 = par - ปัดลง(par / 2.0) * 2
                ถ้า par2 == 0 { สีดินสอ(24, 78, 70) }
                มิฉะนั้น { สีดินสอ(42, 128, 118) }
                วาดสามเหลี่ยม3มิติ(x0, LVL_F, z0,  x1, LVL_F, z0,  x1, LVL_F, z1)
                วาดสามเหลี่ยม3มิติ(x0, LVL_F, z0,  x1, LVL_F, z1,  x0, LVL_F, z1)
            } }
            bind j = j + 1
        }
        bind i = i + 1
    }
    reset_material()
    reset_normal_override()
    set_alpha(1.0)
    โหมดผสม(0)
}

ฟังก์ชัน วาดเลเวล(t, cx, cz) {
    # ── ฮับกลาง [±256], ประตูทุกด้าน (วาดเสมอ) ──
    วาดห้องกล่อง(0.0-256.0, 256.0, 0.0-256.0, 256.0, 1, 1, 1, 1)
    วาดเสา(160.0, 160.0)
    วาดเสา(0.0-160.0, 160.0)
    วาดเสา(160.0, 0.0-160.0)
    วาดเสา(0.0-160.0, 0.0-160.0)
    ถ้า cx*cx + cz*cz < 640000.0 { ลายดอกบัว(0.0, LVL_C, 0.0, 1,0,0, 0,0,1, 60.0, 210.0, 8, t*0.25, t*0.02) }
    วาดของห้อง(0.0-64.0, 64.0, 0.0-64.0, 64.0, t)

    # ── ปีกวาดเฉพาะที่ใกล้ (cull ~800) ──
    ถ้า cx*cx + (cz+704.0)*(cz+704.0) < 640000.0 {            # เหนือ
        วาดห้องกล่อง(0.0-256.0, 256.0, 0.0-960.0, 0.0-448.0, 0, 1, 0, 0)
        วาดทางเดิน(0.0-40.0, 0.0-256.0, 0.0-40.0, 0.0-448.0)
        วาดทางเดิน(40.0, 0.0-256.0, 40.0, 0.0-448.0)
        ลายดอกบัว(0.0, LVL_C, 0.0-704.0, 1,0,0, 0,0,1, 54.0, 190.0, 6, t*0.25, 1.0)
        วาดของห้อง(0.0-64.0, 64.0, 0.0-960.0, 0.0-448.0, t)
        วาดคบไฟ(0.0-36.0, 0.0-352.0, t, 5.0)
        วาดคบไฟ(36.0, 0.0-352.0, t, 6.0)
    }
    ถ้า cx*cx + (cz-704.0)*(cz-704.0) < 640000.0 {            # ใต้
        วาดห้องกล่อง(0.0-256.0, 256.0, 448.0, 960.0, 1, 0, 0, 0)
        วาดทางเดิน(0.0-40.0, 256.0, 0.0-40.0, 448.0)
        วาดทางเดิน(40.0, 256.0, 40.0, 448.0)
        ลายดอกบัว(0.0, LVL_C, 704.0, 1,0,0, 0,0,1, 54.0, 190.0, 6, t*0.25, 2.0)
        วาดของห้อง(0.0-64.0, 64.0, 448.0, 960.0, t)
        วาดคบไฟ(0.0-36.0, 352.0, t, 5.0)
        วาดคบไฟ(36.0, 352.0, t, 6.0)
    }
    ถ้า (cx-704.0)*(cx-704.0) + cz*cz < 640000.0 {            # ออก
        วาดห้องกล่อง(448.0, 960.0, 0.0-256.0, 256.0, 0, 0, 0, 1)
        วาดทางเดิน(256.0, 0.0-40.0, 448.0, 0.0-40.0)
        วาดทางเดิน(256.0, 40.0, 448.0, 40.0)
        ลายดอกบัว(704.0, LVL_C, 0.0, 1,0,0, 0,0,1, 54.0, 190.0, 6, t*0.25, 3.0)
        วาดของห้อง(448.0, 960.0, 0.0-64.0, 64.0, t)
        วาดคบไฟ(352.0, 0.0-36.0, t, 5.0)
        วาดคบไฟ(352.0, 36.0, t, 6.0)
    }
    ถ้า (cx+704.0)*(cx+704.0) + cz*cz < 640000.0 {            # ตก
        วาดห้องกล่อง(0.0-960.0, 0.0-448.0, 0.0-256.0, 256.0, 0, 0, 1, 0)
        วาดทางเดิน(0.0-256.0, 0.0-40.0, 0.0-448.0, 0.0-40.0)
        วาดทางเดิน(0.0-256.0, 40.0, 0.0-448.0, 40.0)
        ลายดอกบัว(0.0-704.0, LVL_C, 0.0, 1,0,0, 0,0,1, 54.0, 190.0, 6, t*0.25, 4.0)
        วาดของห้อง(0.0-960.0, 0.0-448.0, 0.0-64.0, 64.0, t)
        วาดคบไฟ(0.0-352.0, 0.0-36.0, t, 5.0)
        วาดคบไฟ(0.0-352.0, 36.0, t, 6.0)
    }
}

# ════════════════════════════════════════════════════════════════════════════
# การชน: union 9 กล่อง inline — กล่องทางเดินซ้อนเข้าห้อง +30 (ไม่มีรอยต่อตัน)
# ════════════════════════════════════════════════════════════════════════════
ฟังก์ชัน หากล่อง(cx, cz, R) {
    bind B = [
        0.0-256.0, 256.0, 0.0-256.0, 256.0,        # hub
        0.0-40.0, 40.0, 0.0-478.0, 0.0-226.0,      # N corr (ยืด ±30)
        0.0-256.0, 256.0, 0.0-960.0, 0.0-448.0,    # N room
        0.0-40.0, 40.0, 226.0, 478.0,              # S corr
        0.0-256.0, 256.0, 448.0, 960.0,            # S room
        226.0, 478.0, 0.0-40.0, 40.0,              # E corr
        448.0, 960.0, 0.0-256.0, 256.0,            # E room
        0.0-478.0, 0.0-226.0, 0.0-40.0, 40.0,      # W corr
        0.0-960.0, 0.0-448.0, 0.0-256.0, 256.0     # W room
    ]
    bind bpen = 1000000.0;  bind bqx = cx;  bind bqz = cz
    bind i = 0
    ขณะที่ i < 36 {
        bind x0 = list_get(B, i);  bind x1 = list_get(B, i+1)
        bind z0 = list_get(B, i+2);  bind z1 = list_get(B, i+3)
        bind qx = cx;  ถ้า qx < x0+R { bind qx = x0+R }  ถ้า qx > x1-R { bind qx = x1-R }
        bind qz = cz;  ถ้า qz < z0+R { bind qz = z0+R }  ถ้า qz > z1-R { bind qz = z1-R }
        bind p = รากที่สอง((cx-qx)*(cx-qx) + (cz-qz)*(cz-qz))
        ถ้า p < bpen { bind bpen = p;  bind bqx = qx;  bind bqz = qz }
        bind i = i + 4
    }
    คืน [bpen, bqx, bqz]
}

ฟังก์ชัน ชนเสา(ball, cx, cz, px, pz, R) {
    bind dx = cx - px;  bind dz = cz - pz
    bind d = รากที่สอง(dx*dx + dz*dz)
    bind rr = 14.0 + R
    ถ้า d < rr { ถ้า d > 0.01 {
        bind str = (rr - d) * 0.06 + 0.1
        ถ้า str > 0.7 { bind str = 0.7 }
        เตะนุ่ม(ball, dx/d, 0.0, dz/d, str)
    } }
}

ฟังก์ชัน ชนเลเวล(ball, cx, cz, R) {
    bind best = หากล่อง(cx, cz, R)
    bind pen = list_get(best,0)
    ถ้า pen > 0.0 {
        bind dx = list_get(best,1) - cx;  bind dz = list_get(best,2) - cz
        bind dd = รากที่สอง(dx*dx + dz*dz)
        ถ้า dd > 0.001 {
            bind str = pen * 0.4 + 0.12
            ถ้า str > 0.7 { bind str = 0.7 }
            เตะนุ่ม(ball, dx/dd, 0.0, dz/dd, str)
        }
    }
    ชนเสา(ball, cx, cz, 160.0, 160.0, R)
    ชนเสา(ball, cx, cz, 0.0-160.0, 160.0, R)
    ชนเสา(ball, cx, cz, 160.0, 0.0-160.0, R)
    ชนเสา(ball, cx, cz, 0.0-160.0, 0.0-160.0, R)
}

ฟังก์ชัน ดึงกล้อง(cx, cz) {
    bind best = หากล่อง(cx, cz, 3.0)
    คืน [list_get(best,1), list_get(best,2)]
}

# มองเห็น: เส้นจากจุดชม (vx,vz) ไปวัตถุ (ox,oz) โดนผนังไหม → 0 ถ้าโดนบัง, 1 ถ้าเห็น
#   สุ่มจุดบนเส้น; ถ้าจุดใดอยู่นอกพื้นเดินได้ (ในผนัง) = ถูกบัง  (lvl2=1 → ใช้ลาน proc)
ฟังก์ชัน มองเห็น(vx, vz, ox, oz, lvl2) {
    bind k = 1
    ขณะที่ k < 6 {
        bind f = k / 6.0
        bind sx = vx + (ox - vx) * f
        bind sz = vz + (oz - vz) * f
        bind pen = 0.0
        ถ้า lvl2 > 0.5 { bind pen = list_get(หากล่อง2(sx, sz, 0.0), 0) }
        มิฉะนั้น { bind pen = list_get(หากล่อง(sx, sz, 0.0), 0) }
        ถ้า pen > 0.5 { คืน 0 }
        bind k = k + 1
    }
    คืน 1
}

← Back to index