code wiki / (root) / nx_game_runtime_compose_test.nx

nx_game_runtime_compose_test.nx source

↩ module page · 141 lines · 5521 B

1// nx_game_runtime_compose_test.nx -- game-runtime end-to-end. 2// 3// Full game runtime: collision → bounce → animation → audio cue → 4// save. All 4 new primitives composed with prior game-engine and 5// crypto-facade work. 22 assertions. 6 7import "nx_syscalls.nx" 8import "nx_tier.nx" 9import "nx_q14_math.nx" 10import "nx_methyl.nx" 11import "nx_chromatin.nx" 12import "nx_audio_pcm.nx" 13import "nx_collision_aabb.nx" 14import "nx_animation_timeline.nx" 15import "nx_save_slot.nx" 16 17func main() -> i64 { 18 // ===== Step 1: player + voxel collision setup =================== 19 // Player AABB at (3.5, 3.5, 3.5) sized 0.5 20 let player: *NxAabb = nx_aabb_new( 21 3 * NX_Q14 + NX_Q14 / 2 - NX_Q14 / 4, 22 3 * NX_Q14 + NX_Q14 / 2 - NX_Q14 / 4, 23 3 * NX_Q14 + NX_Q14 / 2 - NX_Q14 / 4, 24 3 * NX_Q14 + NX_Q14 / 2 + NX_Q14 / 4, 25 3 * NX_Q14 + NX_Q14 / 2 + NX_Q14 / 4, 26 3 * NX_Q14 + NX_Q14 / 2 + NX_Q14 / 4) 27 // Stone block at (4,3,3) 28 let block: *NxAabb = nx_aabb_from_voxel(4, 3, 3) 29 30 // No overlap yet 31 if nx_aabb_overlap(player, block) != NX_AABB_NO_OVERLAP { return 1 } 32 33 // Walk player +X by 0.5 -> should overlap block at (4,3,3) 34 nx_aabb_translate(player, NX_Q14 / 2, 0, 0) 35 if nx_aabb_overlap(player, block) != NX_AABB_OVERLAP { return 2 } 36 37 // Bounce back: translate -0.5 in x 38 nx_aabb_translate(player, 0 - NX_Q14 / 2, 0, 0) 39 if nx_aabb_overlap(player, block) != NX_AABB_NO_OVERLAP { return 3 } 40 41 // ===== Step 2: animation timeline for player camera bob ========= 42 // Bob: 0 at t=0, 1024 (Q14 0.0625 amplitude) at t=500ms, 0 at t=1000ms 43 let bob: *NxTimeline = nx_timeline_new(8) 44 nx_timeline_add_keyframe(bob, 0, 0) 45 nx_timeline_add_keyframe(bob, 500000, 1024) 46 nx_timeline_add_keyframe(bob, 1000000, 0) 47 if nx_timeline_count(bob) != 3 { return 4 } 48 if nx_timeline_duration_us(bob) != 1000000 { return 5 } 49 50 // Sample peaks at midpoint 51 if nx_timeline_sample(bob, 500000) != 1024 { return 6 } 52 // Quarter-point interpolation: t=250000 -> 512 (half of 1024) 53 if nx_timeline_sample(bob, 250000) != 512 { return 7 } 54 55 // Loop sample: t=1500000 wraps to t=500000 (peak) 56 if nx_timeline_sample_loop(bob, 1500000, 1000000) != 1024 { return 8 } 57 58 // ===== Step 3: audio cue on collision =========================== 59 // Short 16-sample beep at 8 kHz (2ms duration) 60 let beep_samples: *u8 = (sys_mmap(32)) as *u8 61 var i: nx_size = 0 62 while i < 16 { 63 // Alternating loud/quiet for a buzz effect 64 if (i & 1) == 0 { 65 beep_samples[i] = 200 as u8 66 } else { 67 beep_samples[i] = 56 as u8 68 } 69 i = i + 1 70 } 71 let beep: *NxPcmBuffer = nx_pcm_buffer_new(beep_samples, 16, 8000) 72 if nx_pcm_duration_us(beep) != 2000 { return 9 } 73 // Peak amplitude near full-scale 74 if nx_pcm_peak_amplitude(beep) < 50 { return 10 } 75 if nx_pcm_peak_amplitude(beep) > 80 { return 11 } 76 77 // Halve volume 78 nx_pcm_amplitude_scale_q10(beep, 512) 79 // After halving, peak should be ~36 80 let new_peak: nx_int = nx_pcm_peak_amplitude(beep) 81 if new_peak < 30 { return 12 } 82 if new_peak > 45 { return 13 } 83 84 // Resample to 16 kHz for higher-fidelity output 85 let beep_16k: *u8 = (sys_mmap(64)) as *u8 86 let n_16k: nx_int = nx_pcm_resample_linear(beep, beep_16k, 64, 16000) 87 if n_16k != 32 { return 14 } 88 89 // ===== Step 4: save the game state ============================= 90 let sig_key_msg: *u8 = (sys_mmap(96)) as *u8 91 sig_key_msg[0] = 1 as u8 92 let mark_p: *NxMethylMark = nx_methyl_new(10, 0xaaaa, 1000, sig_key_msg, 96) 93 let mark_w: *NxMethylMark = nx_methyl_new(20, 0xbbbb, 1000, sig_key_msg, 96) 94 95 let snap_player: *u8 = (sys_mmap(64)) as *u8 96 snap_player[0] = 42 as u8 97 snap_player[1] = (player.min_x_q14 & 255) as u8 // serialize player position 98 let snap_world: *u8 = (sys_mmap(64)) as *u8 99 snap_world[0] = 99 as u8 100 101 let player_ch: *NxChromatin = nx_chromatin_capture(10, 0xc101, 2000, 102 snap_player, 64, mark_p, 1) 103 let world_ch: *NxChromatin = nx_chromatin_capture(20, 0xc202, 2000, 104 snap_world, 64, mark_w, 1) 105 106 let sk: *u8 = (sys_mmap(32)) as *u8 107 var j: nx_size = 0 108 while j < 32 { 109 sk[j] = (50 + j) as u8 110 j = j + 1 111 } 112 let sig_buf: *u8 = (sys_mmap(128)) as *u8 113 let slot: *NxSaveSlot = nx_save_slot_create(7777, player_ch, world_ch, 5000, 114 sk, 32, sig_buf, 128, 410) 115 if (slot as i64) == 0 { return 15 } 116 117 // Verify save integrity 118 let v: nx_int = nx_save_slot_verify(slot, sk, 32, 410) 119 if v != NX_SS_VALID { return 16 } 120 121 // ===== Step 5: ray-AABB pickaxe test =========================== 122 // Player at (1.5, 3.5, 3.5) looking +X; should hit block at (4,3,3) at t~2.5 123 let out_t: *i64 = (sys_mmap(8)) as *i64 124 let hit: nx_int = nx_aabb_intersect_ray(block, 125 NX_Q14 + NX_Q14 / 2, // 1.5 126 3 * NX_Q14 + NX_Q14 / 2, // 3.5 127 3 * NX_Q14 + NX_Q14 / 2, // 3.5 128 NX_Q14, 0, 0, // +X 129 10 * NX_Q14, 130 out_t) 131 if hit != 1 { return 17 } 132 if out_t[0] < 40000 { return 18 } 133 if out_t[0] > 42000 { return 19 } // ~2.5 in Q14 = 40960 134 135 // ===== Step 6: forensic asserts ================================= 136 if nx_pcm_duration_us(beep) != 2000 { return 20 } 137 if nx_timeline_count(bob) != 3 { return 21 } 138 if nx_save_slot_id(slot) != 7777 { return 22 } 139 140 return 0 141}