The new chapter 15 covers the opt-in setup, where resolution runs in the step and why it runs after the move, shapes and the z-extrusion trap, the asymmetric masks and the defaults that matter more than the mechanism, tiles as a source rather than proxies, the response hook and the three ways it is easy to write wrongly, sensors, the four queries, both partitioners, and what is still not implemented. Collision falsified claims in eight other chapters. The physics chapter said "There is no collision detection, at all" and that collide always raises AKERR_API; actors had six behaviour hooks; the heap had five pools and four non-claiming acquires; the status band held five codes; and the design philosophy had exactly two pluggable subsystems. The appendix gains a collision.h status section, the three new pool ceilings and a table of the collision constants that are deliberately not in a public header. Also fixes chapter labels the renumbering commit left pointing at their old numbers -- "18. Utilities" linked to 19-utilities.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KzBDV2fqgnUAcqCKqKvc71
22 KiB
22. Appendix: limits, statuses and properties
Three reference tables that no single chapter owns: which function raises which status, every compile-time bound, and every configuration property the library reads.
The constant tables come in as excerpt= blocks against their headers, so they cannot
drift from the values the library was built with — and so the hand-aligned columns those
headers maintain survive.
A. Status cross-reference
What this table is. The statuses a caller can expect to see out of each function. It is
built from the FAIL_* and HANDLE* sites in src/ — the function's own body and the
static helpers only it calls — plus, where a nested libakgl call is part of the documented
contract, that status too.
It is not exhaustive, and cannot be. Every libakgl function a given one calls can
propagate anything from its own row, and so can libakstdlib: nearly everything that touches
a file also carries whatever aksl_fopen, aksl_fread, aksl_fwrite and aksl_fclose
report, including bare errno values such as ENOENT, EACCES and ENOSPC. Use the table
to write the HANDLE arms you care about, not to prove a status cannot arrive.
(H) marks a status the function handles rather than raises.
What the statuses mean is Chapter 4.
error.h
| Function | Raises |
|---|---|
akgl_error_init |
AKERR_STATUS_RANGE_OVERLAP, AKERR_STATUS_RANGE_FULL, AKERR_STATUS_NAME_FULL (all libakerror's) |
heap.h
| Function | Raises |
|---|---|
akgl_heap_init, akgl_heap_init_actor |
nothing — no failure path today |
akgl_heap_next_actor, _sprite, _spritesheet, _character, _string, _collision_proxy, _collision_cell, _bspnode |
AKGL_ERR_HEAP |
akgl_heap_release_actor, _sprite, _spritesheet, _character, _string, _collision_proxy, _collision_cell, _bspnode |
AKERR_NULLPOINTER |
registry.h
| Function | Raises |
|---|---|
akgl_registry_init and the eight akgl_registry_init_* |
AKERR_NULLPOINTER |
akgl_registry_load_properties |
AKERR_NULLPOINTER, AKERR_KEY, AKERR_TYPE, AKGL_ERR_HEAP |
akgl_set_property |
AKERR_NULLPOINTER |
akgl_get_property |
AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS, AKERR_VALUE, AKGL_ERR_HEAP |
game.h
| Function | Raises |
|---|---|
akgl_game_init |
AKERR_NULLPOINTER, AKGL_ERR_SDL |
akgl_game_update_fps, akgl_game_lowfps |
void — cannot report |
akgl_game_state_lock |
AKGL_ERR_SDL |
akgl_game_state_unlock |
nothing |
akgl_game_update |
AKGL_ERR_SDL, plus whatever updatefunc, akgl_tilemap_scale_actor, the physics backend or the renderer raises |
akgl_game_save |
AKERR_NULLPOINTER, AKERR_IO, AKERR_OUTOFBOUNDS |
akgl_game_save_actors |
AKERR_NULLPOINTER, AKERR_IO |
akgl_game_load |
AKERR_NULLPOINTER, AKERR_API, AKERR_EOF, AKERR_IO, AKERR_VALUE |
akgl_game_load_versioncmp |
AKERR_NULLPOINTER, AKERR_VALUE, AKERR_API |
actor.h
| Function | Raises |
|---|---|
akgl_actor_initialize |
AKERR_NULLPOINTER, AKERR_KEY |
akgl_actor_set_character |
AKERR_NULLPOINTER — including "no such character" |
akgl_actor_add_child |
AKERR_NULLPOINTER, AKERR_RELATIONSHIP, AKERR_OUTOFBOUNDS |
akgl_actor_update |
AKERR_NULLPOINTER, AKERR_KEY (H) |
akgl_actor_render |
AKERR_NULLPOINTER, AKERR_KEY (H), AKERR_OUTOFBOUNDS (H) |
akgl_actor_automatic_face, _logic_movement, _logic_changeframe |
AKERR_NULLPOINTER |
akgl_actor_cmhf_*_on, akgl_actor_cmhf_*_off |
AKERR_NULLPOINTER |
akgl_registry_iterate_actor |
AKERR_NULLPOINTER, AKERR_KEY — void; unhandled means the process exits |
character.h
| Function | Raises |
|---|---|
akgl_character_initialize |
AKERR_NULLPOINTER, AKERR_KEY |
akgl_character_sprite_add |
AKERR_NULLPOINTER, AKERR_KEY |
akgl_character_sprite_get |
AKERR_NULLPOINTER, AKERR_KEY |
akgl_character_load_json |
AKERR_NULLPOINTER, AKERR_KEY for a state name that is not in AKGL_REGISTRY_ACTOR_STATE_STRINGS, and AKERR_TYPE from the JSON accessors |
akgl_character_state_sprites_iterate |
AKERR_NULLPOINTER — void; unhandled means the process exits |
sprite.h
| Function | Raises |
|---|---|
akgl_sprite_initialize |
AKERR_NULLPOINTER, AKERR_KEY |
akgl_sprite_load_json |
AKERR_NULLPOINTER, AKERR_VALUE, AKERR_OUTOFBOUNDS |
akgl_spritesheet_initialize |
AKERR_NULLPOINTER, AKERR_KEY, AKGL_ERR_SDL |
akgl_spritesheet_coords_for_frame |
AKERR_NULLPOINTER |
json_helpers.h
| Function | Raises |
|---|---|
akgl_get_json_object_value, _boolean_, _integer_, _number_, _double_, _string_, _array_value |
AKERR_NULLPOINTER, AKERR_KEY for absent, AKERR_TYPE for wrong type |
akgl_get_json_array_index_object, _integer, _string |
AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS for a short array, AKERR_TYPE |
akgl_get_json_with_default |
AKERR_NULLPOINTER; handles AKERR_KEY (H), AKERR_OUTOFBOUNDS (H), AKERR_INDEX (H) |
akgl_get_json_string_value and akgl_get_json_array_index_string also raise
AKGL_ERR_HEAP when they have to claim a pooled string and the pool is empty.
physics.h
| Function | Raises |
|---|---|
akgl_physics_init_null, akgl_physics_init_arcade |
AKERR_NULLPOINTER |
akgl_physics_factory |
AKERR_NULLPOINTER, AKERR_KEY for an unknown backend name |
akgl_physics_simulate |
AKERR_NULLPOINTER; handles AKGL_ERR_LOGICINTERRUPT (H) |
akgl_physics_null_gravity, _collide, _move |
AKERR_NULLPOINTER |
akgl_physics_arcade_gravity, _move |
AKERR_NULLPOINTER |
akgl_physics_arcade_collide |
AKERR_NULLPOINTER, plus akgl_collision_resolve's. A no-op when self->collision is NULL |
collision.h
| Function | Raises |
|---|---|
akgl_collision_shape_box, _shape_circle, _shape_capsule, _shape_bounds, _shape_interacts |
AKERR_NULLPOINTER |
akgl_collision_world_init |
AKERR_NULLPOINTER, AKERR_VALUE for a non-positive cell size, plus akgl_partitioner_factory's |
akgl_collision_bind_tilemap |
AKERR_NULLPOINTER, plus akgl_get_json_properties_boolean's; handles AKERR_KEY (H) for a layer with no collidable property |
akgl_collision_test |
AKERR_NULLPOINTER, AKGL_ERR_COLLISION when the ccd arena is exhausted — the message carries the high-water mark |
akgl_collision_resolve |
AKERR_NULLPOINTER, plus akgl_collision_test's and the actor's own collidefunc's |
akgl_collision_settle |
AKERR_NULLPOINTER, AKERR_VALUE when the shape is not clear within maxsteps |
akgl_collision_solid_at, _box_blocked, _query_box, _substeps, _sync_actors |
AKERR_NULLPOINTER |
akgl_collision_proxy_initialize, _proxy_sync, _cell_initialize |
AKERR_NULLPOINTER |
akgl_partitioner_factory |
AKERR_NULLPOINTER, AKERR_KEY for an unknown partitioner name |
akgl_partitioner_init_grid, _init_bsp |
AKERR_NULLPOINTER. The BSP's insert raises AKGL_ERR_HEAP past AKGL_MAX_HEAP_COLLISION_PROXY proxies |
akgl_actor_collide_block |
AKERR_NULLPOINTER |
renderer.h
| Function | Raises |
|---|---|
akgl_render_2d_init |
AKERR_NULLPOINTER, AKGL_ERR_SDL, plus akgl_get_property's |
akgl_render_2d_bind, _shutdown, _frame_start, _frame_end, _draw_texture, _draw_world |
AKERR_NULLPOINTER |
akgl_render_2d_draw_mesh |
AKERR_API — not implemented |
draw.h
| Function | Raises |
|---|---|
akgl_draw_point, _line, _rect, _filled_rect |
AKERR_NULLPOINTER |
akgl_draw_background |
AKERR_NULLPOINTER, AKGL_ERR_SDL |
akgl_draw_circle |
AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS, AKGL_ERR_SDL |
akgl_draw_flood_fill |
AKERR_NULLPOINTER, AKGL_ERR_SDL, AKERR_OUTOFBOUNDS past AKGL_DRAW_MAX_FLOOD_SPANS |
akgl_draw_copy_region, _paste_region |
AKERR_NULLPOINTER, AKGL_ERR_SDL |
tilemap.h
| Function | Raises |
|---|---|
akgl_tilemap_load |
AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS |
akgl_tilemap_load_layers |
AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS |
akgl_tilemap_load_layer_tile |
AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS |
akgl_tilemap_load_layer_image |
AKERR_NULLPOINTER, AKGL_ERR_SDL |
akgl_tilemap_load_layer_objects |
AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS |
akgl_tilemap_load_layer_object_actor |
AKERR_KEY |
akgl_tilemap_load_tilesets |
AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS past AKGL_TILEMAP_MAX_TILESETS |
akgl_tilemap_load_tilesets_each |
AKERR_NULLPOINTER |
akgl_tilemap_load_physics |
handles AKERR_KEY (H) — every physics property is optional |
akgl_get_json_tilemap_property |
AKERR_NULLPOINTER, AKERR_KEY, AKERR_TYPE |
akgl_tilemap_draw, _draw_tileset |
AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS |
akgl_tilemap_scale_actor, akgl_tilemap_release |
AKERR_NULLPOINTER |
controller.h
| Function | Raises |
|---|---|
akgl_controller_open_gamepads, _list_keyboards |
AKERR_NULLPOINTER |
akgl_controller_handle_event, _button_down, _button_up, _added, _removed |
AKERR_NULLPOINTER |
akgl_controller_pushmap |
AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS |
akgl_controller_default |
AKERR_OUTOFBOUNDS, AKGL_ERR_REGISTRY — the library's only site |
akgl_controller_poll_key, _poll_keystroke |
AKERR_NULLPOINTER |
text.h, audio.h, assets.h, util.h, staticstring.h
| Function | Raises |
|---|---|
akgl_text_loadfont |
AKERR_NULLPOINTER, AKGL_ERR_SDL |
akgl_text_unloadfont |
AKERR_NULLPOINTER, AKERR_KEY |
akgl_text_rendertextat |
AKERR_NULLPOINTER — including a NULL akgl_renderer, a NULL sdl_renderer, and a backend never run through akgl_render_2d_bind and so missing draw_texture. An empty string is not an error: it returns success having drawn nothing |
akgl_text_measure, _measure_wrapped |
AKERR_NULLPOINTER. An empty string is legal and measures 0 wide by one line high |
akgl_audio_tone, akgl_audio_sweep |
AKERR_OUTOFBOUNDS |
akgl_audio_voice_active, akgl_audio_mix |
AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS |
akgl_load_start_bgm |
AKERR_NULLPOINTER, AKGL_ERR_SDL |
akgl_path_relative |
AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS |
akgl_rectangle_points, akgl_collide_point_rectangle, akgl_collide_rectangles |
AKERR_NULLPOINTER |
akgl_compare_sdl_surfaces |
AKERR_NULLPOINTER, AKERR_VALUE |
akgl_render_and_compare |
AKERR_NULLPOINTER, AKERR_IO, AKGL_ERR_SDL |
akgl_string_initialize |
AKERR_NULLPOINTER |
akgl_string_copy |
AKERR_NULLPOINTER, AKERR_OUTOFBOUNDS, AKERR_VALUE |
B. Compile-time limits
Everything below is fixed when the library is compiled. Only the AKGL_MAX_HEAP_* eight
and AKGL_CCD_ARENA_BYTES are overridable, and even those have to be overridden for the whole build — see
Chapter 5, "The ceilings are a compile-time ABI constraint". The rest are
plain #defines with no #ifndef guard: changing one means editing the header and
rebuilding libakgl and everything linking it.
The object pools
#ifndef AKGL_MAX_HEAP_ACTOR
#define AKGL_MAX_HEAP_ACTOR 64
#endif
#ifndef AKGL_MAX_HEAP_SPRITE
#define AKGL_MAX_HEAP_SPRITE (AKGL_MAX_HEAP_ACTOR * 16)
#endif
#ifndef AKGL_MAX_HEAP_SPRITESHEET
#define AKGL_MAX_HEAP_SPRITESHEET AKGL_MAX_HEAP_SPRITE
#endif
#ifndef AKGL_MAX_HEAP_CHARACTER
#define AKGL_MAX_HEAP_CHARACTER 256
#endif
#ifndef AKGL_MAX_HEAP_STRING
#define AKGL_MAX_HEAP_STRING 256
#endif
#ifndef AKGL_MAX_HEAP_COLLISION_PROXY
#define AKGL_MAX_HEAP_COLLISION_PROXY (AKGL_MAX_HEAP_ACTOR * 2)
#endif
#ifndef AKGL_MAX_HEAP_BSPNODE
#define AKGL_MAX_HEAP_BSPNODE (AKGL_MAX_HEAP_COLLISION_PROXY)
#endif
#ifndef AKGL_MAX_HEAP_COLLISION_CELL
#define AKGL_MAX_HEAP_COLLISION_CELL (AKGL_MAX_HEAP_COLLISION_PROXY * 16)
#endif
Exceeding any of them is AKGL_ERR_HEAP.
Collision
Three of these are not in a public header, because nothing outside the broad phase may size anything against them:
| Constant | Value | Where | Bounds |
|---|---|---|---|
AKGL_CCD_ARENA_BYTES |
65536 | collision_arena.h |
The narrowphase's whole allocation budget. Overridable. One GJK/EPA box pair measures 7,264 bytes |
AKGL_COLLISION_GRID_COLS / _ROWS |
128 | src/collision_grid.c |
The dense cell-head array, 32 KB. A map wider than 128 cells wraps rather than growing |
AKGL_COLLISION_GRID_MAX_SPAN |
16 | src/collision_grid.c |
Cells one proxy may occupy. Anything larger spills to one oversized chain, which is what makes AKGL_MAX_HEAP_COLLISION_CELL provable rather than hopeful |
AKGL_COLLISION_MAX_SUBSTEPS |
8 | src/collision.c |
Sub-steps per actor per step, and therefore the speed above which tunnelling returns |
AKGL_COLLISION_MAX_ITERATIONS |
100 | src/collision.c |
ccd_t.max_iterations. libccd's own default is (unsigned long)-1 — an unbounded loop inside a frame |
AKGL_COLLISION_DEPTH_RATIO |
2.0 | collision.h |
The z extrusion, as a multiple of the largest planar half-extent. See Chapter 15 before changing it |
Strings
AKGL_MAX_STRING_LENGTH is PATH_MAX, which is 4096 on Linux. That is the capacity of
every akgl_String, and it is why the string pool is over a megabyte on its own.
Actors
/** @brief Longest actor name, including the terminator. Names are truncated, not rejected. */
#define AKGL_ACTOR_MAX_NAME_LENGTH 128
/** @brief Children one actor can carry. A child moves with its parent rather than simulating. */
#define AKGL_ACTOR_MAX_CHILDREN 8
AKGL_ACTOR_MAX_STATES is 32, fixed by the width of int32_t state rather than chosen.
A ninth child is AKERR_OUTOFBOUNDS; an over-long name is silently truncated.
Sprites and spritesheets
#define AKGL_SPRITE_MAX_FRAMES 16
#define AKGL_SPRITE_MAX_NAME_LENGTH 128
#define AKGL_SPRITE_MAX_REGISTRY_SIZE 1024
#define AKGL_SPRITE_SHEET_MAX_FILENAME_LENGTH 512
akgl_sprite_load_json bounds the frames array against AKGL_SPRITE_MAX_FRAMES before
writing anything, and refuses a frame number that will not fit a uint8_t rather than
truncating it into an index naming a different tile (TODO.md item 16).
AKGL_SPRITE_MAX_REGISTRY_SIZE is dead. It is defined in sprite.h and referenced
nowhere in src/, include/, tests/ or util/. It bounds nothing. Do not size anything
against it.
Tilemaps
/** @brief Widest map, in tiles. Width times height is what is actually bounded. */
#define AKGL_TILEMAP_MAX_WIDTH 512
/** @brief Tallest map, in tiles. */
#define AKGL_TILEMAP_MAX_HEIGHT 512
/** @brief Layers per map. Also the number of draw passes akgl_render_2d_draw_world makes. */
#define AKGL_TILEMAP_MAX_LAYERS 16
/** @brief Tilesets per map. */
#define AKGL_TILEMAP_MAX_TILESETS 16
/** @brief Entries in a tileset's offset table. Indexed by *local* tile id, so a tileset with a high `firstgid` still starts at 0. */
#define AKGL_TILEMAP_MAX_TILES_PER_IMAGE 65536
/** @brief Longest tileset name. */
#define AKGL_TILEMAP_MAX_TILESET_NAME_SIZE 512
/** @brief Longest resolved tileset image path. */
#define AKGL_TILEMAP_MAX_TILESET_FILENAME_SIZE PATH_MAX
/** @brief Longest object name. Note that an object naming an actor is truncated at #AKGL_ACTOR_MAX_NAME_LENGTH (128) instead. */
#define AKGL_TILEMAP_MAX_OBJECT_NAME_SIZE 512
/** @brief Objects in one object layer. Not enforced by the loader -- a longer group writes past the array. */
#define AKGL_TILEMAP_MAX_OBJECTS_PER_LAYER 128
Three corrections to what those comments say, all verified against src/tilemap.c:
AKGL_TILEMAP_MAX_OBJECTS_PER_LAYERis enforced. The comment above says it is not.akgl_tilemap_load_layer_objectsboundsjat the top of the loop body and raisesAKERR_OUTOFBOUNDS;akgl_tilemap_load_tilesetsdoes the same forAKGL_TILEMAP_MAX_TILESETS. Both landed in 0.5.0 (TODO.md, "Known and still open" item 17), and the header comment was not updated with them.- Width and height are not bounded individually.
akgl_tilemap_loadcheckswidth * height >= AKGL_TILEMAP_MAX_WIDTH * AKGL_TILEMAP_MAX_HEIGHT, and the comparison is>=, so the true ceiling is 262143 tiles in any shape. A 1024×256 map loads; a 512×512 one does not. AKGL_TILEMAP_MAX_TILES_PER_IMAGEis not checked anywhere. It sizestile_offsets[65536][2]in the struct and nothing validates a tileset against it. It is also whyakgl_Tilesetis large: 512 KiB of offset table per tileset, whatever the image actually holds.
Controllers
/** @brief How many control maps exist -- effectively the local player limit. */
#define AKGL_MAX_CONTROL_MAPS 8
/** @brief Bindings per control map. The default map installed by akgl_controller_default uses 8 of them. */
#define AKGL_MAX_CONTROLS 32
AKGL_CONTROLLER_KEY_BUFFER is 32 — the keystroke ring, sized so a program polling once a
frame never loses a key to a fast typist. AKGL_CONTROLLER_KEYSTROKE_TEXT is 8, enough for
one UTF-8 code point and its terminator; a longer commit is truncated on a code point
boundary rather than through the middle of one.
Drawing
AKGL_DRAW_MAX_FLOOD_SPANS is 4096 — the fixed stack of horizontal runs akgl_draw_flood_fill
keeps instead of recursing per pixel. A region needing more pending runs at once reports
AKERR_OUTOFBOUNDS rather than overflowing; an ordinary convex or moderately concave shape
needs a few dozen.
Audio
/** @brief Sample rate of the generated stream, in frames per second. */
#define AKGL_AUDIO_SAMPLE_RATE 44100
/** @brief Frames the device callback generates per pass through the mixer. */
#define AKGL_AUDIO_MIX_FRAMES 512
AKGL_AUDIO_MAX_VOICES is 3. AKGL_AUDIO_SWEEP_TICK_HZ is 60, and it divides the sample
rate exactly, so a sweep step boundary always lands on a whole frame —
AKGL_AUDIO_SWEEP_TICK_FRAMES is 735.
The SDL_mixer side is separate: AKGL_GAME_AUDIO_MAX_TRACKS is 64 playback tracks, and
slot 0 is unused — AKGL_GAME_AUDIO_TRACK_BGM is slot 1, and the rest are yours.
Time and the frame
| Constant | Value | Meaning |
|---|---|---|
AKGL_TIME_ONESEC_NS |
1000000000 | Nanoseconds in a second — the unit SDL_GetTicksNS reports in |
AKGL_TIME_ONEMS_NS |
1000000 | Nanoseconds in a millisecond — the scale factor from JSON frame durations to internal ones |
AKGL_GAME_STATE_LOCK_BUDGET_MS |
1000 | How long akgl_game_state_lock keeps trying before raising |
AKGL_GAME_STATE_LOCK_RETRY_MS |
100 | How long it sleeps between attempts |
AKGL_PHYSICS_DEFAULT_MAX_TIMESTEP |
0.05 | Default physics.max_timestep, in seconds — three frames at 60 Hz |
AKGL_TIME_ONEMS_NS was called AKGL_TIME_ONESEC_MS until 0.5.0 and held 1000000 — a name
and a value describing two different quantities. The state lock read it as a one-second
budget and was wrong by a factor of a thousand, blocking for roughly sixteen minutes.
The status band
| Constant | Value |
|---|---|
AKGL_ERR_BASE |
256 (AKERR_FIRST_CONSUMER_STATUS) |
AKGL_ERR_COUNT |
5 |
AKGL_ERR_LIMIT |
261 — the one-past-the-end sentinel, not a status |
C. Configuration properties
Everything the library reads out of AKGL_REGISTRY_PROPERTIES. Every value is a string,
including the numbers, and each is parsed by whoever reads it.
| Property | Default | Read by | Read when | Meaning |
|---|---|---|---|---|
game.screenwidth |
"0" |
akgl_render_2d_init |
once, at init | Window and camera width in pixels. Passed straight to SDL_CreateWindowAndRenderer |
game.screenheight |
"0" |
akgl_render_2d_init |
once, at init | Window and camera height in pixels |
physics.gravity.x |
"0.0" |
akgl_physics_init_arcade |
once, at init | Constant acceleration on x, px/s² |
physics.gravity.y |
"0.0" |
akgl_physics_init_arcade |
once, at init | Constant acceleration on y, px/s². Positive is down |
physics.gravity.z |
"0.0" |
akgl_physics_init_arcade |
once, at init | Constant acceleration on z, px/s² |
physics.drag.x |
"0.0" |
akgl_physics_init_arcade |
once, at init | Fraction of environmental velocity shed per second on x |
physics.drag.y |
"0.0" |
akgl_physics_init_arcade |
once, at init | Same for y. The only brake on falling — there is no terminal velocity, and ey approaches gravity_y / drag_y |
physics.drag.z |
"0.0" |
akgl_physics_init_arcade |
once, at init | Same for z |
physics.max_timestep |
"0.05" |
akgl_physics_init_arcade |
once, at init | Ceiling on a single simulation dt, in seconds |
That is the complete list — nine properties, read by two functions, each exactly once.
physics.engine is not read by anything. physics.h says in two places that
akgl_game_init passes it to akgl_physics_factory; akgl_game_init never calls the
factory, and the string does not appear in src/. Pass "null" or "arcade" to
akgl_physics_factory yourself. Correcting the header is a source change and is deliberately
out of scope for this manual.
Everything is read at init. Setting any of these after akgl_render_2d_init or
akgl_physics_init_arcade has no effect at all, and reports success. See
Chapter 6, and the startup order in
Chapter 7.
A property set before AKGL_REGISTRY_PROPERTIES exists is silently discarded.
akgl_set_property does not check SDL's return value. akgl_game_init and
akgl_registry_init both create the registry; a hand-rolled startup that creates neither
gets no configuration and no error.