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.
Files changed (265) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +228 -0
  3. data/README.md +142 -243
  4. data/docs/api/README.md +141 -90
  5. data/docs/api/app.md +125 -68
  6. data/docs/api/assets.md +203 -166
  7. data/docs/api/audio.md +130 -89
  8. data/docs/api/cli.md +259 -0
  9. data/docs/api/components.md +1045 -254
  10. data/docs/api/drawing.md +187 -119
  11. data/docs/api/examples.md +263 -0
  12. data/docs/api/game.md +165 -45
  13. data/docs/api/images.md +39 -39
  14. data/docs/api/input.md +344 -85
  15. data/docs/api/internals.md +241 -62
  16. data/docs/api/localization.md +285 -0
  17. data/docs/api/scene_graph.md +503 -123
  18. data/docs/api/signals.md +81 -76
  19. data/docs/api/systems.md +197 -64
  20. data/docs/api/text.md +58 -41
  21. data/docs/api/tile_maps.md +237 -0
  22. data/docs/api/toolbox.md +400 -147
  23. data/docs/api/ui.md +927 -0
  24. data/docs/api/values.md +234 -19
  25. data/examples/assets/README.md +322 -0
  26. data/examples/assets/blip.ogg +0 -0
  27. data/examples/assets/glyphs.json +5 -0
  28. data/examples/assets/glyphs.png +0 -0
  29. data/examples/assets/hero.json +12 -0
  30. data/examples/assets/hero.png +0 -0
  31. data/examples/assets/icons.json +13 -0
  32. data/examples/assets/icons.png +0 -0
  33. data/examples/assets/music.ogg +0 -0
  34. data/examples/assets/skills.json +10 -0
  35. data/examples/assets/skills.png +0 -0
  36. data/examples/assets/tileset.png +0 -0
  37. data/examples/assets/tileset.tsx +65 -0
  38. data/examples/assets/town.tmx +26 -0
  39. data/examples/assets/ui.json +11 -0
  40. data/examples/assets/ui.png +0 -0
  41. data/examples/collision/locales/en.yml +8 -0
  42. data/examples/collision/main.rb +316 -0
  43. data/examples/collision_tiles/locales/en.yml +9 -0
  44. data/examples/collision_tiles/main.rb +274 -0
  45. data/examples/fullscreen/locales/en.yml +10 -0
  46. data/examples/fullscreen/main.rb +216 -0
  47. data/examples/game_menu/locales/en.yml +8 -0
  48. data/examples/game_menu/main.rb +170 -0
  49. data/examples/input_glyphs/locales/en.yml +14 -0
  50. data/examples/input_glyphs/main.rb +213 -0
  51. data/examples/jump_topdown/locales/en.yml +9 -0
  52. data/examples/jump_topdown/main.rb +178 -0
  53. data/examples/localization/locales/de.yml +12 -0
  54. data/examples/localization/locales/en.yml +13 -0
  55. data/examples/localization/main.rb +158 -0
  56. data/examples/menu_navigation/locales/en.yml +23 -0
  57. data/examples/menu_navigation/main.rb +365 -0
  58. data/examples/music/locales/en.yml +7 -0
  59. data/examples/music/main.rb +134 -0
  60. data/examples/pathfinding/locales/en.yml +17 -0
  61. data/examples/pathfinding/main.rb +298 -0
  62. data/examples/pooling/locales/en.yml +7 -0
  63. data/examples/pooling/main.rb +259 -0
  64. data/examples/quick_wheel/locales/en.yml +16 -0
  65. data/examples/quick_wheel/main.rb +184 -0
  66. data/examples/radial_menu/locales/en.yml +16 -0
  67. data/examples/radial_menu/main.rb +184 -0
  68. data/examples/save_load/locales/en.yml +11 -0
  69. data/examples/save_load/main.rb +207 -0
  70. data/examples/save_load_ids/locales/en.yml +11 -0
  71. data/examples/save_load_ids/main.rb +322 -0
  72. data/examples/scroll_map/locales/en.yml +4 -0
  73. data/examples/scroll_map/main.rb +140 -0
  74. data/examples/signals/locales/en.yml +6 -0
  75. data/examples/signals/main.rb +278 -0
  76. data/examples/skill_bar/locales/en.yml +14 -0
  77. data/examples/skill_bar/main.rb +159 -0
  78. data/examples/sound/locales/en.yml +6 -0
  79. data/examples/sound/main.rb +122 -0
  80. data/examples/split_screen/locales/en.yml +9 -0
  81. data/examples/split_screen/main.rb +304 -0
  82. data/examples/sprite/locales/en.yml +8 -0
  83. data/examples/sprite/main.rb +180 -0
  84. data/examples/timer/locales/en.yml +12 -0
  85. data/examples/timer/main.rb +273 -0
  86. data/examples/velocity/locales/en.yml +6 -0
  87. data/examples/velocity/main.rb +196 -0
  88. data/examples/walk/locales/en.yml +4 -0
  89. data/examples/walk/main.rb +99 -0
  90. data/exe/rgame +9 -0
  91. data/ext/README.md +6 -5
  92. data/ext/rgame_core/app/app.c +215 -11
  93. data/ext/rgame_core/app/locale.c +67 -0
  94. data/ext/rgame_core/app/locale.h +28 -0
  95. data/ext/rgame_core/audio/audio.c +113 -2
  96. data/ext/rgame_core/example.rb +18 -56
  97. data/ext/rgame_core/extconf.rb +16 -113
  98. data/ext/rgame_core/graphics/canvas.c +45 -4
  99. data/ext/rgame_core/graphics/canvas.h +65 -10
  100. data/ext/rgame_core/graphics/clip.c +22 -13
  101. data/ext/rgame_core/include/rgame/core.h +151 -5
  102. data/ext/rgame_core/input/gamepad.c +57 -3
  103. data/ext/rgame_core/ruby/audio_ext.c +10 -5
  104. data/ext/rgame_core/ruby/core_ext.c +46 -7
  105. data/ext/rgame_core/ruby/core_ext.h +3 -0
  106. data/ext/rgame_core/ruby/locale_ext.c +44 -0
  107. data/ext/rgame_core/ruby/recording_ext.c +1 -1
  108. data/ext/rgame_core/ruby/renderer_ext.c +42 -19
  109. data/ext/rgame_util/color_ext.c +12 -3
  110. data/ext/rgame_util/extconf.rb +2 -20
  111. data/ext/rgame_util/route_search.c +305 -0
  112. data/ext/rgame_util/route_search.h +86 -0
  113. data/ext/rgame_util/route_search_ext.c +150 -0
  114. data/ext/rgame_util/solid_grid.c +58 -0
  115. data/ext/rgame_util/solid_grid.h +49 -0
  116. data/ext/rgame_util/solid_grid_ext.c +161 -0
  117. data/ext/rgame_util/tile_sweep.c +164 -0
  118. data/ext/rgame_util/tile_sweep.h +62 -0
  119. data/ext/rgame_util/tile_sweep_ext.c +155 -0
  120. data/ext/rgame_util/util_ext.c +3 -0
  121. data/ext/rgame_util/util_ext.h +15 -0
  122. data/lib/rgame/boot.rb +0 -10
  123. data/lib/rgame/cli/new_project.rb +139 -0
  124. data/lib/rgame/cli/templates/Gemfile.tt +23 -0
  125. data/lib/rgame/cli/templates/README.md.tt +93 -0
  126. data/lib/rgame/cli/templates/Rakefile.tt +9 -0
  127. data/lib/rgame/cli/templates/assets/locales/en.yml.tt +10 -0
  128. data/lib/rgame/cli/templates/game.rb.tt +23 -0
  129. data/lib/rgame/cli/templates/gitignore.tt +12 -0
  130. data/lib/rgame/cli/templates/main.rb.tt +11 -0
  131. data/lib/rgame/cli/templates/nodes/root.rb.tt +24 -0
  132. data/lib/rgame/cli/templates/rspec.tt +2 -0
  133. data/lib/rgame/cli/templates/rubocop.yml.tt +75 -0
  134. data/lib/rgame/cli/templates/ruby-version.tt +1 -0
  135. data/lib/rgame/cli/templates/spec/locales_spec.rb.tt +18 -0
  136. data/lib/rgame/cli/templates/spec/nodes/root_spec.rb.tt +18 -0
  137. data/lib/rgame/cli/templates/spec/spec_helper.rb.tt +37 -0
  138. data/lib/rgame/cli.rb +66 -0
  139. data/lib/rgame/core/app.rb +6 -42
  140. data/lib/rgame/core/asset_manager.rb +13 -31
  141. data/lib/rgame/core/audio.rb +37 -16
  142. data/lib/rgame/core/font.rb +0 -3
  143. data/lib/rgame/core/input.rb +35 -41
  144. data/lib/rgame/core/locale.rb +22 -0
  145. data/lib/rgame/core/nine_slice.rb +0 -21
  146. data/lib/rgame/core/recording.rb +3 -1
  147. data/lib/rgame/core/renderer.rb +75 -84
  148. data/lib/rgame/core/sprite_sheet.rb +0 -3
  149. data/lib/rgame/core/tile_map_renderer.rb +77 -65
  150. data/lib/rgame/core/ui_atlas.rb +28 -13
  151. data/lib/rgame/core.rb +1 -8
  152. data/lib/rgame/engine/actor_blockers.rb +131 -0
  153. data/lib/rgame/engine/animation_set.rb +1 -0
  154. data/lib/rgame/engine/audio_director.rb +36 -6
  155. data/lib/rgame/engine/bounds_blockers.rb +74 -0
  156. data/lib/rgame/engine/camera.rb +55 -10
  157. data/lib/rgame/engine/circle_collider.rb +4 -2
  158. data/lib/rgame/engine/collision_box.rb +26 -1
  159. data/lib/rgame/engine/collision_system.rb +110 -22
  160. data/lib/rgame/engine/component.rb +35 -1
  161. data/lib/rgame/engine/components/action_trigger.rb +0 -1
  162. data/lib/rgame/engine/components/animated_sprite.rb +31 -23
  163. data/lib/rgame/engine/components/box_collider.rb +99 -0
  164. data/lib/rgame/engine/components/camera_follow.rb +45 -0
  165. data/lib/rgame/engine/components/character_body.rb +21 -41
  166. data/lib/rgame/engine/components/circle_collider.rb +47 -11
  167. data/lib/rgame/engine/components/collision_world.rb +159 -31
  168. data/lib/rgame/engine/components/despawn_offscreen.rb +24 -8
  169. data/lib/rgame/engine/components/feet_collider.rb +61 -0
  170. data/lib/rgame/engine/components/hop.rb +76 -0
  171. data/lib/rgame/engine/components/identity.rb +73 -0
  172. data/lib/rgame/engine/components/mover.rb +285 -0
  173. data/lib/rgame/engine/components/navigator.rb +145 -0
  174. data/lib/rgame/engine/components/path_follow.rb +123 -31
  175. data/lib/rgame/engine/components/player_controller.rb +5 -2
  176. data/lib/rgame/engine/components/pool.rb +1 -1
  177. data/lib/rgame/engine/components/screen_wrap.rb +33 -11
  178. data/lib/rgame/engine/components/sprite.rb +22 -6
  179. data/lib/rgame/engine/components/targeting.rb +9 -11
  180. data/lib/rgame/engine/components/thrust_controller.rb +1 -1
  181. data/lib/rgame/engine/components/tile_world.rb +70 -29
  182. data/lib/rgame/engine/components/timer.rb +1 -1
  183. data/lib/rgame/engine/components/velocity.rb +23 -7
  184. data/lib/rgame/engine/components/wander_controller.rb +6 -2
  185. data/lib/rgame/engine/components/world.rb +133 -0
  186. data/lib/rgame/engine/contact_set.rb +74 -0
  187. data/lib/rgame/engine/culling.rb +45 -0
  188. data/lib/rgame/engine/debug_overlay.rb +23 -18
  189. data/lib/rgame/engine/i18n/plural.rb +45 -0
  190. data/lib/rgame/engine/i18n/plural_rules.rb +82 -0
  191. data/lib/rgame/engine/i18n/template.rb +59 -0
  192. data/lib/rgame/engine/i18n.rb +276 -51
  193. data/lib/rgame/engine/input/action_mapper.rb +76 -22
  194. data/lib/rgame/engine/input/actions.rb +63 -12
  195. data/lib/rgame/engine/input/input_map.rb +196 -0
  196. data/lib/rgame/engine/layout.rb +82 -0
  197. data/lib/rgame/engine/nav_grid.rb +87 -0
  198. data/lib/rgame/engine/node2d.rb +364 -80
  199. data/lib/rgame/engine/path.rb +4 -6
  200. data/lib/rgame/engine/player.rb +69 -0
  201. data/lib/rgame/engine/player_layer.rb +70 -0
  202. data/lib/rgame/engine/players.rb +205 -0
  203. data/lib/rgame/engine/presentation.rb +171 -0
  204. data/lib/rgame/engine/scene/scene_stack.rb +29 -7
  205. data/lib/rgame/engine/sealed_privates.rb +54 -0
  206. data/lib/rgame/engine/spatial_hash.rb +53 -8
  207. data/lib/rgame/engine/text.rb +194 -0
  208. data/lib/rgame/engine/tile_blockers.rb +63 -0
  209. data/lib/rgame/engine/tile_map.rb +2 -3
  210. data/lib/rgame/engine/tile_map_layer.rb +82 -0
  211. data/lib/rgame/engine/tileset.rb +2 -4
  212. data/lib/rgame/engine/timer.rb +2 -2
  213. data/lib/rgame/engine/ui/button.rb +248 -0
  214. data/lib/rgame/engine/ui/column.rb +20 -0
  215. data/lib/rgame/engine/ui/icon_button.rb +93 -0
  216. data/lib/rgame/engine/ui/menu.rb +290 -0
  217. data/lib/rgame/engine/ui/navigation.rb +57 -0
  218. data/lib/rgame/engine/ui/nine_slice_style.rb +50 -0
  219. data/lib/rgame/engine/ui/option_button.rb +163 -0
  220. data/lib/rgame/engine/ui/panel_button.rb +32 -0
  221. data/lib/rgame/engine/ui/panel_menu.rb +36 -0
  222. data/lib/rgame/engine/ui/pointing.rb +146 -0
  223. data/lib/rgame/engine/ui/radial_menu.rb +85 -0
  224. data/lib/rgame/engine/ui/ring.rb +55 -0
  225. data/lib/rgame/engine/ui/row.rb +21 -0
  226. data/lib/rgame/engine/ui/shape_style.rb +102 -0
  227. data/lib/rgame/engine/ui/stack.rb +58 -0
  228. data/lib/rgame/engine/ui/stepping.rb +93 -0
  229. data/lib/rgame/engine/ui/text_button.rb +59 -0
  230. data/lib/rgame/engine/view.rb +76 -0
  231. data/lib/rgame/engine/viewports.rb +171 -0
  232. data/lib/rgame/engine/world_view.rb +71 -0
  233. data/lib/rgame/engine.rb +43 -25
  234. data/lib/rgame/game.rb +164 -22
  235. data/lib/rgame/rubocop/cop/game/draw_in_local_space.rb +103 -0
  236. data/lib/rgame/rubocop/cop/game/hot_path.rb +36 -0
  237. data/lib/rgame/rubocop/cop/game/layer_boundary.rb +43 -0
  238. data/lib/rgame/rubocop/cop/game/no_core_in_engine_layer.rb +100 -0
  239. data/lib/rgame/rubocop/cop/game/no_engine_in_core_layer.rb +84 -0
  240. data/lib/rgame/rubocop/cop/game/no_interpolation_in_hot_path.rb +50 -0
  241. data/lib/rgame/rubocop/cop/game/no_literal_text.rb +41 -0
  242. data/lib/rgame/rubocop/cop/game/no_needless_allocation.rb +112 -0
  243. data/lib/rgame/rubocop/default.yml +39 -0
  244. data/lib/rgame/rubocop/plugin.rb +45 -0
  245. data/lib/rgame/rubocop.rb +11 -0
  246. data/lib/rgame/util/color.rb +20 -24
  247. data/lib/rgame/util/controls.rb +106 -44
  248. data/lib/rgame/util/route_search.rb +27 -0
  249. data/lib/rgame/util/save_file.rb +107 -0
  250. data/lib/rgame/util/solid_grid.rb +37 -0
  251. data/lib/rgame/util/tensor.rb +0 -9
  252. data/lib/rgame/util/tile_sweep.rb +36 -0
  253. data/lib/rgame/util/z.rb +123 -0
  254. data/lib/rgame/util.rb +5 -3
  255. data/lib/rgame/version.rb +1 -1
  256. data/lib/rgame.rb +0 -15
  257. metadata +176 -20
  258. data/lib/rgame/engine/actor.rb +0 -53
  259. data/lib/rgame/engine/body.rb +0 -49
  260. data/lib/rgame/engine/cached_label.rb +0 -33
  261. data/lib/rgame/engine/camera_view.rb +0 -28
  262. data/lib/rgame/engine/input/player_controller.rb +0 -14
  263. data/lib/rgame/engine/matrix.rb +0 -32
  264. data/lib/rgame/engine/resettable.rb +0 -67
  265. data/lib/rgame/engine/tile_collision.rb +0 -78
