rgame 0.1.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 +7 -0
- data/LICENSE +26 -0
- data/README.md +406 -0
- data/docs/api/README.md +167 -0
- data/docs/api/app.md +192 -0
- data/docs/api/assets.md +426 -0
- data/docs/api/audio.md +208 -0
- data/docs/api/components.md +321 -0
- data/docs/api/drawing.md +330 -0
- data/docs/api/game.md +99 -0
- data/docs/api/images.md +118 -0
- data/docs/api/input.md +179 -0
- data/docs/api/internals.md +110 -0
- data/docs/api/scene_graph.md +159 -0
- data/docs/api/signals.md +142 -0
- data/docs/api/systems.md +98 -0
- data/docs/api/text.md +116 -0
- data/docs/api/toolbox.md +240 -0
- data/docs/api/values.md +101 -0
- data/ext/README.md +225 -0
- data/ext/rgame_core/app/app.c +721 -0
- data/ext/rgame_core/app/app_gl.h +64 -0
- data/ext/rgame_core/app/frame_loop.c +42 -0
- data/ext/rgame_core/app/frame_loop.h +54 -0
- data/ext/rgame_core/audio/audio.c +466 -0
- data/ext/rgame_core/audio/audio_internal.h +45 -0
- data/ext/rgame_core/audio/vorbis_decoder.c +282 -0
- data/ext/rgame_core/audio/vorbis_decoder.h +45 -0
- data/ext/rgame_core/example.rb +188 -0
- data/ext/rgame_core/extconf.rb +167 -0
- data/ext/rgame_core/graphics/backend.c +52 -0
- data/ext/rgame_core/graphics/backend.h +64 -0
- data/ext/rgame_core/graphics/canvas.c +247 -0
- data/ext/rgame_core/graphics/canvas.h +143 -0
- data/ext/rgame_core/graphics/clip.c +87 -0
- data/ext/rgame_core/graphics/clip.h +89 -0
- data/ext/rgame_core/graphics/draw_queue.c +216 -0
- data/ext/rgame_core/graphics/draw_queue.h +174 -0
- data/ext/rgame_core/graphics/gl_backend.c +122 -0
- data/ext/rgame_core/graphics/gl_backend.h +43 -0
- data/ext/rgame_core/graphics/image.c +304 -0
- data/ext/rgame_core/graphics/image_internal.h +30 -0
- data/ext/rgame_core/graphics/primitives.c +189 -0
- data/ext/rgame_core/graphics/primitives.h +111 -0
- data/ext/rgame_core/graphics/recording.c +119 -0
- data/ext/rgame_core/graphics/recording.h +88 -0
- data/ext/rgame_core/graphics/texture.c +181 -0
- data/ext/rgame_core/graphics/texture.h +165 -0
- data/ext/rgame_core/graphics/transform.c +128 -0
- data/ext/rgame_core/graphics/transform.h +106 -0
- data/ext/rgame_core/include/rgame/core.h +577 -0
- data/ext/rgame_core/input/device_slots.c +103 -0
- data/ext/rgame_core/input/device_slots.h +93 -0
- data/ext/rgame_core/input/gamepad.c +145 -0
- data/ext/rgame_core/input/gamepad.h +63 -0
- data/ext/rgame_core/input/input.c +109 -0
- data/ext/rgame_core/input/input.h +99 -0
- data/ext/rgame_core/ruby/audio_ext.c +321 -0
- data/ext/rgame_core/ruby/core_ext.c +513 -0
- data/ext/rgame_core/ruby/core_ext.h +51 -0
- data/ext/rgame_core/ruby/font_ext.c +168 -0
- data/ext/rgame_core/ruby/image_ext.c +230 -0
- data/ext/rgame_core/ruby/recording_ext.c +186 -0
- data/ext/rgame_core/ruby/renderer_ext.c +376 -0
- data/ext/rgame_core/text/atlas.c +59 -0
- data/ext/rgame_core/text/atlas.h +85 -0
- data/ext/rgame_core/text/font.c +281 -0
- data/ext/rgame_core/text/font.h +139 -0
- data/ext/rgame_core/text/font_atlas.c +385 -0
- data/ext/rgame_core/text/font_internal.h +47 -0
- data/ext/rgame_core/text/glyph_cache.c +142 -0
- data/ext/rgame_core/text/glyph_cache.h +89 -0
- data/ext/rgame_core/vendor/README.md +159 -0
- data/ext/rgame_core/vendor/miniaudio.h +95864 -0
- data/ext/rgame_core/vendor/miniaudio_impl.c +62 -0
- data/ext/rgame_core/vendor/stb_image.h +7988 -0
- data/ext/rgame_core/vendor/stb_image_impl.c +31 -0
- data/ext/rgame_core/vendor/stb_truetype.h +5079 -0
- data/ext/rgame_core/vendor/stb_truetype_impl.c +23 -0
- data/ext/rgame_core/vendor/stb_vorbis.c +5584 -0
- data/ext/rgame_core/vendor/stb_vorbis_impl.c +29 -0
- data/ext/rgame_util/color.c +19 -0
- data/ext/rgame_util/color.h +60 -0
- data/ext/rgame_util/color_ext.c +156 -0
- data/ext/rgame_util/extconf.rb +27 -0
- data/ext/rgame_util/tensor.c +186 -0
- data/ext/rgame_util/util_ext.c +27 -0
- data/ext/rgame_util/util_ext.h +16 -0
- data/lib/rgame/boot.rb +13 -0
- data/lib/rgame/core/app.rb +82 -0
- data/lib/rgame/core/asset_manager.rb +224 -0
- data/lib/rgame/core/audio.rb +124 -0
- data/lib/rgame/core/font.rb +49 -0
- data/lib/rgame/core/gamepad.rb +55 -0
- data/lib/rgame/core/image.rb +55 -0
- data/lib/rgame/core/input.rb +77 -0
- data/lib/rgame/core/nine_slice.rb +163 -0
- data/lib/rgame/core/recording.rb +52 -0
- data/lib/rgame/core/renderer.rb +363 -0
- data/lib/rgame/core/sprite_sheet.rb +108 -0
- data/lib/rgame/core/tile_map_renderer.rb +160 -0
- data/lib/rgame/core/ui_atlas.rb +86 -0
- data/lib/rgame/core.rb +24 -0
- data/lib/rgame/engine/actor.rb +53 -0
- data/lib/rgame/engine/animation_set.rb +49 -0
- data/lib/rgame/engine/animator.rb +44 -0
- data/lib/rgame/engine/audio_bus.rb +24 -0
- data/lib/rgame/engine/audio_director.rb +29 -0
- data/lib/rgame/engine/body.rb +49 -0
- data/lib/rgame/engine/cached_label.rb +33 -0
- data/lib/rgame/engine/camera.rb +33 -0
- data/lib/rgame/engine/camera_view.rb +28 -0
- data/lib/rgame/engine/circle_collider.rb +32 -0
- data/lib/rgame/engine/collision_box.rb +34 -0
- data/lib/rgame/engine/collision_system.rb +44 -0
- data/lib/rgame/engine/component.rb +30 -0
- data/lib/rgame/engine/components/action_trigger.rb +41 -0
- data/lib/rgame/engine/components/animated_sprite.rb +63 -0
- data/lib/rgame/engine/components/character_body.rb +70 -0
- data/lib/rgame/engine/components/circle_collider.rb +44 -0
- data/lib/rgame/engine/components/collision_world.rb +103 -0
- data/lib/rgame/engine/components/despawn_offscreen.rb +26 -0
- data/lib/rgame/engine/components/path_follow.rb +84 -0
- data/lib/rgame/engine/components/player_controller.rb +24 -0
- data/lib/rgame/engine/components/pool.rb +53 -0
- data/lib/rgame/engine/components/screen_wrap.rb +27 -0
- data/lib/rgame/engine/components/sprite.rb +31 -0
- data/lib/rgame/engine/components/targeting.rb +54 -0
- data/lib/rgame/engine/components/thrust_controller.rb +65 -0
- data/lib/rgame/engine/components/tile_world.rb +68 -0
- data/lib/rgame/engine/components/timer.rb +75 -0
- data/lib/rgame/engine/components/velocity.rb +27 -0
- data/lib/rgame/engine/components/wander_controller.rb +60 -0
- data/lib/rgame/engine/debug_overlay.rb +106 -0
- data/lib/rgame/engine/i18n.rb +97 -0
- data/lib/rgame/engine/input/action_mapper.rb +46 -0
- data/lib/rgame/engine/input/actions.rb +41 -0
- data/lib/rgame/engine/input/player_controller.rb +14 -0
- data/lib/rgame/engine/matrix.rb +32 -0
- data/lib/rgame/engine/node2d.rb +271 -0
- data/lib/rgame/engine/path.rb +78 -0
- data/lib/rgame/engine/pool.rb +51 -0
- data/lib/rgame/engine/resettable.rb +67 -0
- data/lib/rgame/engine/scene/scene_stack.rb +65 -0
- data/lib/rgame/engine/signal.rb +75 -0
- data/lib/rgame/engine/spatial_hash.rb +71 -0
- data/lib/rgame/engine/tile_collision.rb +78 -0
- data/lib/rgame/engine/tile_map.rb +149 -0
- data/lib/rgame/engine/tileset.rb +101 -0
- data/lib/rgame/engine/timer.rb +51 -0
- data/lib/rgame/engine.rb +68 -0
- data/lib/rgame/fonts/LiberationSans-Regular.ttf +0 -0
- data/lib/rgame/fonts/OFL.txt +102 -0
- data/lib/rgame/game.rb +129 -0
- data/lib/rgame/util/color.rb +27 -0
- data/lib/rgame/util/controls.rb +107 -0
- data/lib/rgame/util/tensor.rb +12 -0
- data/lib/rgame/util.rb +8 -0
- data/lib/rgame/version.rb +12 -0
- data/lib/rgame.rb +20 -0
- metadata +215 -0
data/lib/rgame/game.rb
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative 'boot'
|
|
4
|
+
require_relative 'core'
|
|
5
|
+
require_relative 'engine'
|
|
6
|
+
|
|
7
|
+
module RGame
|
|
8
|
+
# The entry point of a game, and the one class that knows both halves.
|
|
9
|
+
#
|
|
10
|
+
# class HelloScene < RGame::Engine::Node2D
|
|
11
|
+
# def on_draw(renderer) = renderer.text('Hello world!', 250, 200)
|
|
12
|
+
# end
|
|
13
|
+
#
|
|
14
|
+
# RGame::Game.new(root: HelloScene.new, caption: 'Hello').start
|
|
15
|
+
#
|
|
16
|
+
# A complete game is a root node plus that. `Game` assembles the pieces
|
|
17
|
+
# around it — the window and its loop, the renderer, the asset manager, the
|
|
18
|
+
# sound device, the input mapper, the debug overlay — and drives the root
|
|
19
|
+
# node once per tick.
|
|
20
|
+
#
|
|
21
|
+
# ## Why this class is allowed to name both layers
|
|
22
|
+
#
|
|
23
|
+
# `RGame::Engine` holds game concepts and may not name `RGame::Core`;
|
|
24
|
+
# `RGame::Core` owns handles and may not know Engine exists. Two RuboCop cops
|
|
25
|
+
# say so. Something still has to introduce them, and **this is that
|
|
26
|
+
# something** — see CLAUDE.md, "The rule points both ways". Keeping the
|
|
27
|
+
# introduction to one file is what makes the rule checkable everywhere else,
|
|
28
|
+
# so wiring belongs here and only here.
|
|
29
|
+
#
|
|
30
|
+
# The tile-map loader is the clearest case. Parsing a `.tmx` is Engine's job
|
|
31
|
+
# and drawing one is Core's, and neither may call the other, so `Game`
|
|
32
|
+
# installs the loader that joins them.
|
|
33
|
+
#
|
|
34
|
+
# ## The loop
|
|
35
|
+
#
|
|
36
|
+
# `Game` is an `App`, so it inherits the fixed-timestep loop rather than
|
|
37
|
+
# running one. Its hooks do three things: sample input once per frame, drive
|
|
38
|
+
# the root once per tick, and draw. Nothing here counts steps or measures
|
|
39
|
+
# time — `frame_loop.c` does that, and `update` is called once per whole tick.
|
|
40
|
+
class Game < RGame::Core::App
|
|
41
|
+
Controls = RGame::Util::Controls
|
|
42
|
+
|
|
43
|
+
WIDTH = 640
|
|
44
|
+
HEIGHT = 480
|
|
45
|
+
|
|
46
|
+
attr_reader :root, :renderer, :action_mapper
|
|
47
|
+
|
|
48
|
+
def initialize(root:, width: WIDTH, height: HEIGHT, caption: 'RGame',
|
|
49
|
+
media_root: 'media', action_map: {})
|
|
50
|
+
super(width: width, height: height, caption: caption, media_root: media_root)
|
|
51
|
+
|
|
52
|
+
@root = root
|
|
53
|
+
@renderer = RGame::Core::Renderer.new(self)
|
|
54
|
+
@input = RGame::Core::Input.new(self)
|
|
55
|
+
@action_mapper = RGame::Engine::ActionMapper.new(action_map)
|
|
56
|
+
@overlay = RGame::Engine::DebugOverlay.new # always wired up; F1 reveals it
|
|
57
|
+
@dirty = true # draw the first frame
|
|
58
|
+
|
|
59
|
+
install_asset_loaders
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Brings the tree live and runs until the window closes.
|
|
63
|
+
#
|
|
64
|
+
# The root gets this object as its `context`, which is how a node deep in
|
|
65
|
+
# the tree reaches the asset manager (`node.root.context.assets`) without
|
|
66
|
+
# anything being threaded through its constructor.
|
|
67
|
+
def start
|
|
68
|
+
@root.context = self
|
|
69
|
+
@root.enter_tree # components attach, then on_add
|
|
70
|
+
run
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# One fixed simulation tick. `dt` is always the engine's fixed step, so the
|
|
74
|
+
# tree never sees variable frame time.
|
|
75
|
+
#
|
|
76
|
+
# **Input is polled here, per tick, not in `frame_begin` per frame.** That
|
|
77
|
+
# is not where it started, and the reason is edge detection: `pressed?` is
|
|
78
|
+
# "held now, not held at the previous poll", so whatever polls decides what
|
|
79
|
+
# a press *is*. `frame_begin` runs once per rendered frame, and a loop that
|
|
80
|
+
# renders faster than it simulates runs it many times between two ticks —
|
|
81
|
+
# each one shifting the previous state, so the press is consumed by a poll
|
|
82
|
+
# no tick ever reads. Menus stop responding, and only on fast machines.
|
|
83
|
+
#
|
|
84
|
+
# Polling per tick costs nothing extra and loses nothing: the C layer
|
|
85
|
+
# snapshots the keyboard once per frame, so several ticks inside one frame
|
|
86
|
+
# read identical state, and the edge lands on the first of them — one press,
|
|
87
|
+
# one `pressed?`, which is what a caller means.
|
|
88
|
+
def update(dt)
|
|
89
|
+
@root.control(@action_mapper.poll(@input))
|
|
90
|
+
@root.update(dt)
|
|
91
|
+
@root.sweep_freed # flush queue_free'd nodes outside the update traversal
|
|
92
|
+
@dirty = true
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Only the simulation advancing makes the frame stale. While the overlay is
|
|
96
|
+
# up, redraw anyway, so its numbers stay live even when nothing is moving.
|
|
97
|
+
def needs_redraw? = @dirty || @overlay.visible?
|
|
98
|
+
|
|
99
|
+
def draw
|
|
100
|
+
@root.draw(@renderer)
|
|
101
|
+
@overlay.draw(@renderer, width, height, fps) # last, so it layers on top
|
|
102
|
+
@dirty = false
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def button_down(id)
|
|
106
|
+
close if id == Controls::KEY_ESCAPE
|
|
107
|
+
@overlay.toggle if id == Controls::KEY_F1
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
private
|
|
111
|
+
|
|
112
|
+
# Teaches the asset manager the types Core cannot build for itself.
|
|
113
|
+
#
|
|
114
|
+
# `:tilemap` is the only one so far, and it is the reason this method
|
|
115
|
+
# exists: `RGame::Engine::TileMap` reads the `.tmx`, `Image#tiles` slices the
|
|
116
|
+
# tileset through the cache — so two maps sharing a tileset share one
|
|
117
|
+
# upload — and `Core::TileMapRenderer` draws the result. Three objects, and
|
|
118
|
+
# neither of the outer two may name the other.
|
|
119
|
+
def install_asset_loaders
|
|
120
|
+
game = self
|
|
121
|
+
assets.add_loader(:tilemap) do |path|
|
|
122
|
+
map, image_path = RGame::Engine::TileMap.load(path)
|
|
123
|
+
tiles = game.assets.image(image_path)
|
|
124
|
+
.tiles(map.tileset.tile_width, map.tileset.tile_height)
|
|
125
|
+
RGame::Core::TileMapRenderer.new(map, tiles)
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# RGame::Util::Color is implemented in C — see ext/rgame_util/color_ext.c for
|
|
4
|
+
# the Ruby binding and ext/rgame_util/color.c for the packing arithmetic.
|
|
5
|
+
#
|
|
6
|
+
# Color = RGame::Util::Color
|
|
7
|
+
# Color.new(255, 128, 0) # r, g, b, a defaults to 255
|
|
8
|
+
# Color.rgba(255, 128, 0, 200) # the same thing, named
|
|
9
|
+
# Color.from_packed(0xFF8000FF) # 0xRRGGBBAA
|
|
10
|
+
# Color::WHITE # also BLACK and TRANSPARENT
|
|
11
|
+
#
|
|
12
|
+
# c.r; c.g; c.b; c.a # => Integer, 0..255
|
|
13
|
+
# c.packed # => Integer, 0xRRGGBBAA
|
|
14
|
+
#
|
|
15
|
+
# Instances are frozen and compare by value, so a Color works as a Hash key and
|
|
16
|
+
# can be shared without anyone tinting it out from under its other holders.
|
|
17
|
+
#
|
|
18
|
+
# Every draw call accepts a colour as nil (white), [r, g, b], [r, g, b, a] or a
|
|
19
|
+
# Color; `Color.coerce` is the single place that conversion happens.
|
|
20
|
+
#
|
|
21
|
+
# A colour is a *value* — no window, no GPU handle — so it lives in Util rather
|
|
22
|
+
# than Core. That is what lets the engine layer hold one as an attribute; see
|
|
23
|
+
# CLAUDE.md, "Value objects go in Util; only handle-owners go in Core".
|
|
24
|
+
#
|
|
25
|
+
# It loads from lib/rgame/util_ext.so, which `make ext-util` copies out of
|
|
26
|
+
# ext/rgame_util/.
|
|
27
|
+
require 'rgame/util_ext'
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module RGame
|
|
4
|
+
module Util
|
|
5
|
+
# The vocabulary of physical inputs: which integer means "the left arrow
|
|
6
|
+
# key", "the A button", "the left stick's X axis", "player 2's controller".
|
|
7
|
+
#
|
|
8
|
+
# These are values — plain integers with no window, GPU or OS handle behind
|
|
9
|
+
# them — so they live in Util rather than Core. That is what lets the engine
|
|
10
|
+
# layer and a game's own configuration name a physical input without
|
|
11
|
+
# touching RGame::Core, which they may not do:
|
|
12
|
+
#
|
|
13
|
+
# bindings = Controls::DEFAULT_KEYBOARD.merge(fire: Controls::KEY_J)
|
|
14
|
+
# RGame::Core::Input.new(app, bindings: bindings)
|
|
15
|
+
#
|
|
16
|
+
# The same numbers exist as `#define`s in
|
|
17
|
+
# ext/rgame_core/include/rgame/core.h, because the C engine and the
|
|
18
|
+
# standalone binary need them too and cannot see Ruby. Two definitions means
|
|
19
|
+
# a drift risk, so it is checked: the C side is tied to SDL's own scancodes
|
|
20
|
+
# by _Static_assert at compile time, and spec/rgame/util/controls_spec.rb
|
|
21
|
+
# parses that header and compares every value here against it.
|
|
22
|
+
module Controls
|
|
23
|
+
# --- Keyboard. Values are SDL scancodes. ---
|
|
24
|
+
KEY_RETURN = 40
|
|
25
|
+
KEY_ESCAPE = 41
|
|
26
|
+
KEY_SPACE = 44
|
|
27
|
+
KEY_F1 = 58
|
|
28
|
+
KEY_RIGHT = 79
|
|
29
|
+
KEY_LEFT = 80
|
|
30
|
+
KEY_DOWN = 81
|
|
31
|
+
KEY_UP = 82
|
|
32
|
+
|
|
33
|
+
# --- Gamepad buttons. The gamepad range plus SDL's controller button. ---
|
|
34
|
+
PAD_A = 4096
|
|
35
|
+
PAD_B = 4097
|
|
36
|
+
PAD_X = 4098
|
|
37
|
+
PAD_Y = 4099
|
|
38
|
+
PAD_BACK = 4100
|
|
39
|
+
PAD_GUIDE = 4101
|
|
40
|
+
PAD_START = 4102
|
|
41
|
+
PAD_LEFT_STICK = 4103
|
|
42
|
+
PAD_RIGHT_STICK = 4104
|
|
43
|
+
PAD_LEFT_SHOULDER = 4105
|
|
44
|
+
PAD_RIGHT_SHOULDER = 4106
|
|
45
|
+
PAD_DPAD_UP = 4107
|
|
46
|
+
PAD_DPAD_DOWN = 4108
|
|
47
|
+
PAD_DPAD_LEFT = 4109
|
|
48
|
+
PAD_DPAD_RIGHT = 4110
|
|
49
|
+
|
|
50
|
+
# --- Analog axes. Their own small space: they are float-valued and read
|
|
51
|
+
# through a different call, so folding them into the button space would
|
|
52
|
+
# only invite asking for an axis as if it were a button. ---
|
|
53
|
+
AXIS_LEFT_X = 0
|
|
54
|
+
AXIS_LEFT_Y = 1
|
|
55
|
+
AXIS_RIGHT_X = 2
|
|
56
|
+
AXIS_RIGHT_Y = 3
|
|
57
|
+
AXIS_TRIGGER_LEFT = 4
|
|
58
|
+
AXIS_TRIGGER_RIGHT = 5
|
|
59
|
+
|
|
60
|
+
# --- Devices. The keyboard is 0 so single-player code can leave it out;
|
|
61
|
+
# gamepads follow, one per player slot. ---
|
|
62
|
+
KEYBOARD = 0
|
|
63
|
+
GAMEPAD_FIRST = 1
|
|
64
|
+
MAX_GAMEPADS = 4
|
|
65
|
+
|
|
66
|
+
# The device id for a player slot: gamepad(0) is the first controller.
|
|
67
|
+
def self.gamepad(slot) = GAMEPAD_FIRST + slot
|
|
68
|
+
|
|
69
|
+
# --- Default bindings ---
|
|
70
|
+
#
|
|
71
|
+
# Symbolic action => physical input. Games override these to rebind; they
|
|
72
|
+
# are values, so a config screen can build its own table from the
|
|
73
|
+
# constants above and hand it to the input layer.
|
|
74
|
+
#
|
|
75
|
+
# Two button tables rather than one, because the same action is a
|
|
76
|
+
# different physical input per device class: :fire is the space bar on a
|
|
77
|
+
# keyboard and the A button on a pad.
|
|
78
|
+
DEFAULT_KEYBOARD = {
|
|
79
|
+
left: KEY_LEFT,
|
|
80
|
+
right: KEY_RIGHT,
|
|
81
|
+
up: KEY_UP,
|
|
82
|
+
down: KEY_DOWN,
|
|
83
|
+
confirm: KEY_RETURN,
|
|
84
|
+
fire: KEY_SPACE
|
|
85
|
+
}.freeze
|
|
86
|
+
|
|
87
|
+
DEFAULT_PAD = {
|
|
88
|
+
left: PAD_DPAD_LEFT,
|
|
89
|
+
right: PAD_DPAD_RIGHT,
|
|
90
|
+
up: PAD_DPAD_UP,
|
|
91
|
+
down: PAD_DPAD_DOWN,
|
|
92
|
+
confirm: PAD_A,
|
|
93
|
+
fire: PAD_A
|
|
94
|
+
}.freeze
|
|
95
|
+
|
|
96
|
+
# Analog axes exist only on pads, so there is one table.
|
|
97
|
+
DEFAULT_AXES = {
|
|
98
|
+
move_x: AXIS_LEFT_X,
|
|
99
|
+
move_y: AXIS_LEFT_Y,
|
|
100
|
+
aim_x: AXIS_RIGHT_X,
|
|
101
|
+
aim_y: AXIS_RIGHT_Y,
|
|
102
|
+
trigger_left: AXIS_TRIGGER_LEFT,
|
|
103
|
+
trigger_right: AXIS_TRIGGER_RIGHT
|
|
104
|
+
}.freeze
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# RGame::Util::Tensor is implemented in C — see ext/rgame_util/tensor.c. It used
|
|
4
|
+
# to be a pure-Ruby class here; the public API (RGame::Util::Tensor.new(width,
|
|
5
|
+
# height, depth, initial: nil), #[], #[]=, #width/#height/#depth) is unchanged,
|
|
6
|
+
# only the backing implementation moved to C for speed and a compact flat-array
|
|
7
|
+
# layout.
|
|
8
|
+
#
|
|
9
|
+
# The compiled extension is a separate .so from the SDL/GL engine, so requiring
|
|
10
|
+
# Tensor pulls in no graphics libraries. It loads from lib/rgame/util_ext.so,
|
|
11
|
+
# which the build (`make ext-util`) copies out of ext/rgame_util/.
|
|
12
|
+
require 'rgame/util_ext'
|
data/lib/rgame/util.rb
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# RGame::Util — everything that does NOT depend on SDL, OpenGL, or anything
|
|
4
|
+
# built on them. Backed by the graphics-free extension in ext/rgame_util/.
|
|
5
|
+
# Its counterpart is RGame::Core (see lib/rgame/core.rb).
|
|
6
|
+
require_relative 'util/color'
|
|
7
|
+
require_relative 'util/controls'
|
|
8
|
+
require_relative 'util/tensor'
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# The gem's version, and deliberately nothing else.
|
|
4
|
+
#
|
|
5
|
+
# rgame.gemspec loads this file directly to fill in `spec.version`, which
|
|
6
|
+
# happens before either extension is compiled — so this file must never require
|
|
7
|
+
# anything that reaches for `rgame/util_ext` or `rgame/core_ext`. Reopening the
|
|
8
|
+
# module here is enough; the extensions define `RGame` too, and doing so twice
|
|
9
|
+
# is harmless.
|
|
10
|
+
module RGame
|
|
11
|
+
VERSION = '0.1.0'
|
|
12
|
+
end
|
data/lib/rgame.rb
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Entry point for `require "rgame"`: everything that runs without a window.
|
|
4
|
+
#
|
|
5
|
+
# require 'rgame' # RGame::Util + RGame::Engine — no graphics libraries
|
|
6
|
+
# require 'rgame/core' # adds the window, the GPU and the sound device
|
|
7
|
+
# require 'rgame/game' # all of it, wired together
|
|
8
|
+
#
|
|
9
|
+
# Each line is a strict superset of the one above, and the split is the point.
|
|
10
|
+
# **This one loads no SDL and no OpenGL** — `RGame::Util` is a graphics-free
|
|
11
|
+
# extension and `RGame::Engine` is pure Ruby — so game logic and the specs that
|
|
12
|
+
# cover it run with no display present. `spec/rgame/no_graphics_spec.rb` holds
|
|
13
|
+
# that up rather than leaving it to good intentions.
|
|
14
|
+
#
|
|
15
|
+
# Nothing is forced through this file. `rgame/util`, `rgame/engine` and
|
|
16
|
+
# `rgame/core` are separately requirable, which is how the Core spec suite loads
|
|
17
|
+
# exactly one layer and gets a `NameError` if it reaches for another.
|
|
18
|
+
require_relative 'rgame/version'
|
|
19
|
+
require_relative 'rgame/util'
|
|
20
|
+
require_relative 'rgame/engine'
|
metadata
ADDED
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rgame
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Paul Süßenbach
|
|
8
|
+
bindir: bin
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
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.
|
|
17
|
+
|
|
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.
|
|
23
|
+
email:
|
|
24
|
+
- 2452696+psuessenb@users.noreply.github.com
|
|
25
|
+
executables: []
|
|
26
|
+
extensions:
|
|
27
|
+
- ext/rgame_core/extconf.rb
|
|
28
|
+
- ext/rgame_util/extconf.rb
|
|
29
|
+
extra_rdoc_files: []
|
|
30
|
+
files:
|
|
31
|
+
- LICENSE
|
|
32
|
+
- README.md
|
|
33
|
+
- docs/api/README.md
|
|
34
|
+
- docs/api/app.md
|
|
35
|
+
- docs/api/assets.md
|
|
36
|
+
- docs/api/audio.md
|
|
37
|
+
- docs/api/components.md
|
|
38
|
+
- docs/api/drawing.md
|
|
39
|
+
- docs/api/game.md
|
|
40
|
+
- docs/api/images.md
|
|
41
|
+
- docs/api/input.md
|
|
42
|
+
- docs/api/internals.md
|
|
43
|
+
- docs/api/scene_graph.md
|
|
44
|
+
- docs/api/signals.md
|
|
45
|
+
- docs/api/systems.md
|
|
46
|
+
- docs/api/text.md
|
|
47
|
+
- docs/api/toolbox.md
|
|
48
|
+
- docs/api/values.md
|
|
49
|
+
- ext/README.md
|
|
50
|
+
- ext/rgame_core/app/app.c
|
|
51
|
+
- ext/rgame_core/app/app_gl.h
|
|
52
|
+
- ext/rgame_core/app/frame_loop.c
|
|
53
|
+
- ext/rgame_core/app/frame_loop.h
|
|
54
|
+
- ext/rgame_core/audio/audio.c
|
|
55
|
+
- ext/rgame_core/audio/audio_internal.h
|
|
56
|
+
- ext/rgame_core/audio/vorbis_decoder.c
|
|
57
|
+
- ext/rgame_core/audio/vorbis_decoder.h
|
|
58
|
+
- ext/rgame_core/example.rb
|
|
59
|
+
- ext/rgame_core/extconf.rb
|
|
60
|
+
- ext/rgame_core/graphics/backend.c
|
|
61
|
+
- ext/rgame_core/graphics/backend.h
|
|
62
|
+
- ext/rgame_core/graphics/canvas.c
|
|
63
|
+
- ext/rgame_core/graphics/canvas.h
|
|
64
|
+
- ext/rgame_core/graphics/clip.c
|
|
65
|
+
- ext/rgame_core/graphics/clip.h
|
|
66
|
+
- ext/rgame_core/graphics/draw_queue.c
|
|
67
|
+
- ext/rgame_core/graphics/draw_queue.h
|
|
68
|
+
- ext/rgame_core/graphics/gl_backend.c
|
|
69
|
+
- ext/rgame_core/graphics/gl_backend.h
|
|
70
|
+
- ext/rgame_core/graphics/image.c
|
|
71
|
+
- ext/rgame_core/graphics/image_internal.h
|
|
72
|
+
- ext/rgame_core/graphics/primitives.c
|
|
73
|
+
- ext/rgame_core/graphics/primitives.h
|
|
74
|
+
- ext/rgame_core/graphics/recording.c
|
|
75
|
+
- ext/rgame_core/graphics/recording.h
|
|
76
|
+
- ext/rgame_core/graphics/texture.c
|
|
77
|
+
- ext/rgame_core/graphics/texture.h
|
|
78
|
+
- ext/rgame_core/graphics/transform.c
|
|
79
|
+
- ext/rgame_core/graphics/transform.h
|
|
80
|
+
- ext/rgame_core/include/rgame/core.h
|
|
81
|
+
- ext/rgame_core/input/device_slots.c
|
|
82
|
+
- ext/rgame_core/input/device_slots.h
|
|
83
|
+
- ext/rgame_core/input/gamepad.c
|
|
84
|
+
- ext/rgame_core/input/gamepad.h
|
|
85
|
+
- ext/rgame_core/input/input.c
|
|
86
|
+
- ext/rgame_core/input/input.h
|
|
87
|
+
- ext/rgame_core/ruby/audio_ext.c
|
|
88
|
+
- ext/rgame_core/ruby/core_ext.c
|
|
89
|
+
- ext/rgame_core/ruby/core_ext.h
|
|
90
|
+
- ext/rgame_core/ruby/font_ext.c
|
|
91
|
+
- ext/rgame_core/ruby/image_ext.c
|
|
92
|
+
- ext/rgame_core/ruby/recording_ext.c
|
|
93
|
+
- ext/rgame_core/ruby/renderer_ext.c
|
|
94
|
+
- ext/rgame_core/text/atlas.c
|
|
95
|
+
- ext/rgame_core/text/atlas.h
|
|
96
|
+
- ext/rgame_core/text/font.c
|
|
97
|
+
- ext/rgame_core/text/font.h
|
|
98
|
+
- ext/rgame_core/text/font_atlas.c
|
|
99
|
+
- ext/rgame_core/text/font_internal.h
|
|
100
|
+
- ext/rgame_core/text/glyph_cache.c
|
|
101
|
+
- ext/rgame_core/text/glyph_cache.h
|
|
102
|
+
- ext/rgame_core/vendor/README.md
|
|
103
|
+
- ext/rgame_core/vendor/miniaudio.h
|
|
104
|
+
- ext/rgame_core/vendor/miniaudio_impl.c
|
|
105
|
+
- ext/rgame_core/vendor/stb_image.h
|
|
106
|
+
- ext/rgame_core/vendor/stb_image_impl.c
|
|
107
|
+
- ext/rgame_core/vendor/stb_truetype.h
|
|
108
|
+
- ext/rgame_core/vendor/stb_truetype_impl.c
|
|
109
|
+
- ext/rgame_core/vendor/stb_vorbis.c
|
|
110
|
+
- ext/rgame_core/vendor/stb_vorbis_impl.c
|
|
111
|
+
- ext/rgame_util/color.c
|
|
112
|
+
- ext/rgame_util/color.h
|
|
113
|
+
- ext/rgame_util/color_ext.c
|
|
114
|
+
- ext/rgame_util/extconf.rb
|
|
115
|
+
- ext/rgame_util/tensor.c
|
|
116
|
+
- ext/rgame_util/util_ext.c
|
|
117
|
+
- ext/rgame_util/util_ext.h
|
|
118
|
+
- lib/rgame.rb
|
|
119
|
+
- lib/rgame/boot.rb
|
|
120
|
+
- lib/rgame/core.rb
|
|
121
|
+
- lib/rgame/core/app.rb
|
|
122
|
+
- lib/rgame/core/asset_manager.rb
|
|
123
|
+
- lib/rgame/core/audio.rb
|
|
124
|
+
- lib/rgame/core/font.rb
|
|
125
|
+
- lib/rgame/core/gamepad.rb
|
|
126
|
+
- lib/rgame/core/image.rb
|
|
127
|
+
- lib/rgame/core/input.rb
|
|
128
|
+
- lib/rgame/core/nine_slice.rb
|
|
129
|
+
- lib/rgame/core/recording.rb
|
|
130
|
+
- lib/rgame/core/renderer.rb
|
|
131
|
+
- lib/rgame/core/sprite_sheet.rb
|
|
132
|
+
- lib/rgame/core/tile_map_renderer.rb
|
|
133
|
+
- lib/rgame/core/ui_atlas.rb
|
|
134
|
+
- lib/rgame/engine.rb
|
|
135
|
+
- lib/rgame/engine/actor.rb
|
|
136
|
+
- lib/rgame/engine/animation_set.rb
|
|
137
|
+
- lib/rgame/engine/animator.rb
|
|
138
|
+
- lib/rgame/engine/audio_bus.rb
|
|
139
|
+
- lib/rgame/engine/audio_director.rb
|
|
140
|
+
- lib/rgame/engine/body.rb
|
|
141
|
+
- lib/rgame/engine/cached_label.rb
|
|
142
|
+
- lib/rgame/engine/camera.rb
|
|
143
|
+
- lib/rgame/engine/camera_view.rb
|
|
144
|
+
- lib/rgame/engine/circle_collider.rb
|
|
145
|
+
- lib/rgame/engine/collision_box.rb
|
|
146
|
+
- lib/rgame/engine/collision_system.rb
|
|
147
|
+
- lib/rgame/engine/component.rb
|
|
148
|
+
- lib/rgame/engine/components/action_trigger.rb
|
|
149
|
+
- lib/rgame/engine/components/animated_sprite.rb
|
|
150
|
+
- lib/rgame/engine/components/character_body.rb
|
|
151
|
+
- lib/rgame/engine/components/circle_collider.rb
|
|
152
|
+
- lib/rgame/engine/components/collision_world.rb
|
|
153
|
+
- lib/rgame/engine/components/despawn_offscreen.rb
|
|
154
|
+
- lib/rgame/engine/components/path_follow.rb
|
|
155
|
+
- lib/rgame/engine/components/player_controller.rb
|
|
156
|
+
- lib/rgame/engine/components/pool.rb
|
|
157
|
+
- lib/rgame/engine/components/screen_wrap.rb
|
|
158
|
+
- lib/rgame/engine/components/sprite.rb
|
|
159
|
+
- lib/rgame/engine/components/targeting.rb
|
|
160
|
+
- lib/rgame/engine/components/thrust_controller.rb
|
|
161
|
+
- lib/rgame/engine/components/tile_world.rb
|
|
162
|
+
- lib/rgame/engine/components/timer.rb
|
|
163
|
+
- lib/rgame/engine/components/velocity.rb
|
|
164
|
+
- lib/rgame/engine/components/wander_controller.rb
|
|
165
|
+
- lib/rgame/engine/debug_overlay.rb
|
|
166
|
+
- lib/rgame/engine/i18n.rb
|
|
167
|
+
- lib/rgame/engine/input/action_mapper.rb
|
|
168
|
+
- lib/rgame/engine/input/actions.rb
|
|
169
|
+
- lib/rgame/engine/input/player_controller.rb
|
|
170
|
+
- lib/rgame/engine/matrix.rb
|
|
171
|
+
- lib/rgame/engine/node2d.rb
|
|
172
|
+
- lib/rgame/engine/path.rb
|
|
173
|
+
- lib/rgame/engine/pool.rb
|
|
174
|
+
- lib/rgame/engine/resettable.rb
|
|
175
|
+
- lib/rgame/engine/scene/scene_stack.rb
|
|
176
|
+
- lib/rgame/engine/signal.rb
|
|
177
|
+
- lib/rgame/engine/spatial_hash.rb
|
|
178
|
+
- lib/rgame/engine/tile_collision.rb
|
|
179
|
+
- lib/rgame/engine/tile_map.rb
|
|
180
|
+
- lib/rgame/engine/tileset.rb
|
|
181
|
+
- lib/rgame/engine/timer.rb
|
|
182
|
+
- lib/rgame/fonts/LiberationSans-Regular.ttf
|
|
183
|
+
- lib/rgame/fonts/OFL.txt
|
|
184
|
+
- lib/rgame/game.rb
|
|
185
|
+
- lib/rgame/util.rb
|
|
186
|
+
- lib/rgame/util/color.rb
|
|
187
|
+
- lib/rgame/util/controls.rb
|
|
188
|
+
- lib/rgame/util/tensor.rb
|
|
189
|
+
- lib/rgame/version.rb
|
|
190
|
+
homepage: https://github.com/psuessenb/rgame
|
|
191
|
+
licenses:
|
|
192
|
+
- MIT
|
|
193
|
+
metadata:
|
|
194
|
+
source_code_uri: https://github.com/psuessenb/rgame
|
|
195
|
+
bug_tracker_uri: https://github.com/psuessenb/rgame/issues
|
|
196
|
+
documentation_uri: https://github.com/psuessenb/rgame/blob/main/docs/api/README.md
|
|
197
|
+
rubygems_mfa_required: 'true'
|
|
198
|
+
rdoc_options: []
|
|
199
|
+
require_paths:
|
|
200
|
+
- lib
|
|
201
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
202
|
+
requirements:
|
|
203
|
+
- - ">="
|
|
204
|
+
- !ruby/object:Gem::Version
|
|
205
|
+
version: '4.0'
|
|
206
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
207
|
+
requirements:
|
|
208
|
+
- - ">="
|
|
209
|
+
- !ruby/object:Gem::Version
|
|
210
|
+
version: '0'
|
|
211
|
+
requirements: []
|
|
212
|
+
rubygems_version: 4.0.10
|
|
213
|
+
specification_version: 4
|
|
214
|
+
summary: A 2D game engine in C on SDL2 and OpenGL, exposed to Ruby.
|
|
215
|
+
test_files: []
|