rgame 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +228 -0
- data/README.md +142 -243
- data/docs/api/README.md +141 -90
- data/docs/api/app.md +125 -68
- data/docs/api/assets.md +203 -166
- data/docs/api/audio.md +130 -89
- data/docs/api/cli.md +259 -0
- data/docs/api/components.md +1045 -254
- data/docs/api/drawing.md +187 -119
- data/docs/api/examples.md +263 -0
- data/docs/api/game.md +165 -45
- data/docs/api/images.md +39 -39
- data/docs/api/input.md +344 -85
- data/docs/api/internals.md +241 -62
- data/docs/api/localization.md +285 -0
- data/docs/api/scene_graph.md +503 -123
- data/docs/api/signals.md +81 -76
- data/docs/api/systems.md +197 -64
- data/docs/api/text.md +58 -41
- data/docs/api/tile_maps.md +237 -0
- data/docs/api/toolbox.md +400 -147
- data/docs/api/ui.md +927 -0
- data/docs/api/values.md +234 -19
- data/examples/assets/README.md +322 -0
- data/examples/assets/blip.ogg +0 -0
- data/examples/assets/glyphs.json +5 -0
- data/examples/assets/glyphs.png +0 -0
- data/examples/assets/hero.json +12 -0
- data/examples/assets/hero.png +0 -0
- data/examples/assets/icons.json +13 -0
- data/examples/assets/icons.png +0 -0
- data/examples/assets/music.ogg +0 -0
- data/examples/assets/skills.json +10 -0
- data/examples/assets/skills.png +0 -0
- data/examples/assets/tileset.png +0 -0
- data/examples/assets/tileset.tsx +65 -0
- data/examples/assets/town.tmx +26 -0
- data/examples/assets/ui.json +11 -0
- data/examples/assets/ui.png +0 -0
- data/examples/collision/locales/en.yml +8 -0
- data/examples/collision/main.rb +316 -0
- data/examples/collision_tiles/locales/en.yml +9 -0
- data/examples/collision_tiles/main.rb +274 -0
- data/examples/fullscreen/locales/en.yml +10 -0
- data/examples/fullscreen/main.rb +216 -0
- data/examples/game_menu/locales/en.yml +8 -0
- data/examples/game_menu/main.rb +170 -0
- data/examples/input_glyphs/locales/en.yml +14 -0
- data/examples/input_glyphs/main.rb +213 -0
- data/examples/jump_topdown/locales/en.yml +9 -0
- data/examples/jump_topdown/main.rb +178 -0
- data/examples/localization/locales/de.yml +12 -0
- data/examples/localization/locales/en.yml +13 -0
- data/examples/localization/main.rb +158 -0
- data/examples/menu_navigation/locales/en.yml +23 -0
- data/examples/menu_navigation/main.rb +365 -0
- data/examples/music/locales/en.yml +7 -0
- data/examples/music/main.rb +134 -0
- data/examples/pathfinding/locales/en.yml +17 -0
- data/examples/pathfinding/main.rb +298 -0
- data/examples/pooling/locales/en.yml +7 -0
- data/examples/pooling/main.rb +259 -0
- data/examples/quick_wheel/locales/en.yml +16 -0
- data/examples/quick_wheel/main.rb +184 -0
- data/examples/radial_menu/locales/en.yml +16 -0
- data/examples/radial_menu/main.rb +184 -0
- data/examples/save_load/locales/en.yml +11 -0
- data/examples/save_load/main.rb +207 -0
- data/examples/save_load_ids/locales/en.yml +11 -0
- data/examples/save_load_ids/main.rb +322 -0
- data/examples/scroll_map/locales/en.yml +4 -0
- data/examples/scroll_map/main.rb +140 -0
- data/examples/signals/locales/en.yml +6 -0
- data/examples/signals/main.rb +278 -0
- data/examples/skill_bar/locales/en.yml +14 -0
- data/examples/skill_bar/main.rb +159 -0
- data/examples/sound/locales/en.yml +6 -0
- data/examples/sound/main.rb +122 -0
- data/examples/split_screen/locales/en.yml +9 -0
- data/examples/split_screen/main.rb +304 -0
- data/examples/sprite/locales/en.yml +8 -0
- data/examples/sprite/main.rb +180 -0
- data/examples/timer/locales/en.yml +12 -0
- data/examples/timer/main.rb +273 -0
- data/examples/velocity/locales/en.yml +6 -0
- data/examples/velocity/main.rb +196 -0
- data/examples/walk/locales/en.yml +4 -0
- data/examples/walk/main.rb +99 -0
- data/exe/rgame +9 -0
- data/ext/README.md +6 -5
- data/ext/rgame_core/app/app.c +215 -11
- data/ext/rgame_core/app/locale.c +67 -0
- data/ext/rgame_core/app/locale.h +28 -0
- data/ext/rgame_core/audio/audio.c +113 -2
- data/ext/rgame_core/example.rb +18 -56
- data/ext/rgame_core/extconf.rb +16 -113
- data/ext/rgame_core/graphics/canvas.c +45 -4
- data/ext/rgame_core/graphics/canvas.h +65 -10
- data/ext/rgame_core/graphics/clip.c +22 -13
- data/ext/rgame_core/include/rgame/core.h +151 -5
- data/ext/rgame_core/input/gamepad.c +57 -3
- data/ext/rgame_core/ruby/audio_ext.c +10 -5
- data/ext/rgame_core/ruby/core_ext.c +46 -7
- data/ext/rgame_core/ruby/core_ext.h +3 -0
- data/ext/rgame_core/ruby/locale_ext.c +44 -0
- data/ext/rgame_core/ruby/recording_ext.c +1 -1
- data/ext/rgame_core/ruby/renderer_ext.c +42 -19
- data/ext/rgame_util/color_ext.c +12 -3
- data/ext/rgame_util/extconf.rb +2 -20
- data/ext/rgame_util/route_search.c +305 -0
- data/ext/rgame_util/route_search.h +86 -0
- data/ext/rgame_util/route_search_ext.c +150 -0
- data/ext/rgame_util/solid_grid.c +58 -0
- data/ext/rgame_util/solid_grid.h +49 -0
- data/ext/rgame_util/solid_grid_ext.c +161 -0
- data/ext/rgame_util/tile_sweep.c +164 -0
- data/ext/rgame_util/tile_sweep.h +62 -0
- data/ext/rgame_util/tile_sweep_ext.c +155 -0
- data/ext/rgame_util/util_ext.c +3 -0
- data/ext/rgame_util/util_ext.h +15 -0
- data/lib/rgame/boot.rb +0 -10
- data/lib/rgame/cli/new_project.rb +139 -0
- data/lib/rgame/cli/templates/Gemfile.tt +23 -0
- data/lib/rgame/cli/templates/README.md.tt +93 -0
- data/lib/rgame/cli/templates/Rakefile.tt +9 -0
- data/lib/rgame/cli/templates/assets/locales/en.yml.tt +10 -0
- data/lib/rgame/cli/templates/game.rb.tt +23 -0
- data/lib/rgame/cli/templates/gitignore.tt +12 -0
- data/lib/rgame/cli/templates/main.rb.tt +11 -0
- data/lib/rgame/cli/templates/nodes/root.rb.tt +24 -0
- data/lib/rgame/cli/templates/rspec.tt +2 -0
- data/lib/rgame/cli/templates/rubocop.yml.tt +75 -0
- data/lib/rgame/cli/templates/ruby-version.tt +1 -0
- data/lib/rgame/cli/templates/spec/locales_spec.rb.tt +18 -0
- data/lib/rgame/cli/templates/spec/nodes/root_spec.rb.tt +18 -0
- data/lib/rgame/cli/templates/spec/spec_helper.rb.tt +37 -0
- data/lib/rgame/cli.rb +66 -0
- data/lib/rgame/core/app.rb +6 -42
- data/lib/rgame/core/asset_manager.rb +13 -31
- data/lib/rgame/core/audio.rb +37 -16
- data/lib/rgame/core/font.rb +0 -3
- data/lib/rgame/core/input.rb +35 -41
- data/lib/rgame/core/locale.rb +22 -0
- data/lib/rgame/core/nine_slice.rb +0 -21
- data/lib/rgame/core/recording.rb +3 -1
- data/lib/rgame/core/renderer.rb +75 -84
- data/lib/rgame/core/sprite_sheet.rb +0 -3
- data/lib/rgame/core/tile_map_renderer.rb +77 -65
- data/lib/rgame/core/ui_atlas.rb +28 -13
- data/lib/rgame/core.rb +1 -8
- data/lib/rgame/engine/actor_blockers.rb +131 -0
- data/lib/rgame/engine/animation_set.rb +1 -0
- data/lib/rgame/engine/audio_director.rb +36 -6
- data/lib/rgame/engine/bounds_blockers.rb +74 -0
- data/lib/rgame/engine/camera.rb +55 -10
- data/lib/rgame/engine/circle_collider.rb +4 -2
- data/lib/rgame/engine/collision_box.rb +26 -1
- data/lib/rgame/engine/collision_system.rb +110 -22
- data/lib/rgame/engine/component.rb +35 -1
- data/lib/rgame/engine/components/action_trigger.rb +0 -1
- data/lib/rgame/engine/components/animated_sprite.rb +31 -23
- data/lib/rgame/engine/components/box_collider.rb +99 -0
- data/lib/rgame/engine/components/camera_follow.rb +45 -0
- data/lib/rgame/engine/components/character_body.rb +21 -41
- data/lib/rgame/engine/components/circle_collider.rb +47 -11
- data/lib/rgame/engine/components/collision_world.rb +159 -31
- data/lib/rgame/engine/components/despawn_offscreen.rb +24 -8
- data/lib/rgame/engine/components/feet_collider.rb +61 -0
- data/lib/rgame/engine/components/hop.rb +76 -0
- data/lib/rgame/engine/components/identity.rb +73 -0
- data/lib/rgame/engine/components/mover.rb +285 -0
- data/lib/rgame/engine/components/navigator.rb +145 -0
- data/lib/rgame/engine/components/path_follow.rb +123 -31
- data/lib/rgame/engine/components/player_controller.rb +5 -2
- data/lib/rgame/engine/components/pool.rb +1 -1
- data/lib/rgame/engine/components/screen_wrap.rb +33 -11
- data/lib/rgame/engine/components/sprite.rb +22 -6
- data/lib/rgame/engine/components/targeting.rb +9 -11
- data/lib/rgame/engine/components/thrust_controller.rb +1 -1
- data/lib/rgame/engine/components/tile_world.rb +70 -29
- data/lib/rgame/engine/components/timer.rb +1 -1
- data/lib/rgame/engine/components/velocity.rb +23 -7
- data/lib/rgame/engine/components/wander_controller.rb +6 -2
- data/lib/rgame/engine/components/world.rb +133 -0
- data/lib/rgame/engine/contact_set.rb +74 -0
- data/lib/rgame/engine/culling.rb +45 -0
- data/lib/rgame/engine/debug_overlay.rb +23 -18
- data/lib/rgame/engine/i18n/plural.rb +45 -0
- data/lib/rgame/engine/i18n/plural_rules.rb +82 -0
- data/lib/rgame/engine/i18n/template.rb +59 -0
- data/lib/rgame/engine/i18n.rb +276 -51
- data/lib/rgame/engine/input/action_mapper.rb +76 -22
- data/lib/rgame/engine/input/actions.rb +63 -12
- data/lib/rgame/engine/input/input_map.rb +196 -0
- data/lib/rgame/engine/layout.rb +82 -0
- data/lib/rgame/engine/nav_grid.rb +87 -0
- data/lib/rgame/engine/node2d.rb +364 -80
- data/lib/rgame/engine/path.rb +4 -6
- data/lib/rgame/engine/player.rb +69 -0
- data/lib/rgame/engine/player_layer.rb +70 -0
- data/lib/rgame/engine/players.rb +205 -0
- data/lib/rgame/engine/presentation.rb +171 -0
- data/lib/rgame/engine/scene/scene_stack.rb +29 -7
- data/lib/rgame/engine/sealed_privates.rb +54 -0
- data/lib/rgame/engine/spatial_hash.rb +53 -8
- data/lib/rgame/engine/text.rb +194 -0
- data/lib/rgame/engine/tile_blockers.rb +63 -0
- data/lib/rgame/engine/tile_map.rb +2 -3
- data/lib/rgame/engine/tile_map_layer.rb +82 -0
- data/lib/rgame/engine/tileset.rb +2 -4
- data/lib/rgame/engine/timer.rb +2 -2
- data/lib/rgame/engine/ui/button.rb +248 -0
- data/lib/rgame/engine/ui/column.rb +20 -0
- data/lib/rgame/engine/ui/icon_button.rb +93 -0
- data/lib/rgame/engine/ui/menu.rb +290 -0
- data/lib/rgame/engine/ui/navigation.rb +57 -0
- data/lib/rgame/engine/ui/nine_slice_style.rb +50 -0
- data/lib/rgame/engine/ui/option_button.rb +163 -0
- data/lib/rgame/engine/ui/panel_button.rb +32 -0
- data/lib/rgame/engine/ui/panel_menu.rb +36 -0
- data/lib/rgame/engine/ui/pointing.rb +146 -0
- data/lib/rgame/engine/ui/radial_menu.rb +85 -0
- data/lib/rgame/engine/ui/ring.rb +55 -0
- data/lib/rgame/engine/ui/row.rb +21 -0
- data/lib/rgame/engine/ui/shape_style.rb +102 -0
- data/lib/rgame/engine/ui/stack.rb +58 -0
- data/lib/rgame/engine/ui/stepping.rb +93 -0
- data/lib/rgame/engine/ui/text_button.rb +59 -0
- data/lib/rgame/engine/view.rb +76 -0
- data/lib/rgame/engine/viewports.rb +171 -0
- data/lib/rgame/engine/world_view.rb +71 -0
- data/lib/rgame/engine.rb +43 -25
- data/lib/rgame/game.rb +164 -22
- data/lib/rgame/rubocop/cop/game/draw_in_local_space.rb +103 -0
- data/lib/rgame/rubocop/cop/game/hot_path.rb +36 -0
- data/lib/rgame/rubocop/cop/game/layer_boundary.rb +43 -0
- data/lib/rgame/rubocop/cop/game/no_core_in_engine_layer.rb +100 -0
- data/lib/rgame/rubocop/cop/game/no_engine_in_core_layer.rb +84 -0
- data/lib/rgame/rubocop/cop/game/no_interpolation_in_hot_path.rb +50 -0
- data/lib/rgame/rubocop/cop/game/no_literal_text.rb +41 -0
- data/lib/rgame/rubocop/cop/game/no_needless_allocation.rb +112 -0
- data/lib/rgame/rubocop/default.yml +39 -0
- data/lib/rgame/rubocop/plugin.rb +45 -0
- data/lib/rgame/rubocop.rb +11 -0
- data/lib/rgame/util/color.rb +20 -24
- data/lib/rgame/util/controls.rb +106 -44
- data/lib/rgame/util/route_search.rb +27 -0
- data/lib/rgame/util/save_file.rb +107 -0
- data/lib/rgame/util/solid_grid.rb +37 -0
- data/lib/rgame/util/tensor.rb +0 -9
- data/lib/rgame/util/tile_sweep.rb +36 -0
- data/lib/rgame/util/z.rb +123 -0
- data/lib/rgame/util.rb +5 -3
- data/lib/rgame/version.rb +1 -1
- data/lib/rgame.rb +0 -15
- metadata +176 -20
- data/lib/rgame/engine/actor.rb +0 -53
- data/lib/rgame/engine/body.rb +0 -49
- data/lib/rgame/engine/cached_label.rb +0 -33
- data/lib/rgame/engine/camera_view.rb +0 -28
- data/lib/rgame/engine/input/player_controller.rb +0 -14
- data/lib/rgame/engine/matrix.rb +0 -32
- data/lib/rgame/engine/resettable.rb +0 -67
- data/lib/rgame/engine/tile_collision.rb +0 -78
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 54caa0772adc1eb3211edbd694540c196be0018d6482089447d727f5c871e19a
|
|
4
|
+
data.tar.gz: 16b3d1de8baefc2579bbf5a89fb7b42041d174567b6c7059d5c967f2598621f5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ab441100a4d86c34d93efed615b350a7d65ad819d3b7929e868e709c6a9790b9c78a956b9860632e62750f0880ca9656a1f7f6c98cc3df6c1b19f7d229e40919
|
|
7
|
+
data.tar.gz: e98b7a96d21700bf0533f0155be99ffc9f480e35fda2375aaee4b8b2a7bb65b871d0a70a1f2486873b32e28a83aaa4abfc91a14991226153f57959b0d62237b4
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented here.
|
|
4
|
+
|
|
5
|
+
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and
|
|
6
|
+
this project uses [Semantic Versioning](https://semver.org/spec/v2.0.0.html) —
|
|
7
|
+
which before 1.0 means the public API can still change in a minor release.
|
|
8
|
+
|
|
9
|
+
Entries describe what changed for someone *using* the engine. The reasoning
|
|
10
|
+
behind a change belongs in the documentation it lands with; this file is the
|
|
11
|
+
index, not the argument.
|
|
12
|
+
|
|
13
|
+
## [Unreleased]
|
|
14
|
+
|
|
15
|
+
## [0.3.0] - 2026-09-15
|
|
16
|
+
|
|
17
|
+
### Added
|
|
18
|
+
|
|
19
|
+
- **`rgame new NAME`.** The gem installs an `rgame` command, and `rgame new`
|
|
20
|
+
generates a project: a game class, a root node, an English translation table,
|
|
21
|
+
and a spec suite and RuboCop config that pass. Only `game.rb` loads SDL, so the
|
|
22
|
+
generated specs run without a display. See [docs/api/cli.md](docs/api/cli.md).
|
|
23
|
+
- **RuboCop cops for games.** The gem ships rgame's `Game/` cops as a RuboCop
|
|
24
|
+
plugin, and `rgame new` enables them. They catch per-frame allocations, a node
|
|
25
|
+
drawn at its own position twice, literal text and Core named from headless
|
|
26
|
+
code. See [docs/api/cli.md](docs/api/cli.md#the-generated-rubocop-configuration).
|
|
27
|
+
- **Translation by default.** `RGame::Game` loads every `locales/**/*.yml` and
|
|
28
|
+
picks the player's language from `RGame::Core.preferred_locales`. A node draws
|
|
29
|
+
an `Engine::Text` built from a key, and a UI button's `label:` is a key. See
|
|
30
|
+
[docs/api/localization.md](docs/api/localization.md).
|
|
31
|
+
- **Fullscreen and scaling.** `Game.new` takes `fullscreen:` and `scale_mode:`,
|
|
32
|
+
and both can change while the game runs. `scale_mode:` maps the logical size
|
|
33
|
+
onto the window, and defaults to `:letterbox`. See
|
|
34
|
+
[docs/api/game.md](docs/api/game.md).
|
|
35
|
+
- **Saving.** `Util::SaveFile` reads and writes a game's state in the player's
|
|
36
|
+
save directory. `Components::Identity` gives a node a stable id to save it
|
|
37
|
+
under. See [docs/api/values.md](docs/api/values.md).
|
|
38
|
+
- **Box colliders.** `Components::BoxCollider` is a rectangle in the same
|
|
39
|
+
`CollisionWorld` as `CircleCollider`. `FeetCollider` derives its box from the
|
|
40
|
+
node's size, so a top-down character collides at its feet. See
|
|
41
|
+
[docs/api/components.md](docs/api/components.md).
|
|
42
|
+
- **Movers that something can stop.** `CharacterBody`, `Velocity` and
|
|
43
|
+
`PathFollow` share the base `Components::Mover`. Its `blocked_by:` lists what
|
|
44
|
+
stops a step: solid tiles, the world's edge or collider layers. `on_blocked` and
|
|
45
|
+
`on_unblocked` report the blocker and the axis. See
|
|
46
|
+
[docs/api/components.md](docs/api/components.md).
|
|
47
|
+
- **Pathfinding.** `Engine::NavGrid` finds routes over a tile grid, and
|
|
48
|
+
`TileWorld#nav_grid` hands one out. `Components::Navigator#go_to` walks a node
|
|
49
|
+
there. The search runs in C, in `Util::SolidGrid`, `Util::RouteSearch` and
|
|
50
|
+
`Util::TileSweep`. See [docs/api/toolbox.md](docs/api/toolbox.md).
|
|
51
|
+
- **`Components::World`** gives a scene its bounds without a tile map.
|
|
52
|
+
`ScreenWrap` and `DespawnOffscreen` read the bounds from it or from
|
|
53
|
+
`TileWorld`. See [docs/api/components.md](docs/api/components.md).
|
|
54
|
+
- **`Components::Hop`** lifts a character's picture off the ground through the
|
|
55
|
+
new `Node2D#elevation`. Colliders and cameras ignore the lift. See
|
|
56
|
+
[docs/api/components.md](docs/api/components.md).
|
|
57
|
+
- **New buttons and styles.** `UI::Button` is the base for a button with its
|
|
58
|
+
own look. `TextButton`, `PanelButton`, `OptionButton` and `IconButton` draw
|
|
59
|
+
their background from a `NineSliceStyle` or a `ShapeStyle`. A `hotkey:` presses
|
|
60
|
+
a button without focusing it. See [docs/api/ui.md](docs/api/ui.md).
|
|
61
|
+
- **Menu layouts and navigations.** `UI::Menu` takes a `layout:` (`Column`,
|
|
62
|
+
`Row` or `Ring`) and a `navigation:` (`Stepping`, `Pointing` or `nil`).
|
|
63
|
+
`UI::RadialMenu` focuses whatever the stick points at. `UI::PanelMenu` draws a
|
|
64
|
+
panel that grows with its buttons. See [docs/api/ui.md](docs/api/ui.md).
|
|
65
|
+
- **Menus open and close.** A menu answers `open?`, `open` and `close`, and
|
|
66
|
+
emits `on_opened` and `on_closed`. A closed menu draws nothing and takes no
|
|
67
|
+
input. `trigger:` names an action that holds a menu open while it is down. See
|
|
68
|
+
[docs/api/ui.md](docs/api/ui.md).
|
|
69
|
+
- **A UI atlas can name images.** A descriptor's `images` section cuts
|
|
70
|
+
rectangles from the sheet, and `Renderer#register_ui_atlas` registers each by
|
|
71
|
+
name. `UI::IconButton.new(image: :home)` then draws one.
|
|
72
|
+
- **Input prompts.** `InputMap#button_for(action, device)` returns the bound
|
|
73
|
+
button that device can press. `Controls.gamepad?` and `Controls.pad_button?`
|
|
74
|
+
tell the two kinds of id apart. See [docs/api/input.md](docs/api/input.md).
|
|
75
|
+
- **Sounds by path.** `audio.play_sound` and `play_music` accept a path and
|
|
76
|
+
load it through the asset manager on first use. `RGame::Game` subscribes an
|
|
77
|
+
`AudioDirector`, so `AudioBus` sounds play without setup. See
|
|
78
|
+
[docs/api/audio.md](docs/api/audio.md).
|
|
79
|
+
- **24 examples, one concept each.** Each is a single `main.rb` that runs on its
|
|
80
|
+
own, from `walk` and `sprite` to `pathfinding` and `localization`. See
|
|
81
|
+
[docs/api/examples.md](docs/api/examples.md).
|
|
82
|
+
- `AssetManager#glob` lists the files under the media root that match a pattern.
|
|
83
|
+
- `Util::Color` gains named colours, from `RED` to `DARK_GRAY`.
|
|
84
|
+
|
|
85
|
+
### Changed
|
|
86
|
+
|
|
87
|
+
- **A subclass may not redefine `Node2D`'s or `Component`'s internal methods.**
|
|
88
|
+
Their private and protected machinery now starts with `_`. A subclass that
|
|
89
|
+
defines one of those names raises `NameError` where the class is defined.
|
|
90
|
+
Before, it silently switched that machinery off. See
|
|
91
|
+
[docs/api/scene_graph.md](docs/api/scene_graph.md).
|
|
92
|
+
- **Nodes draw in local space.** `Node2D#draw` pushes the node's transform
|
|
93
|
+
before it calls `on_draw`, so a node draws at its own origin:
|
|
94
|
+
`renderer.rect(0, 0, width, height)`. Drop `abs_x`/`abs_y` from draw calls, or
|
|
95
|
+
the position applies twice. See
|
|
96
|
+
[docs/api/scene_graph.md](docs/api/scene_graph.md).
|
|
97
|
+
- **`abs_x`, `abs_y` and `abs_angle` are now `world_x`, `world_y` and
|
|
98
|
+
`world_angle`.** A node computes them when read, so they are never a tick
|
|
99
|
+
stale. `world_x=` and `world_y=` place a node in world space. See
|
|
100
|
+
[docs/api/scene_graph.md](docs/api/scene_graph.md).
|
|
101
|
+
- **`UI::Menu` is handed its buttons.** `Menu#add(button)` replaces `add_item`,
|
|
102
|
+
`items` is now `buttons`, and `MenuItem` is now `UI::PanelButton`. The item
|
|
103
|
+
size moves to `layout: UI::Column.new(...)`. Confirm activates a button when
|
|
104
|
+
released. See [docs/api/ui.md](docs/api/ui.md).
|
|
105
|
+
- **`CharacterBody` takes its shape from a sibling collider.**
|
|
106
|
+
`CharacterBody.new(speed:, blocked_by:)` replaces `feet_width:` and
|
|
107
|
+
`feet_height:`. A body with no `blocked_by:` moves freely, and `TileWorld#move`
|
|
108
|
+
is gone. See [docs/api/components.md](docs/api/components.md).
|
|
109
|
+
- **Contacts are edges.** `on_hit` fires once when two colliders start to
|
|
110
|
+
overlap, and the new `on_separated` fires once when they part. Before,
|
|
111
|
+
`on_hit` fired on every step of an overlap.
|
|
112
|
+
- **`I18n` reads YAML tables keyed by locale.** A key falls back from `de-AT`
|
|
113
|
+
to `de` to the default. Plurals follow CLDR rules, and `I18n.missing` decides
|
|
114
|
+
what a missing key shows. `load_file` is gone. See
|
|
115
|
+
[docs/api/localization.md](docs/api/localization.md).
|
|
116
|
+
- **`ScreenWrap` and `DespawnOffscreen` work in world space**, so a node under an
|
|
117
|
+
offset parent wraps at the world's edge. Their `width:` and `height:` are now
|
|
118
|
+
optional. A node with two responses to the edge raises when the second
|
|
119
|
+
attaches.
|
|
120
|
+
- **A component raises when its sibling is missing.** `PlayerController`,
|
|
121
|
+
`WanderController` and `AnimatedSprite` name what they need when they attach.
|
|
122
|
+
A node with two movers raises too.
|
|
123
|
+
- **`AnimatedSprite` follows any mover**, and faces along the larger axis of
|
|
124
|
+
its heading.
|
|
125
|
+
- **Engine internals are private.** `Renderer`'s raw `draw_*`, `push_*`, `pop`
|
|
126
|
+
and `*_record` methods, `Recording#draw_at` and `Song#play_looping` are
|
|
127
|
+
private. Call `rect`, `translated`, `record`, `Recording#draw` and `Song#play`
|
|
128
|
+
instead. The Tiled parse helpers are private too.
|
|
129
|
+
|
|
130
|
+
### Removed
|
|
131
|
+
|
|
132
|
+
- `Engine::CachedLabel`. Use `Engine::Text`.
|
|
133
|
+
- `Engine::Body`, `Engine::Actor`, `Engine::Matrix`, `Engine::Resettable` and
|
|
134
|
+
`Engine::PlayerController`. None had a caller in the engine.
|
|
135
|
+
`Components::PlayerController` stays.
|
|
136
|
+
- `Engine::TileCollision`, which is now `Engine::TileBlockers`.
|
|
137
|
+
- The examples `14_asteroids`, `15_tiled_world` and `16_hello_world`. They are
|
|
138
|
+
whole games rather than examples of one concept, and no longer ship.
|
|
139
|
+
|
|
140
|
+
### Fixed
|
|
141
|
+
|
|
142
|
+
- The README's hello-world gave `on_draw` one parameter; it takes two
|
|
143
|
+
(`renderer, view`).
|
|
144
|
+
- A new `UI::Menu` drew its first item without a highlight until the first
|
|
145
|
+
press.
|
|
146
|
+
- `Path#distance_to` returned wrong distances for Integer coordinates.
|
|
147
|
+
|
|
148
|
+
## [0.2.0] - 2026-08-26
|
|
149
|
+
|
|
150
|
+
### Added
|
|
151
|
+
|
|
152
|
+
- **Split-screen.** A game has seats (`RGame::Game.new(players: 2)`), and a
|
|
153
|
+
`RGame::Engine::Player` owns a device, a binding table, a camera and a region
|
|
154
|
+
of the screen. The shared world is updated once and drawn once per viewport by
|
|
155
|
+
a `WorldView`. Which player a node answers to is inherited down the tree like
|
|
156
|
+
its transform, so `ship.input_owner = players[1]` moves a whole subtree.
|
|
157
|
+
New: `Player`, `Players`, `Viewports`, `View`, `WorldView`, `Layout`.
|
|
158
|
+
- **`RGame::Engine::InputMap`** — one binding table per player, written in terms
|
|
159
|
+
of physical ids from `RGame::Util::Controls`, so a game names keys and pad
|
|
160
|
+
buttons in one place and reads named actions everywhere else.
|
|
161
|
+
- **Draw bands** (`RGame::Util::Z`): `:world`, `:hud`, `:overlay` and `:debug`.
|
|
162
|
+
A band beats every `z` in the tree, so nothing in the world can draw over the
|
|
163
|
+
HUD. Inherited down the tree, and set by the nodes that exist to mark one.
|
|
164
|
+
- **Culling** (`RGame::Engine::Culling`, `view.visible?`), which stops being an
|
|
165
|
+
optimisation once the world is drawn once per player.
|
|
166
|
+
- **A bare-bones UI package**: `PlayerLayer` gives a player their own screen, and
|
|
167
|
+
`UI::Menu` / `UI::MenuItem` navigate it by focus and activation — enough for
|
|
168
|
+
keyboard and controller menus. Layout, nesting, scrolling and text entry are
|
|
169
|
+
not in it; see [docs/api/ui.md](docs/api/ui.md).
|
|
170
|
+
- **Pausing** (`Node2D#paused`), which stops `control` and `update` for a node
|
|
171
|
+
and its whole subtree while it keeps drawing — a frozen world under a cutscene
|
|
172
|
+
overlay that goes on animating.
|
|
173
|
+
- `Components::CameraFollow`, and `TileMapLayer` as a node of its own.
|
|
174
|
+
- **`tools/drive_example.rb`** — boots an example unmodified, feeds it a
|
|
175
|
+
scripted input backend and reports what the game actually asked for: draws,
|
|
176
|
+
clips, sounds, scenes, ticks against frames.
|
|
177
|
+
- **macOS and Windows support**, and CI that runs every verification tier on
|
|
178
|
+
all three platforms.
|
|
179
|
+
- This changelog, linked from the gem's RubyGems page through `changelog_uri`.
|
|
180
|
+
|
|
181
|
+
### Changed
|
|
182
|
+
|
|
183
|
+
- `Node2D#draw` and `on_draw` take the viewport being drawn into:
|
|
184
|
+
`on_draw(renderer, view)`. Most nodes ignore it; laying out against the edges
|
|
185
|
+
of a player's region, and culling, need it.
|
|
186
|
+
- `z` orders a node among its **siblings** only. It is never added to anything
|
|
187
|
+
and never reaches the renderer, so a node's whole subtree draws before or
|
|
188
|
+
after a sibling's, never interleaved with it. This replaces the additive
|
|
189
|
+
`abs_z = parent.abs_z + z`, under which a node at z 2 with a child at z 5
|
|
190
|
+
resolved to 7 and overtook a sibling at 4.
|
|
191
|
+
- `F2` quits and `F1` toggles the debug overlay. `Esc` is deliberately left to
|
|
192
|
+
the game, because it is the button a player expects to back out of a menu.
|
|
193
|
+
- Reading an action no `InputMap` declares raises `KeyError` instead of reading
|
|
194
|
+
as "never pressed" forever.
|
|
195
|
+
|
|
196
|
+
### Removed
|
|
197
|
+
|
|
198
|
+
- `RGame::Engine::CameraView`. A camera belongs to a `Player` and is applied by
|
|
199
|
+
the `View` being drawn.
|
|
200
|
+
|
|
201
|
+
## [0.1.0] - 2026-08-20
|
|
202
|
+
|
|
203
|
+
First release, and the first version that runs a game end to end.
|
|
204
|
+
|
|
205
|
+
### Added
|
|
206
|
+
|
|
207
|
+
- **The C engine**, as two Ruby extensions built from one source tree: an SDL2
|
|
208
|
+
window and a fixed-timestep main loop, keyboard and gamepad input with
|
|
209
|
+
hot-plug, a z-sorted batching renderer with transforms, clipping and baked
|
|
210
|
+
recordings, text from a shipped TrueType font, and audio (samples and
|
|
211
|
+
streamed Ogg Vorbis or WAV).
|
|
212
|
+
- **`RGame::Core`** — the half that owns the window, the GPU and the sound
|
|
213
|
+
device: `App`, `Input`, `Gamepad`, `Image`, `Renderer`, `Recording`, `Font`,
|
|
214
|
+
`Audio`, plus the asset layer (`AssetManager`, `SpriteSheet`, `NineSlice`,
|
|
215
|
+
`UIAtlas`, `TileMapRenderer`).
|
|
216
|
+
- **`RGame::Util`** — the graphics-free half, so values can be required with no
|
|
217
|
+
SDL and no OpenGL in the process: `Tensor`, `Color`, `Controls`.
|
|
218
|
+
- **`RGame::Engine`** — the scene graph a game is written in: nodes,
|
|
219
|
+
components, signals, sprites, tile maps, collision and pathfinding. Pure
|
|
220
|
+
Ruby, and unable to name `RGame::Core` at all, which is what lets game logic
|
|
221
|
+
and its specs run with no display.
|
|
222
|
+
- **`RGame::Game`** — the entry point that wires the two halves together.
|
|
223
|
+
- Examples: `14_asteroids`, `15_tiled_world`, `16_hello_world`.
|
|
224
|
+
|
|
225
|
+
[Unreleased]: https://github.com/psuessenb/rgame/compare/v0.3.0...HEAD
|
|
226
|
+
[0.3.0]: https://github.com/psuessenb/rgame/compare/v0.2.0...v0.3.0
|
|
227
|
+
[0.2.0]: https://github.com/psuessenb/rgame/compare/v0.1.0...v0.2.0
|
|
228
|
+
[0.1.0]: https://github.com/psuessenb/rgame/releases/tag/v0.1.0
|