Odin't Know That ยท Appendix D

Appendix D: Troubleshooting

The recurring traps from the book, in one place. When something misbehaves, start here.

A dangling or garbled cstring

Symptom: text draws as junk, or the game crashes when drawing dynamic text. Cause: a cstring from fmt.ctprintf (or a temp-allocator clone_to_cstring) was kept past the frame it was made in; the temp memory has since been recycled. Fix: format text at the moment you draw it, every frame. Never store a temp cstring in a struct. (Chapter 3.)

Silence, or a crash, from audio

Symptom: no sound, or a crash on the first PlaySound/LoadSoundFromWave. Cause: an audio call ran before rl.InitAudioDevice(). Fix: initialise the audio device first, and defer rl.CloseAudioDevice(). All loading and playing comes after. (Chapter 10.)

The wolf teleports through a wall after a hitch

Symptom: dragging the window, alt-tabbing, or a stall makes the wolf jump through obstacles. Cause: rl.GetFrameTime() returned a huge dt for one frame, and physics integrated a giant step. Fix: clamp it: dt := min(rl.GetFrameTime(), 0.05). (Chapter 3.)

A crash in the audio callback

Symptom: intermittent crash tied to sound. Cause: the AudioStream callback runs on raylib's audio thread with no Odin context, or it raced on game state. Fix: first line of the callback is context = runtime.default_context(); keep its shared state to a couple of plain values it only reads; don't allocate or call into gameplay from it. (Chapter 10.)

Mismatched types ... f32 vs f64

Symptom: a constant expression won't multiply with an f32. Cause: an untyped float constant assigned with := defaulted to f64 (e.g. air := 2 * JUMP_SPEED / GRAVITY). Fix: pin the type: air: f32 = 2 * JUMP_SPEED / GRAVITY. (Chapter 2 & 4.)

The HUD shakes with the world

Symptom: score/messages jitter during screen shake, or scroll off with the world. Cause: the HUD was drawn inside BeginMode2D/EndMode2D. Fix: draw the world inside Mode2D; draw the HUD and backdrop outside it, in screen space. (Chapters 5, 8, 9.)

The enumerated array won't compile

Symptom: an error about a missing key in [Enum]T{...}. Cause: an enumerated array literal must cover every enum value. Fix: add the missing row (this is the feature working; it's what keeps OBSTACLE_DEFS a true single source of truth). (Chapter 6.)

os.write_entire_file won't compile / result ignored

Symptom: "result must be handled" error, or read_entire_file overload not found. Cause: in this Odin version, os.write_entire_file returns an Error you must handle, and reads use os.read_entire_file_from_path(name, allocator) -> ([]byte, Error). Fix: _ = os.write_entire_file(...) to deliberately ignore; check err != nil on read. (Ch. 11.)

Non-reproducible runs

Symptom: the "fixed seed" course differs each run. Cause: something in the simulation read the wall clock or raylib's GetRandomValue instead of the seeded generator. Fix: all gameplay randomness goes through g.rng via context.random_generator; movement uses dt, never GetTime(). (Chapter 11.)

The game won't run on a headless machine

Symptom: it works on your desktop but fails on a server/CI box with no display. Cause: raylib needs a real window server, GPU/OpenGL context and audio device. Fix: run it on a desktop with a display. (This is expected: Chapter 12.)

odin run can't find raylib

Symptom: a link or import error on import rl "vendor:raylib". Cause: a broken or partial Odin install; vendor: couldn't be resolved. Fix: reinstall/verify Odin per the install guide; raylib ships inside it; you never fetch it separately. (Chapter 1.)