metadata CHANGED
@@ -1,56 +1,130 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rgame
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Paul Süßenbach
8
- bindir: bin
8
+ bindir: exe
9
9
  cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies: []
12
12
  description: |
13
- rgame is a 2D game engine written in C on top of SDL2 and OpenGL and exposed
14
- to Ruby as C extensions. It opens a window, runs a fixed-timestep main loop,
15
- reads keyboard and controllers, loads PNGs onto the GPU and draws shapes and
16
- sprites through a z-sorted batching renderer.
13
+ RGame is a small 2D game engine for Ruby, written in Ruby and C. It's build
14
+ on top of SDL2, OpenGL and miniaudio. It's built with testability and
15
+ performance in mind, and aims to be an engine where you can write your whole
16
+ game code in Ruby, test it as usual with RSpec (or Minitest, or another test
17
+ framework) and still have acceptable performance.
17
18
 
18
- Everything Ruby-visible lives under the RGame module, split in two by what it
19
- depends on. RGame::Core owns the window, the GPU and the OS handles;
20
- RGame::Util holds the shareable value types and links no graphics libraries
21
- at all, so `require "rgame"` gives you the pure half with no SDL or OpenGL in
22
- the process and pure-logic code stays testable with no display.
19
+ While still a work in progress, RGame aims to be more than a SDL/OpenGL
20
+ binding - it ships with high level features like a scene graph, sprites,
21
+ collision systems, debugging tools and an UI toolkit.
23
22
  email:
