rgame 0.1.0 → 0.2.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 +94 -0
- data/README.md +130 -233
- data/docs/api/README.md +116 -69
- data/docs/api/assets.md +11 -12
- data/docs/api/components.md +58 -34
- data/docs/api/drawing.md +77 -9
- data/docs/api/game.md +34 -13
- data/docs/api/input.md +232 -51
- data/docs/api/scene_graph.md +242 -15
- data/docs/api/systems.md +20 -0
- data/docs/api/toolbox.md +19 -15
- data/docs/api/ui.md +98 -0
- data/docs/api/values.md +32 -0
- data/ext/README.md +6 -5
- data/ext/rgame_core/app/app.c +182 -8
- data/ext/rgame_core/audio/audio.c +74 -0
- data/ext/rgame_core/example.rb +17 -6
- data/ext/rgame_core/extconf.rb +52 -24
- 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 +113 -3
- data/ext/rgame_core/input/gamepad.c +57 -3
- data/ext/rgame_core/ruby/core_ext.c +16 -0
- data/ext/rgame_core/ruby/renderer_ext.c +23 -0
- data/ext/rgame_util/color_ext.c +12 -3
- data/lib/rgame/core/app.rb +2 -0
- data/lib/rgame/core/input.rb +35 -41
- data/lib/rgame/core/recording.rb +3 -1
- data/lib/rgame/core/renderer.rb +76 -28
- data/lib/rgame/core/tile_map_renderer.rb +84 -55
- data/lib/rgame/engine/camera.rb +55 -10
- data/lib/rgame/engine/component.rb +11 -1
- data/lib/rgame/engine/components/animated_sprite.rb +9 -3
- data/lib/rgame/engine/components/camera_follow.rb +44 -0
- data/lib/rgame/engine/components/character_body.rb +25 -4
- data/lib/rgame/engine/components/sprite.rb +11 -1
- data/lib/rgame/engine/components/tile_world.rb +31 -18
- data/lib/rgame/engine/culling.rb +47 -0
- data/lib/rgame/engine/debug_overlay.rb +20 -9
- data/lib/rgame/engine/input/action_mapper.rb +101 -21
- data/lib/rgame/engine/input/actions.rb +69 -12
- data/lib/rgame/engine/input/input_map.rb +178 -0
- data/lib/rgame/engine/layout.rb +82 -0
- data/lib/rgame/engine/node2d.rb +205 -36
- data/lib/rgame/engine/player.rb +69 -0
- data/lib/rgame/engine/player_layer.rb +70 -0
- data/lib/rgame/engine/players.rb +212 -0
- data/lib/rgame/engine/scene/scene_stack.rb +25 -3
- data/lib/rgame/engine/spatial_hash.rb +17 -4
- data/lib/rgame/engine/tile_map_layer.rb +84 -0
- data/lib/rgame/engine/ui/menu.rb +115 -0
- data/lib/rgame/engine/ui/menu_item.rb +84 -0
- data/lib/rgame/engine/view.rb +76 -0
- data/lib/rgame/engine/viewports.rb +174 -0
- data/lib/rgame/engine/world_view.rb +70 -0
- data/lib/rgame/engine.rb +13 -1
- data/lib/rgame/game.rb +81 -11
- data/lib/rgame/util/controls.rb +117 -41
- data/lib/rgame/util/z.rb +133 -0
- data/lib/rgame/util.rb +1 -0
- data/lib/rgame/version.rb +1 -1
- metadata +26 -11
- data/lib/rgame/engine/camera_view.rb +0 -28
data/lib/rgame/util/z.rb
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RGame
|
|
4
|
+
module Util
|
|
5
|
+
# The vocabulary of draw order: which band a thing is drawn in, and how the
|
|
6
|
+
# single number the renderer sorts on is built out of one.
|
|
7
|
+
#
|
|
8
|
+
# RGame::Util::Z::BANDS # => [:world, :hud, :overlay, :debug]
|
|
9
|
+
# RGame::Util::Z.base(:hud, 3) # the fourth slot handed out in the HUD band
|
|
10
|
+
#
|
|
11
|
+
# These are values — plain Symbols and Integers with no window, GPU or OS
|
|
12
|
+
# handle behind them — so they live here rather than in Core, and both sides
|
|
13
|
+
# of the line may name them. `RGame::Engine` decides which band a node is
|
|
14
|
+
# in; `RGame::Core::Renderer` turns that into a z. Neither could reach the
|
|
15
|
+
# other's spelling of it, and the vocabulary is exactly what they have to
|
|
16
|
+
# agree on. Same reasoning as RGame::Util::Controls.
|
|
17
|
+
#
|
|
18
|
+
# ## Draw order is tree order, not a number a caller picks
|
|
19
|
+
#
|
|
20
|
+
# A frame's order is decided in three steps, coarsest first:
|
|
21
|
+
#
|
|
22
|
+
# 1. **The band.** Structural and inherited: everything in `:world` is under
|
|
23
|
+
# everything in `:hud`, whatever either drew. Bands are 2**40 apart, so
|
|
24
|
+
# no arithmetic below can carry one into the next.
|
|
25
|
+
# 2. **The slot.** The scene graph is walked depth-first with siblings in
|
|
26
|
+
# `z` order, and each node takes the next slot in its band as it is
|
|
27
|
+
# reached. Because the walk descends fully before moving on, a node's
|
|
28
|
+
# subtree occupies one contiguous run of slots — which is what makes a
|
|
29
|
+
# subtree atomic, and what stops some of a node's children landing in
|
|
30
|
+
# front of a sibling the node itself is behind.
|
|
31
|
+
# 3. **The offset.** `Z_MIN..Z_MAX` inside the node's own slot, and the only
|
|
32
|
+
# part a `z:` argument on a drawing call touches. It orders a node's
|
|
33
|
+
# components against each other and its own draw calls against each
|
|
34
|
+
# other, and it cannot reach the next node, let alone the next band.
|
|
35
|
+
#
|
|
36
|
+
# So a node's `z` is **only ever compared to its siblings'**. Its magnitude
|
|
37
|
+
# means nothing: `z: 1` and `z: 1_000_000` behave identically if they are
|
|
38
|
+
# the only two children, and negatives are ordinary.
|
|
39
|
+
#
|
|
40
|
+
# ## The arithmetic is exact
|
|
41
|
+
#
|
|
42
|
+
# Every value here is an integer below 2**42, and the `double` the draw
|
|
43
|
+
# queue sorts on is exact below 2**53. Two different slots can therefore
|
|
44
|
+
# never compare equal by rounding — which would show up as two sprites
|
|
45
|
+
# swapping places between frames, and would be very hard to see as a
|
|
46
|
+
# precision problem.
|
|
47
|
+
module Z
|
|
48
|
+
# How much room a node has for ordering its own drawing. Nothing in this
|
|
49
|
+
# repo uses more than three offsets; a thousand is room to stop thinking
|
|
50
|
+
# about it.
|
|
51
|
+
SLOT = 1024
|
|
52
|
+
HALF = SLOT / 2
|
|
53
|
+
|
|
54
|
+
# What a `z:` argument on a drawing call may be. Signed, because a node
|
|
55
|
+
# drawing something *behind* its sprite is as ordinary as drawing
|
|
56
|
+
# something in front of it, and the sprite's own default is 0.
|
|
57
|
+
Z_MIN = -HALF
|
|
58
|
+
Z_MAX = HALF - 1
|
|
59
|
+
|
|
60
|
+
# The gap between bands: 2**30 slots each, which no frame will approach.
|
|
61
|
+
STRIDE = 1 << 40
|
|
62
|
+
SLOTS_PER_BAND = STRIDE / SLOT
|
|
63
|
+
|
|
64
|
+
# In order, back to front.
|
|
65
|
+
#
|
|
66
|
+
# `:world` is what a node with no band ancestor is in, so a game that
|
|
67
|
+
# never mentions a band is entirely in it. `:hud` is one player's own
|
|
68
|
+
# screen space (RGame::Engine::PlayerLayer), `:overlay` is screen space
|
|
69
|
+
# across the whole window — a cutscene, a results panel — and `:debug` is
|
|
70
|
+
# the development overlay, over everything by construction.
|
|
71
|
+
BANDS = %i[world hud overlay debug].freeze
|
|
72
|
+
DEFAULT = :world
|
|
73
|
+
|
|
74
|
+
INDICES = BANDS.each_with_index.to_h.freeze
|
|
75
|
+
|
|
76
|
+
def self.band?(band) = INDICES.key?(band)
|
|
77
|
+
|
|
78
|
+
# Raises unless `band` names one. Called where a band is *set* rather than
|
|
79
|
+
# where it is used, so a typo surfaces at assignment with the list in the
|
|
80
|
+
# message instead of as a KeyError from inside a draw.
|
|
81
|
+
def self.band!(band)
|
|
82
|
+
return band if band?(band)
|
|
83
|
+
|
|
84
|
+
raise ArgumentError, "unknown z band #{band.inspect}; expected one of #{BANDS.inspect}"
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Which band this is, 0-based and back to front. This is what a renderer's
|
|
88
|
+
# slot counters are keyed on, so it is also where a bad band is caught.
|
|
89
|
+
def self.index(band)
|
|
90
|
+
INDICES[band] || band!(band)
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# The z base of the `slot_index`-th slot in the band with that index.
|
|
94
|
+
# Offsets are measured from the middle of the slot, so Z_MIN..Z_MAX is
|
|
95
|
+
# symmetric — a node can draw behind its own sprite as easily as in front.
|
|
96
|
+
#
|
|
97
|
+
# Takes the band's *index* rather than its name because a renderer already
|
|
98
|
+
# has the index in hand (it counts slots per index), and looking the same
|
|
99
|
+
# Symbol up twice per node per frame is work with nothing to show for it.
|
|
100
|
+
# hot-path
|
|
101
|
+
def self.slot_base(band_index, slot_index)
|
|
102
|
+
if slot_index >= SLOTS_PER_BAND
|
|
103
|
+
raise RangeError,
|
|
104
|
+
"z band #{BANDS[band_index].inspect} is full at " \
|
|
105
|
+
"#{SLOTS_PER_BAND} slots per frame"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
(band_index * STRIDE) + (slot_index * SLOT) + HALF
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# The same thing by name, for a caller that has one rather than an index.
|
|
112
|
+
def self.base(band, slot_index) = slot_base(index(band), slot_index)
|
|
113
|
+
|
|
114
|
+
# Checks a `z:` argument and returns it. Drawing methods run this instead
|
|
115
|
+
# of trusting the caller, because the whole guarantee — that a node cannot
|
|
116
|
+
# draw outside its band — rests on the offset staying inside one slot.
|
|
117
|
+
# A stale global z (the bands used to be Integers a caller passed) lands
|
|
118
|
+
# here and says so rather than sorting somewhere surprising.
|
|
119
|
+
# hot-path
|
|
120
|
+
def self.offset(z)
|
|
121
|
+
raise TypeError, "no implicit conversion of #{z.class} into Float" unless z.is_a?(Numeric)
|
|
122
|
+
|
|
123
|
+
unless z.between?(Z_MIN, Z_MAX)
|
|
124
|
+
raise ArgumentError,
|
|
125
|
+
"z: #{z} is outside a node's slot (#{Z_MIN}..#{Z_MAX}); a `z:` orders one " \
|
|
126
|
+
'node\'s own drawing, and the band comes from the tree'
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
z
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
end
|
data/lib/rgame/util.rb
CHANGED
data/lib/rgame/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rgame
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Paul Süßenbach
|
|
@@ -10,16 +10,15 @@ cert_chain: []
|
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies: []
|
|
12
12
|
description: |
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
24
|
executables: []
|
|
@@ -28,6 +27,7 @@ extensions:
|
|
|
28
27
|
- ext/rgame_util/extconf.rb
|
|
29
28
|
extra_rdoc_files: []
|
|
30
29
|
files:
|
|
30
|
+
- CHANGELOG.md
|
|
31
31
|
- LICENSE
|
|
32
32
|
- README.md
|
|
33
33
|
- docs/api/README.md
|
|
@@ -45,6 +45,7 @@ files:
|
|
|
45
45
|
- docs/api/systems.md
|
|
46
46
|
- docs/api/text.md
|
|
47
47
|
- docs/api/toolbox.md
|
|
48
|
+
- docs/api/ui.md
|
|
48
49
|
- docs/api/values.md
|
|
49
50
|
- ext/README.md
|
|
50
51
|
- ext/rgame_core/app/app.c
|
|
@@ -140,13 +141,13 @@ files:
|
|
|
140
141
|
- lib/rgame/engine/body.rb
|
|
141
142
|
- lib/rgame/engine/cached_label.rb
|
|
142
143
|
- lib/rgame/engine/camera.rb
|
|
143
|
-
- lib/rgame/engine/camera_view.rb
|
|
144
144
|
- lib/rgame/engine/circle_collider.rb
|
|
145
145
|
- lib/rgame/engine/collision_box.rb
|
|
146
146
|
- lib/rgame/engine/collision_system.rb
|
|
147
147
|
- lib/rgame/engine/component.rb
|
|
148
148
|
- lib/rgame/engine/components/action_trigger.rb
|
|
149
149
|
- lib/rgame/engine/components/animated_sprite.rb
|
|
150
|
+
- lib/rgame/engine/components/camera_follow.rb
|
|
150
151
|
- lib/rgame/engine/components/character_body.rb
|
|
151
152
|
- lib/rgame/engine/components/circle_collider.rb
|
|
152
153
|
- lib/rgame/engine/components/collision_world.rb
|
|
@@ -162,14 +163,20 @@ files:
|
|
|
162
163
|
- lib/rgame/engine/components/timer.rb
|
|
163
164
|
- lib/rgame/engine/components/velocity.rb
|
|
164
165
|
- lib/rgame/engine/components/wander_controller.rb
|
|
166
|
+
- lib/rgame/engine/culling.rb
|
|
165
167
|
- lib/rgame/engine/debug_overlay.rb
|
|
166
168
|
- lib/rgame/engine/i18n.rb
|
|
167
169
|
- lib/rgame/engine/input/action_mapper.rb
|
|
168
170
|
- lib/rgame/engine/input/actions.rb
|
|
171
|
+
- lib/rgame/engine/input/input_map.rb
|
|
169
172
|
- lib/rgame/engine/input/player_controller.rb
|
|
173
|
+
- lib/rgame/engine/layout.rb
|
|
170
174
|
- lib/rgame/engine/matrix.rb
|
|
171
175
|
- lib/rgame/engine/node2d.rb
|
|
172
176
|
- lib/rgame/engine/path.rb
|
|
177
|
+
- lib/rgame/engine/player.rb
|
|
178
|
+
- lib/rgame/engine/player_layer.rb
|
|
179
|
+
- lib/rgame/engine/players.rb
|
|
173
180
|
- lib/rgame/engine/pool.rb
|
|
174
181
|
- lib/rgame/engine/resettable.rb
|
|
175
182
|
- lib/rgame/engine/scene/scene_stack.rb
|
|
@@ -177,8 +184,14 @@ files:
|
|
|
177
184
|
- lib/rgame/engine/spatial_hash.rb
|
|
178
185
|
- lib/rgame/engine/tile_collision.rb
|
|
179
186
|
- lib/rgame/engine/tile_map.rb
|
|
187
|
+
- lib/rgame/engine/tile_map_layer.rb
|
|
180
188
|
- lib/rgame/engine/tileset.rb
|
|
181
189
|
- lib/rgame/engine/timer.rb
|
|
190
|
+
- lib/rgame/engine/ui/menu.rb
|
|
191
|
+
- lib/rgame/engine/ui/menu_item.rb
|
|
192
|
+
- lib/rgame/engine/view.rb
|
|
193
|
+
- lib/rgame/engine/viewports.rb
|
|
194
|
+
- lib/rgame/engine/world_view.rb
|
|
182
195
|
- lib/rgame/fonts/LiberationSans-Regular.ttf
|
|
183
196
|
- lib/rgame/fonts/OFL.txt
|
|
184
197
|
- lib/rgame/game.rb
|
|
@@ -186,6 +199,7 @@ files:
|
|
|
186
199
|
- lib/rgame/util/color.rb
|
|
187
200
|
- lib/rgame/util/controls.rb
|
|
188
201
|
- lib/rgame/util/tensor.rb
|
|
202
|
+
- lib/rgame/util/z.rb
|
|
189
203
|
- lib/rgame/version.rb
|
|
190
204
|
homepage: https://github.com/psuessenb/rgame
|
|
191
205
|
licenses:
|
|
@@ -194,6 +208,7 @@ metadata:
|
|
|
194
208
|
source_code_uri: https://github.com/psuessenb/rgame
|
|
195
209
|
bug_tracker_uri: https://github.com/psuessenb/rgame/issues
|
|
196
210
|
documentation_uri: https://github.com/psuessenb/rgame/blob/main/docs/api/README.md
|
|
211
|
+
changelog_uri: https://github.com/psuessenb/rgame/blob/main/CHANGELOG.md
|
|
197
212
|
rubygems_mfa_required: 'true'
|
|
198
213
|
rdoc_options: []
|
|
199
214
|
require_paths:
|
|
@@ -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
|