152 lines
15 KiB
Markdown
152 lines
15 KiB
Markdown
|
|
# Provenance of the tutorial assets
|
||
|
|
|
||
|
|
Everything under `docs/tutorials/assets/` is **CC0 1.0** or was written for this
|
||
|
|
repository. Nothing here carries an attribution requirement, a share-alike
|
||
|
|
clause, or a field-of-use restriction, which is the whole point: a reader who
|
||
|
|
copies a tutorial into their own game inherits whatever obligation these assets
|
||
|
|
carry, and CC0 carries none. "Free to download" is not the same thing and was
|
||
|
|
not accepted -- each pack's licence was read on its Kenney page *and* in the
|
||
|
|
`License.txt` it ships, and `scripts/fetch_tutorial_assets.sh` re-checks both on
|
||
|
|
every refresh and refuses to vendor a pack that fails either.
|
||
|
|
|
||
|
|
`LICENSE` is the CC0 1.0 legal code. The three `LICENSE.kenney_*.txt` files are
|
||
|
|
the licence statements the packs themselves ship, kept beside the art in the
|
||
|
|
same way `tests/assets/akgl_test_mono.LICENSE.txt` sits beside its font.
|
||
|
|
|
||
|
|
The two tables below account for all 56 asset files: 14 carry upstream bytes and
|
||
|
|
42 were written here. This file and `README.md` are the remaining two, and are
|
||
|
|
documentation of the same kind as the rest of `docs/`.
|
||
|
|
|
||
|
|
## Upstream packs
|
||
|
|
|
||
|
|
| Pack | URL | Licence | Licence file in this tree |
|
||
|
|
|-----------------------|------------------------------------------------|---------|--------------------------------------------|
|
||
|
|
| Pixel Line Platformer | https://kenney.nl/assets/pixel-line-platformer | CC0 1.0 | `LICENSE.kenney_pixel-line-platformer.txt` |
|
||
|
|
| RPG Urban Pack | https://kenney.nl/assets/rpg-urban-pack | CC0 1.0 | `LICENSE.kenney_rpg-urban-pack.txt` |
|
||
|
|
| Music Jingles | https://kenney.nl/assets/music-jingles | CC0 1.0 | `LICENSE.kenney_music-jingles.txt` |
|
||
|
|
|
||
|
|
Kenney asks for credit and does not require it. Credit is given here and in the
|
||
|
|
tutorial chapters.
|
||
|
|
|
||
|
|
## Files carrying upstream bytes
|
||
|
|
|
||
|
|
| File | Pack | Source URL | Licence | Cropped / repacked into |
|
||
|
|
|--------------------------------------------|-----------------------|-----------------------------------------------------------------|---------|----------------------------------------------------------------------------------------------------|
|
||
|
|
| `LICENSE` | creativecommons.org | https://creativecommons.org/publicdomain/zero/1.0/legalcode.txt | CC0 1.0 | The CC0 1.0 Universal legal code, fetched verbatim |
|
||
|
|
| `LICENSE.kenney_pixel-line-platformer.txt` | Pixel Line Platformer | https://kenney.nl/assets/pixel-line-platformer | CC0 1.0 | The pack's own `License.txt`, copied verbatim |
|
||
|
|
| `LICENSE.kenney_rpg-urban-pack.txt` | RPG Urban Pack | https://kenney.nl/assets/rpg-urban-pack | CC0 1.0 | The pack's own `License.txt`, copied verbatim |
|
||
|
|
| `LICENSE.kenney_music-jingles.txt` | Music Jingles | https://kenney.nl/assets/music-jingles | CC0 1.0 | The pack's own `License.txt`, copied verbatim |
|
||
|
|
| `sidescroller/tiles.png` | Pixel Line Platformer | https://kenney.nl/assets/pixel-line-platformer | CC0 1.0 | `Tilemap/tilemap_packed.png` copied verbatim: 160x96, 10x6 tiles of 16x16, no spacing, no margin |
|
||
|
|
| `sidescroller/player.png` | Pixel Line Platformer | https://kenney.nl/assets/pixel-line-platformer | CC0 1.0 | Tiles 40, 41, 42 and their horizontal mirrors, bottom-centred in six 32x32 cells |
|
||
|
|
| `sidescroller/coin.png` | Pixel Line Platformer | https://kenney.nl/assets/pixel-line-platformer | CC0 1.0 | Tile 44, bottom-centred in one 32x32 cell |
|
||
|
|
| `sidescroller/hazard.png` | Pixel Line Platformer | https://kenney.nl/assets/pixel-line-platformer | CC0 1.0 | Tiles 55, 56, 51, 52, bottom-centred in four 32x32 cells |
|
||
|
|
| `sidescroller/jingle_start.ogg` | Music Jingles | https://kenney.nl/assets/music-jingles | CC0 1.0 | `Audio/8-Bit jingles/jingles_NES00.ogg`, copied verbatim (1.8 s) |
|
||
|
|
| `jrpg/tiles.png` | RPG Urban Pack | https://kenney.nl/assets/rpg-urban-pack | CC0 1.0 | `Tilemap/tilemap_packed.png` copied verbatim: 432x288, 27x18 tiles of 16x16, no spacing, no margin |
|
||
|
|
| `jrpg/player.png` | RPG Urban Pack | https://kenney.nl/assets/rpg-urban-pack | CC0 1.0 | Character block 0 (tileset columns 23-26, rows 0-2) regrouped into twelve 32x32 cells |
|
||
|
|
| `jrpg/npc_shopkeeper.png` | RPG Urban Pack | https://kenney.nl/assets/rpg-urban-pack | CC0 1.0 | Character block 3 (tileset columns 23-26, rows 9-11) regrouped into twelve 32x32 cells |
|
||
|
|
| `jrpg/npc_elder.png` | RPG Urban Pack | https://kenney.nl/assets/rpg-urban-pack | CC0 1.0 | Character block 2 (tileset columns 23-26, rows 6-8) regrouped into twelve 32x32 cells |
|
||
|
|
| `jrpg/jingle_start.ogg` | Music Jingles | https://kenney.nl/assets/music-jingles | CC0 1.0 | `Audio/Pizzicato jingles/jingles_PIZZI07.ogg`, copied verbatim (1.3 s) |
|
||
|
|
|
||
|
|
## Files written for this repository
|
||
|
|
|
||
|
|
These contain no upstream content. They are libakgl source in JSON form: they
|
||
|
|
name the art above, they do not embed it.
|
||
|
|
|
||
|
|
| File | Kind | What it is |
|
||
|
|
|-------------------------------------------------|-----------|---------------------------------------------------------------------------------|
|
||
|
|
| `jrpg/character_jrpg_elder.json` | character | State-name to sprite-name bindings; contains no upstream content |
|
||
|
|
| `jrpg/character_jrpg_player.json` | character | State-name to sprite-name bindings; contains no upstream content |
|
||
|
|
| `jrpg/character_jrpg_shopkeeper.json` | character | State-name to sprite-name bindings; contains no upstream content |
|
||
|
|
| `jrpg/sprite_jrpg_elder_idle_down.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_elder_idle_left.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_elder_idle_right.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_elder_idle_up.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_elder_walk_down.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_elder_walk_left.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_elder_walk_right.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_elder_walk_up.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_player_idle_down.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_player_idle_left.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_player_idle_right.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_player_idle_up.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_player_walk_down.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_player_walk_left.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_player_walk_right.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_player_walk_up.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_shopkeeper_idle_down.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_shopkeeper_idle_left.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_shopkeeper_idle_right.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_shopkeeper_idle_up.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_shopkeeper_walk_down.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_shopkeeper_walk_left.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_shopkeeper_walk_right.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/sprite_jrpg_shopkeeper_walk_up.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `jrpg/town.tmj` | map | Tiled 1.8 TMJ, tileset **embedded**. 30x20 cells, ground + decoration + actors |
|
||
|
|
| `sidescroller/character_ss_coin.json` | character | State-name to sprite-name bindings; contains no upstream content |
|
||
|
|
| `sidescroller/character_ss_hazard_blob.json` | character | State-name to sprite-name bindings; contains no upstream content |
|
||
|
|
| `sidescroller/character_ss_hazard_moth.json` | character | State-name to sprite-name bindings; contains no upstream content |
|
||
|
|
| `sidescroller/character_ss_player.json` | character | State-name to sprite-name bindings; contains no upstream content |
|
||
|
|
| `sidescroller/level1.tmj` | map | Tiled 1.8 TMJ, tileset **embedded**. 40x15 cells, background + terrain + actors |
|
||
|
|
| `sidescroller/sprite_ss_coin.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `sidescroller/sprite_ss_hazard_blob.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `sidescroller/sprite_ss_hazard_moth.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `sidescroller/sprite_ss_player_idle_left.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `sidescroller/sprite_ss_player_idle_right.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `sidescroller/sprite_ss_player_jump_left.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `sidescroller/sprite_ss_player_jump_right.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `sidescroller/sprite_ss_player_run_left.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
| `sidescroller/sprite_ss_player_run_right.json` | sprite | Frame list into the sheet named by its own `spritesheet.filename` |
|
||
|
|
|
||
|
|
## How the repacking works, and why
|
||
|
|
|
||
|
|
**Tilesets are copied verbatim.** Both packs already ship a 16x16 grid with zero
|
||
|
|
spacing and zero margin, which is the only geometry
|
||
|
|
`akgl_tilemap_compute_tileset_offsets` gets right -- it adds `spacing` to the
|
||
|
|
tile pitch but sets the *first* row's y offset to `spacing` rather than zero,
|
||
|
|
and it ignores `margin` completely. A packed sheet with a 1 px gutter, which is
|
||
|
|
what most of Kenney's older packs ship, would render every tile in row 0 one
|
||
|
|
pixel low. That ruled several otherwise-suitable packs out.
|
||
|
|
|
||
|
|
**Character sheets are repacked into one row of 32x32 cells.** The asset
|
||
|
|
contract for these tutorials is 16x16 tiles and 32x32 character frames, and
|
||
|
|
neither pack ships 32x32 art, so each 16x16 source tile is composited at (8, 16)
|
||
|
|
inside its cell -- horizontally centred, sitting on the cell's bottom edge. The
|
||
|
|
art is not resampled: a 2x upscale would put 2x2 pixel blocks next to 1x1 tiles,
|
||
|
|
and every sprite in the repository would stop matching the source pixel for
|
||
|
|
pixel. The cost is that three quarters of each cell is empty, and the benefit is
|
||
|
|
one rule the tutorials can rely on: **an actor drawn into a 32x32 destination
|
||
|
|
rectangle has its feet on the bottom edge of that rectangle and its body
|
||
|
|
centred**, whichever sheet it came from.
|
||
|
|
|
||
|
|
**Left-facing frames are stored, not mirrored at draw time.**
|
||
|
|
`akgl_actor_render` calls `draw_texture` with `SDL_FLIP_NONE` hard-coded
|
||
|
|
(`src/actor.c`), so there is no way to ask for a mirrored blit. The sidescroller
|
||
|
|
sheet therefore carries frames 0-2 facing right and frames 3-5 as their
|
||
|
|
horizontal mirrors. The JRPG sheets need no mirroring: the RPG Urban Pack draws
|
||
|
|
both side views.
|
||
|
|
|
||
|
|
**One frame is used twice.** Pixel Line Platformer has no dedicated jump pose.
|
||
|
|
Frame 1 is the passing position of the run cycle, which is the airborne one, and
|
||
|
|
`ss_player_jump_right` reuses it. Said here rather than left for a reader to
|
||
|
|
notice.
|
||
|
|
|
||
|
|
**The coin does not animate.** Pixel Line Platformer ships one gold pickup tile
|
||
|
|
and no rotation frames, so `sprite_ss_coin.json` is a single frame. Nothing was
|
||
|
|
invented to pad it out.
|
||
|
|
|
||
|
|
## Reproducing this
|
||
|
|
|
||
|
|
```sh
|
||
|
|
scripts/fetch_tutorial_assets.sh
|
||
|
|
```
|
||
|
|
|
||
|
|
Fetches all three packs, checks each page and each shipped `License.txt` says
|
||
|
|
CC0, verifies the source images are the size the frame arithmetic assumes,
|
||
|
|
repacks into a temporary directory, checks every staged file's dimensions, and
|
||
|
|
only then moves anything into place. A failure at any step leaves the tracked
|
||
|
|
copies untouched and exits non-zero. The output is byte-for-byte reproducible --
|
||
|
|
ImageMagick's wall-clock `date:create` and `date:modify` chunks are stripped, so
|
||
|
|
a refresh that changes nothing produces no diff.
|
||
|
|
|
||
|
|
The script does not touch the JSON or the TMJ maps. Those are hand-maintained.
|