24
23
  - 2452696+psuessenb@users.noreply.github.com
25
- executables: []
24
+ executables:
25
+ - rgame
26
26
  extensions:
27
27
  - ext/rgame_core/extconf.rb
28
28
  - ext/rgame_util/extconf.rb
29
29
  extra_rdoc_files: []
30
30
  files:
31
+ - CHANGELOG.md
31
32
  - LICENSE
32
33
  - README.md
33
34
  - docs/api/README.md
34
35
  - docs/api/app.md
35
36
  - docs/api/assets.md
36
37
  - docs/api/audio.md
38
+ - docs/api/cli.md
37
39
  - docs/api/components.md
38
40
  - docs/api/drawing.md
41
+ - docs/api/examples.md
39
42
  - docs/api/game.md
40
43
  - docs/api/images.md
41
44
  - docs/api/input.md
42
45
  - docs/api/internals.md
46
+ - docs/api/localization.md
43
47
  - docs/api/scene_graph.md
44
48
  - docs/api/signals.md
45
49
  - docs/api/systems.md
46
50
  - docs/api/text.md
51
+ - docs/api/tile_maps.md
47
52
  - docs/api/toolbox.md
53
+ - docs/api/ui.md
48
54
  - docs/api/values.md
55
+ - examples/assets/README.md
56
+ - examples/assets/blip.ogg
57
+ - examples/assets/glyphs.json
58
+ - examples/assets/glyphs.png
59
+ - examples/assets/hero.json
60
+ - examples/assets/hero.png
61
+ - examples/assets/icons.json
62
+ - examples/assets/icons.png
63
+ - examples/assets/music.ogg
64
+ - examples/assets/skills.json
65
+ - examples/assets/skills.png
66
+ - examples/assets/tileset.png
67
+ - examples/assets/tileset.tsx
68
+ - examples/assets/town.tmx
69
+ - examples/assets/ui.json
70
+ - examples/assets/ui.png
71
+ - examples/collision/locales/en.yml
72
+ - examples/collision/main.rb
73
+ - examples/collision_tiles/locales/en.yml
74
+ - examples/collision_tiles/main.rb
75
+ - examples/fullscreen/locales/en.yml
76
+ - examples/fullscreen/main.rb
77
+ - examples/game_menu/locales/en.yml
78
+ - examples/game_menu/main.rb
79
+ - examples/input_glyphs/locales/en.yml
80
+ - examples/input_glyphs/main.rb
81
+ - examples/jump_topdown/locales/en.yml
82
+ - examples/jump_topdown/main.rb
83
+ - examples/localization/locales/de.yml
84
+ - examples/localization/locales/en.yml
85
+ - examples/localization/main.rb
86
+ - examples/menu_navigation/locales/en.yml
87
+ - examples/menu_navigation/main.rb
88
+ - examples/music/locales/en.yml
89
+ - examples/music/main.rb
90
+ - examples/pathfinding/locales/en.yml
91
+ - examples/pathfinding/main.rb
92
+ - examples/pooling/locales/en.yml
93
+ - examples/pooling/main.rb
94
+ - examples/quick_wheel/locales/en.yml
95
+ - examples/quick_wheel/main.rb
96
+ - examples/radial_menu/locales/en.yml
97
+ - examples/radial_menu/main.rb
98
+ - examples/save_load/locales/en.yml
99
+ - examples/save_load/main.rb
100
+ - examples/save_load_ids/locales/en.yml
101
+ - examples/save_load_ids/main.rb
102
+ - examples/scroll_map/locales/en.yml
103
+ - examples/scroll_map/main.rb
104
+ - examples/signals/locales/en.yml
105
+ - examples/signals/main.rb
106
+ - examples/skill_bar/locales/en.yml
107
+ - examples/skill_bar/main.rb
108
+ - examples/sound/locales/en.yml
109
+ - examples/sound/main.rb
110
+ - examples/split_screen/locales/en.yml
111
+ - examples/split_screen/main.rb
112
+ - examples/sprite/locales/en.yml
113
+ - examples/sprite/main.rb
114
+ - examples/timer/locales/en.yml
115
+ - examples/timer/main.rb
116
+ - examples/velocity/locales/en.yml
117
+ - examples/velocity/main.rb
118
+ - examples/walk/locales/en.yml
119
+ - examples/walk/main.rb
120
+ - exe/rgame
49
121
  - ext/README.md
