akgl_rectangle_points, akgl_collide_point_rectangle, akgl_Point and akgl_RectanglePoints go. They were the intermediate form of an implementation that changed: akgl_collide_rectangles was eight corner-containment tests built on them, and it has been four span comparisons since the cross-case fix. Nothing outside tests/ called either function, and a point-in-rectangle test is four comparisons a caller can write without a struct conversion in front of them. akgl_collide_rectangles stays. It has two correct callers in the sidescroller asking a game-level overlap question -- a coin, a hazard, from an updatefunc -- where a bool is the whole answer and a proxy plus a narrowphase call would be computing a normal nothing reads. TODO.md records the split rather than leaving it to be rediscovered. Public API removal, so 194 exported akgl_ symbols against 196, and the manual's counts move with them. The perf suite loses its rectangle_points row; the all-pairs sweep stays as the control it is now labelled, and PERFORMANCE.md says what 0.8.0 measured against it -- 188.5 us for 32,640 pairs at 256 actors, where a whole step with collision attached is 54.1 us doing strictly more. 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_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.