Class: SFML::App
Overview
Subclass-friendly main loop. Removes the boilerplate of window creation, event pumping, clock management, and clear/display so a small app fits in a few methods.
class MyApp < SFML::App
antialiasing 4 # class-level config — applies to every instance
framerate 120
background SFML::Color.new(18, 20, 28)
def setup
@ball = SFML::CircleShape.new(radius: 30, position: [200, 200],
fill_color: SFML::Color.white)
end
def update(dt)
@ball.move([60 * dt.as_seconds, 30 * dt.as_seconds])
end
def draw
window.draw(@ball)
end
end
MyApp.new(title: "Hello").run
The loop auto-handles :closed and :key_pressed/:escape by calling #quit; everything else is forwarded to #on_event. Override that to handle keys, mouse, etc.
## Configuration
Every constructor kwarg is also a class-level macro: declare defaults with ‘antialiasing 4` etc. inside the class body, and `MyApp.new` picks them up. Per-instance kwargs still win on a case-by-case basis. Subclasses inherit their parent’s settings — set one in a base class, override in a subclass.
Constant Summary collapse
- CONFIG_KEYS =
%i[ width height title framerate vsync background style fullscreen antialiasing context ].freeze
Instance Attribute Summary collapse
-
#background_color ⇒ Object
Returns the value of attribute background_color.
-
#current_scene ⇒ Object
readonly
—- Scenes —-.
-
#window ⇒ Object
readonly
Returns the value of attribute window.
Class Method Summary collapse
-
.initial_scene(klass = nil) ⇒ Object
Set the scene class the app should switch into automatically at ‘setup` time.
Instance Method Summary collapse
- #draw ⇒ Object
- #height ⇒ Object
-
#initialize(**opts) ⇒ App
constructor
Per-instance kwargs override anything set at the class level.
-
#on_event(event) ⇒ Object
The framework consumes: * ‘:closed` — closes the window (always) * `:resized` — forwarded to `on_resize` * `:key_pressed` whose code matches a scene- or app-level `on_key` binding Everything else lands here.
-
#on_resize(width, height) ⇒ Object
Default: forward to the current scene.
-
#pause ⇒ Object
—- Pause / resume —-.
- #paused? ⇒ Boolean
-
#quit ⇒ Object
Close the window.
- #resume ⇒ Object
-
#run ⇒ Object
The main entry point.
-
#setup ⇒ Object
—- Override these in subclasses ————————————–.
-
#switch_to(scene_or_class) ⇒ Object
Activate ‘scene_or_class`.
-
#teardown ⇒ Object
Called once after the main loop exits.
- #toggle_pause ⇒ Object
- #update(dt) ⇒ Object
-
#width ⇒ Object
Width and height shortcuts that always reflect the current window size — matters once the user is allowed to resize.
Methods included from Keybindings
Constructor Details
#initialize(**opts) ⇒ App
Per-instance kwargs override anything set at the class level. Anything not given here OR at the class level falls back to the hard-coded defaults below.
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
# File 'lib/sfml/app.rb', line 83 def initialize(**opts) cfg = self.class width = opts[:width] || cfg.width || 800 height = opts[:height] || cfg.height || 600 title = opts[:title] || cfg.title || cfg.name framerate = opts[:framerate] || cfg.framerate || 60 vsync = opts.fetch(:vsync, cfg.vsync) background = opts[:background] || cfg.background || Color::BLACK style = opts.fetch(:style, cfg.style) fullscreen = opts.fetch(:fullscreen, cfg.fullscreen) fullscreen = false if fullscreen.nil? antialiasing = opts.fetch(:antialiasing, cfg.antialiasing) context = opts.fetch(:context, cfg.context) window_opts = { framerate: framerate, fullscreen: fullscreen } window_opts[:vsync] = vsync unless vsync.nil? window_opts[:style] = style unless style.nil? window_opts[:antialiasing] = antialiasing unless antialiasing.nil? window_opts[:context] = context unless context.nil? @window = RenderWindow.new(width, height, title, **window_opts) @background_color = background end |
Instance Attribute Details
#background_color ⇒ Object
Returns the value of attribute background_color.
78 79 80 |
# File 'lib/sfml/app.rb', line 78 def background_color @background_color end |
#current_scene ⇒ Object (readonly)
—- Scenes —-
‘current_scene` is whatever the app last activated via `switch_to`. When non-nil, App’s default ‘update` / `draw` / `on_event` / `on_resize` forward to it; key bindings on the scene class shadow ones on the app class while the scene is active.
128 129 130 |
# File 'lib/sfml/app.rb', line 128 def current_scene @current_scene end |
#window ⇒ Object (readonly)
Returns the value of attribute window.
77 78 79 |
# File 'lib/sfml/app.rb', line 77 def window @window end |
Class Method Details
.initial_scene(klass = nil) ⇒ Object
Set the scene class the app should switch into automatically at ‘setup` time. Inheritable: a subclass that doesn’t set one inherits the parent’s choice.
70 71 72 73 74 |
# File 'lib/sfml/app.rb', line 70 def initial_scene(klass = nil) @initial_scene = klass if klass return @initial_scene if instance_variable_defined?(:@initial_scene) superclass.respond_to?(:initial_scene) ? superclass.initial_scene : nil end |
Instance Method Details
#draw ⇒ Object
192 193 194 |
# File 'lib/sfml/app.rb', line 192 def draw @current_scene&.draw end |
#height ⇒ Object
111 |
# File 'lib/sfml/app.rb', line 111 def height = @window.size.y |
#on_event(event) ⇒ Object
The framework consumes:
* `:closed` — closes the window (always)
* `:resized` — forwarded to `on_resize`
* `:key_pressed` whose code matches a scene- or app-level
`on_key` binding
Everything else lands here. Override to handle game-specific input. By default forwards to the current scene’s ‘on_event`.
203 204 205 |
# File 'lib/sfml/app.rb', line 203 def on_event(event) @current_scene&.on_event(event) end |
#on_resize(width, height) ⇒ Object
Default: forward to the current scene. Override to additionally do app-wide layout fixups; call ‘super` to keep the scene in the loop.
210 211 212 |
# File 'lib/sfml/app.rb', line 210 def on_resize(width, height) @current_scene&.on_resize(width, height) end |
#pause ⇒ Object
—- Pause / resume —-
While paused, ‘update(dt)` is not called — the world stops advancing. `draw` keeps running so the window still updates (handy for pause overlays that need to be drawn over a frozen scene).
153 |
# File 'lib/sfml/app.rb', line 153 def pause = (@paused = true) |
#paused? ⇒ Boolean
156 |
# File 'lib/sfml/app.rb', line 156 def paused? = @paused == true |
#quit ⇒ Object
Close the window. The main loop exits at the start of the next frame.
115 116 117 118 |
# File 'lib/sfml/app.rb', line 115 def quit @window.close self end |
#resume ⇒ Object
154 |
# File 'lib/sfml/app.rb', line 154 def resume = (@paused = false) |
#run ⇒ Object
The main entry point. Calls #setup once, then runs the per-frame loop until the window closes.
160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/sfml/app.rb', line 160 def run setup clock = Clock.new while @window.open? dt = clock.restart @window.each_event { |event| _dispatch(event) } update(dt) unless paused? @window.clear(@background_color) draw @window.display end teardown self end |
#setup ⇒ Object
—- Override these in subclasses ————————————–
Defaults forward to the current scene when one is active. The ‘initial_scene` class macro auto-instantiates a scene at `setup` time so subclasses with `initial_scene Foo` don’t have to define ‘setup` themselves.
182 183 184 185 186 |
# File 'lib/sfml/app.rb', line 182 def setup if (klass = self.class.initial_scene) switch_to(klass) end end |
#switch_to(scene_or_class) ⇒ Object
Activate ‘scene_or_class`. Tears down the previous scene before calling `setup` on the new one. Accepts either:
* a Scene subclass — instantiated with `self` as host
* an existing Scene instance — used as-is
134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/sfml/app.rb', line 134 def switch_to(scene_or_class) new_scene = case scene_or_class when Class then scene_or_class.new(self) else scene_or_class end @current_scene&.teardown @current_scene = new_scene @current_scene&.setup @current_scene end |
#teardown ⇒ Object
Called once after the main loop exits. Tears down the active scene by default.
216 217 218 |
# File 'lib/sfml/app.rb', line 216 def teardown @current_scene&.teardown end |
#toggle_pause ⇒ Object
155 |
# File 'lib/sfml/app.rb', line 155 def toggle_pause = (@paused = !paused?) |
#update(dt) ⇒ Object
188 189 190 |
# File 'lib/sfml/app.rb', line 188 def update(dt) @current_scene&.update(dt) end |
#width ⇒ Object
Width and height shortcuts that always reflect the current window size — matters once the user is allowed to resize.
110 |
# File 'lib/sfml/app.rb', line 110 def width = @window.size.x |