50
122
  - ext/rgame_core/app/app.c
51
123
  - ext/rgame_core/app/app_gl.h
52
124
  - ext/rgame_core/app/frame_loop.c
53
125
  - ext/rgame_core/app/frame_loop.h
126
+ - ext/rgame_core/app/locale.c
127
+ - ext/rgame_core/app/locale.h
54
128
  - ext/rgame_core/audio/audio.c
55
129
  - ext/rgame_core/audio/audio_internal.h
56
130
  - ext/rgame_core/audio/vorbis_decoder.c
@@ -89,6 +163,7 @@ files:
89
163
  - ext/rgame_core/ruby/core_ext.h
90
164
  - ext/rgame_core/ruby/font_ext.c
91
165
  - ext/rgame_core/ruby/image_ext.c
166
+ - ext/rgame_core/ruby/locale_ext.c
92
167
  - ext/rgame_core/ruby/recording_ext.c
93
168
  - ext/rgame_core/ruby/renderer_ext.c
94
169
  - ext/rgame_core/text/atlas.c
@@ -112,11 +187,36 @@ files:
112
187
  - ext/rgame_util/color.h
113
188
  - ext/rgame_util/color_ext.c
114
189
  - ext/rgame_util/extconf.rb
190
+ - ext/rgame_util/route_search.c
191
+ - ext/rgame_util/route_search.h
192
+ - ext/rgame_util/route_search_ext.c
193
+ - ext/rgame_util/solid_grid.c
194
+ - ext/rgame_util/solid_grid.h
195
+ - ext/rgame_util/solid_grid_ext.c
115
196
  - ext/rgame_util/tensor.c
