diff options
Diffstat (limited to 'README.org')
| -rw-r--r-- | README.org | 125 |
1 files changed, 125 insertions, 0 deletions
diff --git a/README.org b/README.org new file mode 100644 index 0000000..45db408 --- /dev/null +++ b/README.org @@ -0,0 +1,125 @@ +* Downstroke + +A 2D tile-driven game engine for Chicken Scheme, built on SDL2. Targets old-school platformer and arcade games — NES-style and beyond. The API is inspired by Phaser 2: one call to start, lifecycle hooks to fill in. A minimal game is ~20 lines of Scheme. + +#+begin_src scheme +(define my-game + (make-game + title: "My Game" width: 320 height: 240 + preload: (lambda (game) ...) ; load assets + create: (lambda (game) ...) ; set up scene + update: (lambda (game dt) ...))) ; per-frame logic (physics runs first) + +(game-run! my-game) +#+end_src + +** Features + +- Tile-based physics: gravity, velocity, AABB collision against TMX tilemaps +- Built-in update pipeline: input → acceleration → gravity → x-collision → y-collision → ground detection → entity collisions +- Entities as plists — purely functional, no classes +- Data-driven prefab/mixin system for composing entity types +- FSM-based enemy AI via the =states= egg +- Configurable input: keyboard, joystick, and controller +- Asset registry with =preload:= lifecycle hook +- Scene and camera management +- Sprite animation with frame/tick tracking +- SDL2_mixer audio via a thin FFI binding + +** Status + +Early extraction phase. The engine logic is fully working — it powers [[https://genepasquet.itch.io/macroknight][macroknight]], built for Spring Lisp Game Jam 2025. Work is underway to extract it into a standalone, installable Chicken egg. + +| Milestone | Description | Status | +|-----------+------------------------------------+----------| +| 1 | Zero-risk module extraction | DONE | +| 2 | Configurable input system | pending | +| 3 | Data-driven entity rendering | pending | +| 4 | Renderer abstraction | pending | +| 5 | Asset preloading | pending | +| 6 | Scene loading via =create:= hook | pending | +| 7 | =make-game= / =game-run!= API | pending | +| 8 | Camera follow | pending | +| 9 | Named scene states | pending | +| 10 | AI tag-based lookup | pending | +| 11 | Package as Chicken egg (v0.1.0) | pending | +| 12 | Macroknight ported to use the egg | pending | + +Milestones 1–6 are pure refactoring. Milestone 7 is the design pivot where the public API stabilises. Milestones 11–12 produce the first installable egg and validate it against macroknight. + +** Dependencies + +System libraries: =SDL2=, =SDL2_image=, =SDL2_mixer=, =SDL2_ttf= + +Chicken eggs: +#+begin_example +chicken-install sdl2 sdl2-image expat matchable defstruct states \ + srfi-197 simple-logger srfi-64 +#+end_example + +** Building + +#+begin_src sh +make # compile all modules to bin/ +make test # run SRFI-64 test suites +make demos # build demo games (verifies they compile) +make clean # remove bin/ +#+end_src + +Single test module: +#+begin_src sh +csi -s tests/physics-test.scm +#+end_src + +** Architecture + +Modules live at the project root. Each compiles as a Chicken unit (=csc -c -J -unit=). Compile order follows the dependency graph: + +: entity, tilemap → world → animation, physics, ai → input → prefabs → mixer → sound → engine + +| Module | Responsibility | +|----------------+---------------------------------------------------| +| =entity= | Plist accessors: =entity-ref=, =entity-set= | +| =tilemap= | TMX/TSX parsing (expat), tileset loading | +| =world= | Scene struct, entity list ops, camera | +| =physics= | Gravity, velocity, AABB tile + entity collisions | +| =input= | SDL2 events → action mapping, configurable binds | +| =animation= | Frame/tick tracking, sprite ID mapping | +| =ai= | FSM enemy AI: idle → patrol → chase → attack | +| =prefabs= | Mixin composition, entity instantiation | +| =renderer= | =draw-sprite=, =draw-tilemap-layer=, =draw-text= | +| =assets= | Asset registry for the =preload:= hook | +| =scene-loader= | =game-load-scene!=, =instantiate-prefab= | +| =mixer= | SDL_mixer FFI (no Scheme deps) | +| =sound= | Sound registry, music playback | +| =engine= | =make-game=, =game-run!=, lifecycle orchestration | + +Entities are plists — no classes, purely functional: + +#+begin_src scheme +(list #:type 'player + #:x 100 #:y 200 #:width 16 #:height 16 + #:vx 0 #:vy 0 + #:gravity? #t #:on-ground? #f + #:tile-id 29 + #:tags '(player) + #:anim-name 'walk + #:animations '((idle #:frames (28) #:duration 10) + (walk #:frames (27 28) #:duration 10))) +#+end_src + +Entity types are composed from mixins declared in a data file: + +#+begin_src scheme +(mixins + (physics-body #:vx 0 #:vy 0 #:gravity? #t #:on-ground? #f) + (has-facing #:facing 1)) + +(prefabs + (player physics-body has-facing #:type player #:tile-id 29)) +#+end_src + +** Credits + +Engine extracted from [[https://genepasquet.itch.io/macroknight][macroknight]] (Spring Lisp Game Jam 2025). +Code: Gene Pasquet — Levels: Owen Pasquet — Art: [[https://kenney.nl][Kenney]] (1-bit pack) |
