Files
libakgl/docs/tutorials/assets/jrpg/npc_shopkeeper.png

8 lines
783 B
Plaintext
Raw Normal View History

Add two tutorial games that build, run in CI, and cannot drift examples/sidescroller and examples/jrpg are complete programs, built with the library and exercised headless by ctest. The chapters quote them with `c excerpt=examples/...` blocks rather than restating the code, so a chapter cannot drift from a program that compiles -- the excerpt check fails the moment the source moves. 34 excerpts in one chapter, 21 in the other. The two are complementary. The sidescroller is the physics tutorial: gravity, a jump, coins, hazards. The JRPG is the content-pipeline tutorial: a town map, NPCs spawned from map objects, four-way per-facing animation, a text box, a follower. Both smoke tests drive real SDL_Events through akgl_controller_handle_event and step the physics clock at a fixed 1/60s rather than sleeping, so a scripted run is deterministic and finishes in under five seconds. Writing them is what turned up most of the defects recorded in the next commit, because a game exercises paths a unit test does not. Each workaround says in the chapter which library gap forced it: - collision is written in a custom movementlogicfunc, because akgl_physics_arcade_collide raises AKERR_API and akgl_physics_simulate never calls collide at all; - the sidescroller cancels the step's own gravity when it blocks downward, because otherwise a quarter-pixel of penetration makes the *horizontal* sweep report blocked and the character walks backwards a tile at a time; - both clear movement_controls_face on every map-spawned actor, because the default facefunc leaves a stopped actor with no facing bit, no sprite, and no draw; - the JRPG's follower gets a renderfunc that nulls obj->parent for the duration of the draw, because a child's offset is counted twice. Assets are CC0 from three Kenney packs, vendored with per-pack licence text, per-file provenance, and the geometry contract in docs/tutorials/assets/README.md. CC0 specifically rather than merely free: a reader who copies a tutorial into their own game inherits no obligation. scripts/fetch_tutorial_assets.sh refreshes them in the shape mkcontrollermappings.sh was fixed into for 0.5.0 -- it checks curl's status, refuses a pack page that does not say CC0, verifies the archive and the staged dimensions, and leaves the tracked bytes untouched on any failure. Both failure paths were tested, and a no-op refresh is byte-identical. Co-Authored-By: Claude Code <noreply@anthropic.com> Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-01 20:59:00 -04:00
<EFBFBD>PNG

IHDR<01> ,r_<72>9PLTE<00>M'<27><>Lڒ><3E>}6``Z773<37>_><3E>sJeA@qH/<2F>RCŹ<43><C5B9><EFBFBD><EFBFBD><EFBFBD>Ԫzw<7A><77><EFBFBD><EFBFBD>܆R<DC86>vRp<12>/tRNS@<40><>f<02>IDATh<54><68><EFBFBD>ю<EFBFBD> ES<45><1B><><EFBFBD><EFBFBD><EFBFBD><7F>0<EFBFBD>h<EFBFBD>\<5C><><EFBFBD><EFBFBD><EC8BAF><03><>v<EFBFBD><<1E><><EFBFBD><EFBFBD>x<<1E><><EFBFBD><EFBFBD>x<<1E><><EFBFBD><EFBFBD>x<EFBFBD>Ƀ<EFBFBD>a{m<03><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c<EFBFBD><17>Raqゲ|<7C>,<2C><>)<29>Z<EFBFBD><18><><EFBFBD>'<27><>q{<7B>"*<2A><>!xY<78>Y)<29><>%<25><>y^<5E>A<EFBFBD>i?<3F>K<><4B>0W><3E>9Zoq[<5B><><EFBFBD>5`<60><0F><>
X@<08>h<><05> <0E>q<EFBFBD><71><EFBFBD><EFBFBD><EFBFBD>8<EFBFBD><38>\<5C>1<EFBFBD>m<EFBFBD>qM9<4D>g<EFBFBD>c<EFBFBD>cN<63>+<06>+C<>-b<1C><><EFBFBD>:q<><71><02><><EFBFBD>?<3F>?k<>F<EFBFBD>)p<>dqF<71>Ln
f*-n`{<7B><><02>ڦ<1F><1F><><EFBFBD><EFBFBD><EFBFBD>y<EFBFBD>Ƹ%p<><1C><><EFBFBD><EFBFBD>`<60>`<60><><18>nim<69>~tn
<EFBFBD>-<2D>/$oD<6F><44><EFBFBD>
<EFBFBD><1E><>-<2D><13>%i<><69><EFBFBD>{<7B>i<EFBFBD>@?<1C>o$<24> <0B>T<EFBFBD>|@<40><><EFBFBD><EFBFBD>l<EFBFBD>R<EFBFBD><52>J:?7S=<3D>*<2A>P<EFBFBD>!<21>m?<3F><>S
<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>_鞧<EFBFBD><EFBFBD>`<00>`.<2E><><03> ԃ<0F><> <0A>D<EFBFBD>]<5D><><EFBFBD><EFBFBD><EFBFBD>}<7D><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>c~H<># M0<4D>ZJ<5A><4A><EFBFBD><EFBFBD><EFBFBD>s<EFBFBD><73>X<><58><EFBFBD>J<EFBFBD><4A><EFBFBD>r<EFBFBD>B<EFBFBD><42><EFBFBD>z*<2A>@<40><00>֏ߏ<D68F>./r?<3F>O<EFBFBD>؏<EFBFBD>^<5E><> 2<>`f<><05> l^Anț<6E> <0B>y}F<>e<><65><EFBFBD>/<2F><>hm>9<><39> <09><05>t<EFBFBD><74>@<40>S<EFBFBD><53>a?<3F>+D[<5B>ϗ(/<2F><><14>4<><18><><EFBFBD><00>~~=i<>K<EFBFBD><4B><EFBFBD>p{g<><67><EFBFBD><07><>ϧj~<7E>Sj<53><01>ŏ.<2E><>>o/(<0F>[k<><17>G罁J<E7BD81>J<><4A> <0F><>/<2F><><EFBFBD><EFBFBD><EFBFBD>~W<><08>_穼<5F><E7A9BC>8<EFBFBD>k<EFBFBD><6B><06>/<2F>ϛ|<7C><>_.54%C<>uPIEND<4E>B`<60>