197
+ - ext/rgame_util/tile_sweep.c
198
+ - ext/rgame_util/tile_sweep.h
199
+ - ext/rgame_util/tile_sweep_ext.c
116
200
  - ext/rgame_util/util_ext.c
117
201
  - ext/rgame_util/util_ext.h
118
202
  - lib/rgame.rb
119
203
  - lib/rgame/boot.rb
204
+ - lib/rgame/cli.rb
205
+ - lib/rgame/cli/new_project.rb
206
+ - lib/rgame/cli/templates/Gemfile.tt
207
+ - lib/rgame/cli/templates/README.md.tt
208
+ - lib/rgame/cli/templates/Rakefile.tt
209
+ - lib/rgame/cli/templates/assets/locales/en.yml.tt
210
+ - lib/rgame/cli/templates/game.rb.tt
211
+ - lib/rgame/cli/templates/gitignore.tt
212
+ - lib/rgame/cli/templates/main.rb.tt
213
+ - lib/rgame/cli/templates/nodes/root.rb.tt
214
+ - lib/rgame/cli/templates/rspec.tt
215
+ - lib/rgame/cli/templates/rubocop.yml.tt
216
+ - lib/rgame/cli/templates/ruby-version.tt
217
+ - lib/rgame/cli/templates/spec/locales_spec.rb.tt
218
+ - lib/rgame/cli/templates/spec/nodes/root_spec.rb.tt
219
+ - lib/rgame/cli/templates/spec/spec_helper.rb.tt
120
220
  - lib/rgame/core.rb
121
221
  - lib/rgame/core/app.rb
122
222
  - lib/rgame/core/asset_manager.rb
@@ -125,6 +225,7 @@ files:
125
225
  - lib/rgame/core/gamepad.rb
126
226
  - lib/rgame/core/image.rb
127
227
  - lib/rgame/core/input.rb
228
+ - lib/rgame/core/locale.rb
128
229
  - lib/rgame/core/nine_slice.rb
129
230
  - lib/rgame/core/recording.rb
130
231
  - lib/rgame/core/renderer.rb
@@ -132,25 +233,30 @@ files:
132
233
  - lib/rgame/core/tile_map_renderer.rb
133
234
  - lib/rgame/core/ui_atlas.rb
134
235
  - lib/rgame/engine.rb
135
- - lib/rgame/engine/actor.rb
236
+ - lib/rgame/engine/actor_blockers.rb
136
237
  - lib/rgame/engine/animation_set.rb
137
238
  - lib/rgame/engine/animator.rb
138
239
  - lib/rgame/engine/audio_bus.rb
139
240
  - lib/rgame/engine/audio_director.rb
140
- - lib/rgame/engine/body.rb
141
- - lib/rgame/engine/cached_label.rb
241
+ - lib/rgame/engine/bounds_blockers.rb
142
242
  - lib/rgame/engine/camera.rb
143
- - lib/rgame/engine/camera_view.rb
144
243
  - lib/rgame/engine/circle_collider.rb
145
244
  - lib/rgame/engine/collision_box.rb
146
245
  - lib/rgame/engine/collision_system.rb
147
246
  - lib/rgame/engine/component.rb
148
247
  - lib/rgame/engine/components/action_trigger.rb
149
248
  - lib/rgame/engine/components/animated_sprite.rb
249
+ - lib/rgame/engine/components/box_collider.rb
250
+ - lib/rgame/engine/components/camera_follow.rb
150
251
  - lib/rgame/engine/components/character_body.rb
151
252
  - lib/rgame/engine/components/circle_collider.rb
152
253
  - lib/rgame/engine/components/collision_world.rb
153
254
  - lib/rgame/engine/components/despawn_offscreen.rb
255
+ - lib/rgame/engine/components/feet_collider.rb
256
+ - lib/rgame/engine/components/hop.rb
257
+ - lib/rgame/engine/components/identity.rb
258
+ - lib/rgame/engine/components/mover.rb
259
+ - lib/rgame/engine/components/navigator.rb
154
260
  - lib/rgame/engine/components/path_follow.rb
155
261
  - lib/rgame/engine/components/player_controller.rb
156
262
  - lib/rgame/engine/components/pool.rb
@@ -162,30 +268,79 @@ files:
162
268
  - lib/rgame/engine/components/timer.rb
163
269
  - lib/rgame/engine/components/velocity.rb
164
270
  - lib/rgame/engine/components/wander_controller.rb
271
+ - lib/rgame/engine/components/world.rb
272
+ - lib/rgame/engine/contact_set.rb
273
+ - lib/rgame/engine/culling.rb
165
274
  - lib/rgame/engine/debug_overlay.rb
166
275
  - lib/rgame/engine/i18n.rb
276
+ - lib/rgame/engine/i18n/plural.rb
277
+ - lib/rgame/engine/i18n/plural_rules.rb
278
+ - lib/rgame/engine/i18n/template.rb
167
279
  - lib/rgame/engine/input/action_mapper.rb
168
280
  - lib/rgame/engine/input/actions.rb
169
- - lib/rgame/engine/input/player_controller.rb
170
- - lib/rgame/engine/matrix.rb
281
+ - lib/rgame/engine/input/input_map.rb
282
+ - lib/rgame/engine/layout.rb
283
+ - lib/rgame/engine/nav_grid.rb
171
284
  - lib/rgame/engine/node2d.rb
172
285
  - lib/rgame/engine/path.rb
286
+ - lib/rgame/engine/player.rb
287
+ - lib/rgame/engine/player_layer.rb
288
+ - lib/rgame/engine/players.rb
173
289
  - lib/rgame/engine/pool.rb
174
- - lib/rgame/engine/resettable.rb
290
+ - lib/rgame/engine/presentation.rb
175
291
  - lib/rgame/engine/scene/scene_stack.rb
292
+ - lib/rgame/engine/sealed_privates.rb
176
293
  - lib/rgame/engine/signal.rb
177
294
  - lib/rgame/engine/spatial_hash.rb
178
- - lib/rgame/engine/tile_collision.rb
295
+ - lib/rgame/engine/text.rb
296
+ - lib/rgame/engine/tile_blockers.rb
179
297
  - lib/rgame/engine/tile_map.rb
298
+ - lib/rgame/engine/tile_map_layer.rb
180
299
  - lib/rgame/engine/tileset.rb
181
300
  - lib/rgame/engine/timer.rb
301
+ - lib/rgame/engine/ui/button.rb
302
+ - lib/rgame/engine/ui/column.rb
303
+ - lib/rgame/engine/ui/icon_button.rb
304
+ - lib/rgame/engine/ui/menu.rb
305
+ - lib/rgame/engine/ui/navigation.rb
306
+ - lib/rgame/engine/ui/nine_slice_style.rb
307
+ - lib/rgame/engine/ui/option_button.rb
308
+ - lib/rgame/engine/ui/panel_button.rb
309
+ - lib/rgame/engine/ui/panel_menu.rb
310
+ - lib/rgame/engine/ui/pointing.rb
311
+ - lib/rgame/engine/ui/radial_menu.rb
312
+ - lib/rgame/engine/ui/ring.rb
313
+ - lib/rgame/engine/ui/row.rb
314
+ - lib/rgame/engine/ui/shape_style.rb
315
+ - lib/rgame/engine/ui/stack.rb
316
+ - lib/rgame/engine/ui/stepping.rb
317
+ - lib/rgame/engine/ui/text_button.rb
318
+ - lib/rgame/engine/view.rb
319
+ - lib/rgame/engine/viewports.rb
320
+ - lib/rgame/engine/world_view.rb
182
321
  - lib/rgame/fonts/LiberationSans-Regular.ttf
183
322
  - lib/rgame/fonts/OFL.txt
184
323
  - lib/rgame/game.rb
324
+ - lib/rgame/rubocop.rb
325
+ - lib/rgame/rubocop/cop/game/draw_in_local_space.rb
326
+ - lib/rgame/rubocop/cop/game/hot_path.rb
327
+ - lib/rgame/rubocop/cop/game/layer_boundary.rb
328
+ - lib/rgame/rubocop/cop/game/no_core_in_engine_layer.rb
329
+ - lib/rgame/rubocop/cop/game/no_engine_in_core_layer.rb
330
+ - lib/rgame/rubocop/cop/game/no_interpolation_in_hot_path.rb
331
+ - lib/rgame/rubocop/cop/game/no_literal_text.rb
332
+ - lib/rgame/rubocop/cop/game/no_needless_allocation.rb
333
+ - lib/rgame/rubocop/default.yml
334
+ - lib/rgame/rubocop/plugin.rb
185
335
  - lib/rgame/util.rb
186
336
  - lib/rgame/util/color.rb
187
337
  - lib/rgame/util/controls.rb
338
+ - lib/rgame/util/route_search.rb
339
+ - lib/rgame/util/save_file.rb
340
+ - lib/rgame/util/solid_grid.rb
188
341
  - lib/rgame/util/tensor.rb
342
+ - lib/rgame/util/tile_sweep.rb
343
+ - lib/rgame/util/z.rb
189
344
  - lib/rgame/version.rb
190
345
  homepage: https://github.com/psuessenb/rgame
191
346
  licenses:
@@ -194,6 +349,7 @@ metadata:
194
349
  source_code_uri: https://github.com/psuessenb/rgame
195
350
  bug_tracker_uri: https://github.com/psuessenb/rgame/issues
196
351
  documentation_uri: https://github.com/psuessenb/rgame/blob/main/docs/api/README.md
352
+ changelog_uri: https://github.com/psuessenb/rgame/blob/main/CHANGELOG.md
197
353
  rubygems_mfa_required: 'true'
198
354
  rdoc_options: []
199
355
  require_paths:
@@ -1,53 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RGame
4
- module Engine
5
- # A character in the world. Composes the pieces it owns — a collision box, an
6
- # animator, a sprite id (the renderer maps it to a sheet), and a controller that
7
- # decides movement — rather than baking them in. Pure logic; no graphics.
8
- #
9
- # The controller responds to `intent(dt, input) -> [ix, iy]` with each axis in
10
- # [-1, 1]; PlayerController reads input, AI/scripted controllers ignore it.
11
- class Actor
12
- attr_accessor :x, :y
13
- attr_reader :sprite_id, :collision_box, :animator
14
-
15
- def initialize(x:, y:, sprite_id:, collision_box:, animator:, controller:, speed: 120.0)
16
- @x = x
17
- @y = y
18
- @sprite_id = sprite_id
19
- @collision_box = collision_box
20
- @animator = animator
21
- @controller = controller
22
- @speed = speed
23
- end
24
-
25
- def update(dt, collision_system, input)
26
- intent_x, intent_y = @controller.intent(dt, input)
27
-
28
- collision_system.move(self, intent_x * @speed * dt, intent_y * @speed * dt)
29
-
30
- @animator.play(walk_animation(intent_x, intent_y))
31
- @animator.update(dt)
32
- end
33
-
34
- # [row, col, flip_x] for the current frame.
35
- def frame
36
- @animator.frame
37
- end
38
-
39
- private
40
-
41
- # Facing follows movement intent (so we still "walk" while pushing a wall);
42
- # horizontal wins over vertical.
43
- def walk_animation(intent_x, intent_y)
44
- if intent_x.negative? then :walk_left
45
- elsif intent_x.positive? then :walk_right
46
- elsif intent_y.negative? then :walk_up
47
- elsif intent_y.positive? then :walk_down
48
- else :stand
49
- end
50
- end
51
- end
52
- end
53
- end
@@ -1,49 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RGame
4
- module Engine
5
- # Reusable kinematics for free-moving, rotating entities (ship, rocks, bullets):
6
- # position, linear velocity, facing angle and angular velocity. `integrate`
7
- # advances them by a fixed dt; `wrap!` implements toroidal screen-wrap and
8
- # `offscreen?` the despawn test. Pure logic; no graphics.
9
- #
10
- # Angle is in radians, 0 = pointing right (+x), increasing clockwise on screen
11
- # (since y grows downward). A heading's unit vector is therefore (cos, sin).
12
- class Body
13
- attr_accessor :x, :y, :vx, :vy, :angle, :spin
14
-
15
- def initialize(x: 0.0, y: 0.0, vx: 0.0, vy: 0.0, angle: 0.0, spin: 0.0)
16
- @x = x
17
- @y = y
18
- @vx = vx
19
- @vy = vy
20
- @angle = angle
21
- @spin = spin
22
- end
23
-
24
- def integrate(dt)
25
- @x += @vx * dt
26
- @y += @vy * dt
27
- @angle += @spin * dt
28
- end
29
-
30
- # Toroidal wrap: once the centre passes `margin` beyond an edge it reappears on
31
- # the opposite side. Using margin = the entity's radius means an object spawned
32
- # flush against an edge (centre at -radius) is exactly *at* the threshold, not
33
- # past it, so it never wraps on the frame it spawns.
34
- def wrap!(width, height, margin)
35
- span_x = width + (2 * margin)
36
- span_y = height + (2 * margin)
37
- @x += span_x while @x < -margin
38
- @x -= span_x while @x > width + margin
39
- @y += span_y while @y < -margin
40
- @y -= span_y while @y > height + margin
41
- end
42
-
43
- # Fully past an edge by `margin` (e.g. a bullet that left the screen).
44
- def offscreen?(width, height, margin)
45
- @x < -margin || @x > width + margin || @y < -margin || @y > height + margin
46
- end
47
- end
48
- end
49
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RGame
4
- module Engine
5
- # Holds a display string and rebuilds it only when its source value changes, so a
6
- # per-frame draw can show the cached copy without interpolating (allocating) a String
7
- # every frame. The format block runs only on an actual change.
8
- #
9
- # @score_label = Engine::CachedLabel.new { |score| "Score: #{score}" } # build the block once
10
- # renderer.text(@score_label[@score], 12, 10) # in on_draw: cached, no alloc
11
- #
12
- # `@score_label[value]` returns the cached string when `value` is unchanged, and
13
- # otherwise rebuilds it through the block. Construct it (and its block) outside the
14
- # per-frame path — e.g. in `on_add` — so the interpolation isn't itself a per-frame cost.
15
- class CachedLabel
16
- def initialize(&format)
17
- raise ArgumentError, 'CachedLabel needs a format block' unless format
18
-
19
- @format = format
20
- @value = nil
21
- @text = nil
22
- end
23
-
24
- # The cached string for `value`, rebuilt only when `value` differs from last time.
25
- def [](value)
26
- return @text if !@text.nil? && value == @value
27
-
28
- @value = value
29
- @text = @format.call(value)
30
- end
31
- end
32
- end
33
- end
@@ -1,28 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RGame
4
- module Engine
5
- # A node whose children live in *world* space and are drawn through a Camera: it
6
- # wraps their draw in renderer.translated(-camera.x, -camera.y), so the camera's
7
- # offset maps the world onto the screen. The children never know about the camera —
8
- # they draw at their own absolute (world) origin, and the view transform does the
9
- # rest. The owning scene drives the camera (e.g. centring it on the player); this
10
- # node only applies it.
11
- #
12
- # The offset is a draw-time transform, not a position baked into a node, so the same
13
- # world can later be drawn through several cameras (split-screen) by repeating the
14
- # pass under different offsets/clips.
15
- class CameraView < Node2D
16
- def initialize(camera:, **)
17
- super(**)
18
- @camera = camera
19
- end
20
-
21
- private
22
-
23
- def draw_children(renderer)
24
- renderer.translated(-@camera.x, -@camera.y) { super }
25
- end
26
- end
27
- end
28
- end
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RGame
4
- module Engine
5
- # Drives an Actor from player input: turns the move_x/move_y actions into a
6
- # movement intent. NPC controllers implement the same `intent(dt, input)` seam
7
- # and ignore `input`.
8
- class PlayerController
9
- def intent(_dt, input)
10
- [input.axis(:move_x), input.axis(:move_y)]
11
- end
12
- end
13
- end
14
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RGame
4
- module Engine
5
- # A fixed-size 2-D grid backed by a single flat (row-major) array, addressed as
6
- # [x, y]. The flat backing keeps the whole grid in one contiguous allocation —
7
- # cheaper than an array-of-arrays and a straightforward shape to later move into a
8
- # C-level buffer. Pure; no bounds checking on the hot path (callers stay in range).
9
- #
10
- # This stays Ruby, unlike the engine's old `Tensor`, which was deleted in
11
- # favour of the C `RGame::Util::Tensor`. The reason is only that there is no
12
- # C `Util::Matrix` to swap to — `Util` holds `Tensor`, `Controls` and
13
- # `Color`. If one is ever written, this is the caller to point at it.
14
- class Matrix
15
- attr_reader :width, :height
16
-
17
- def initialize(width, height, initial: nil)
18
- @width = width
19
- @height = height
20
- @data = Array.new(width * height, initial)
21
- end
22
-
23
- def [](x, y)
24
- @data[(y * @width) + x]
25
- end
26
-
27
- def []=(x, y, value)
28
- @data[(y * @width) + x] = value
29
- end
30
- end
31
- end
32
- end
@@ -1,67 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RGame
4
- module Engine
5
- # Builds value-object classes for pooling. Like `Data.define`, instances expose
6
- # read-only accessors and carry their fields as a unit — but where a `Data` value
7
- # is fully immutable (every change means a fresh allocation), these add exactly
8
- # one mutation: `reset`, which overwrites all fields at once and returns self.
9
- #
10
- # That is the only mutability a pool needs: acquire a recycled instance and
11
- # `reset` it, without exposing the per-field setters a `Struct` would. The methods
12
- # are generated fixed-arity with direct ivar assignment (as Struct/Data do), so
13
- # `reset` is allocation-free and recycling stays zero-allocation in steady state.
14
- #
15
- # Positional by default; pass `keyword_init: true` for keyword fields. Keywords
16
- # are *also* allocation-free here because they are generated as named parameters
17
- # (`reset(x:, y:)`), not a `**kwargs` splat — the splat is the one form that builds
18
- # a Hash per call.
19
- #
20
- # Point = Engine::Resettable.define(:x, :y)
21
- # p = Point.new(3, 4); p.x # => 3
22
- # p.reset(5, 6) # same object, new values; returns p
23
- #
24
- # Event = Engine::Resettable.define(:type, :payload, keyword_init: true)
25
- # e = Event.new(type: :hit, payload: 10)
26
- # e.reset(type: :lose, payload: nil) # same object; returns e
27
- # e.respond_to?(:type=) # => false (no setters)
28
- #
29
- # Field names are generated into real methods, so they must be plain identifiers.
30
- module Resettable
31
- IDENTIFIER = /\A[a-z_][a-zA-Z0-9_]*\z/
32
-
33
- def self.define(*fields, keyword_init: false)
34
- fields.each do |field|
35
- raise ArgumentError, "invalid field name: #{field.inspect}" unless field.to_s.match?(IDENTIFIER)
36
- end
37
-
38
- params = fields.map { |f| keyword_init ? "#{f}:" : f.to_s }.join(', ')
39
- assign = fields.map { |f| "@#{f} = #{f}" }.join("\n")
40
-
41
- Class.new do
42
- class_eval(<<~RUBY, __FILE__, __LINE__ + 1)
43
- # For fields [:x, :y] this generates (keyword_init makes `x, y` -> `x:, y:`):
44
- # attr_reader :x, :y
45
- # def initialize(x, y)
46
- # @x = x; @y = y
47
- # end
48
- # def reset(x, y)
49
- # @x = x; @y = y
50
- # self
51
- # end
52
- attr_reader #{fields.map { |f| ":#{f}" }.join(', ')}
53
-
54
- def initialize(#{params})
55
- #{assign}
56
- end
57
-
58
- def reset(#{params})
59
- #{assign}
60
- self
61
- end
62
- RUBY
63
- end
64
- end
65
- end
66
- end
67
- end
@@ -1,78 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RGame
4
- module Engine
5
- # Axis-separated AABB-vs-tile collision resolution (pure). `solid` is a callable
6
- # `solid.call(col, row) -> bool`. Resolve X then Y (with the X result) to get
7
- # wall-sliding. Assumes per-step movement smaller than a tile (no tunneling),
8
- # which holds for our speeds.
9
- class TileCollision
10
- EPS = 1e-9
11
-
12
- def initialize(tile_width:, tile_height:, solid:)
13
- @tile_width = tile_width
14
- @tile_height = tile_height
15
- @solid = solid
16
- end
17
-
18
- # Move an AABB (top-left x, y; size w, h) by dx, snapping flush against solids.
19
- def resolve_x(x, y, w, h, dx)
20
- nx = x + dx
21
- return nx if dx.zero?
22
-
23
- first_row = (y / @tile_height).floor
24
- last_row = ((y + h - EPS) / @tile_height).floor
25
-
26
- if dx.positive?
27
- col = ((nx + w - EPS) / @tile_width).floor
28
- return col * @tile_width - w if solid_in_rows?(col, first_row, last_row)
29
- else
30
- col = (nx / @tile_width).floor
31
- return (col + 1) * @tile_width if solid_in_rows?(col, first_row, last_row)
32
- end
33
- nx
34
- end
35
-
36
- def resolve_y(x, y, w, h, dy)
37
- ny = y + dy
38
- return ny if dy.zero?
39
-
40
- first_col = (x / @tile_width).floor
41
- last_col = ((x + w - EPS) / @tile_width).floor
42
-
43
- if dy.positive?
44
- row = ((ny + h - EPS) / @tile_height).floor
45
- return row * @tile_height - h if solid_in_cols?(row, first_col, last_col)
46
- else
47
- row = (ny / @tile_height).floor
48
- return (row + 1) * @tile_height if solid_in_cols?(row, first_col, last_col)
49
- end
50
- ny
51
- end
52
-
53
- private
54
-
55
- # Plain integer loops rather than (a..b).any? { ... }: the Range literal would
56
- # allocate on this per-frame collision path.
57
- def solid_in_rows?(col, first_row, last_row)
58
- row = first_row
59
- while row <= last_row
60
- return true if @solid.call(col, row)
61
-
62
- row += 1
63
- end
64
- false
65
- end
66
-
67
- def solid_in_cols?(row, first_col, last_col)
68
- col = first_col
69
- while col <= last_col
70
- return true if @solid.call(col, row)
71
-
72
- col += 1
73
- end
74
- false
75
- end
76
- end
77
- end
78
- end