diff --git a/app/classes/scene_instance.rb b/app/classes/scene_instance.rb index c04797d..bbd3ad7 100644 --- a/app/classes/scene_instance.rb +++ b/app/classes/scene_instance.rb @@ -4,9 +4,11 @@ class SceneInstance def initialize(_args, opts = {}) @tick_in_background = opts.tick_in_background._? false + @reset_on_pop = opts.reset_on_pop._? false end attr_reader :tick_in_background + attr_accessor :reset_on_pop # called every tick of the game loop def tick(args) end diff --git a/app/constants.rb b/app/constants.rb index 320eadc..b5449d2 100644 --- a/app/constants.rb +++ b/app/constants.rb @@ -26,7 +26,7 @@ ORANGE = { r: 255, g: 173, b: 31 } PINK = { r: 245, g: 146, b: 198 } PURPLE = { r: 133, g: 42, b: 216 } RED = { r: 231, g: 89, b: 82 } -YELLOW = { r: 240, g: 232, b: 89 } +YELLOW = { r: 255, g: 200, b: 5 } DARK_BLUE = { r: 22, g: 122, b: 188 } DARK_GREEN = { r: 5, g: 84, b: 12 } diff --git a/app/scenes/main_menu.rb b/app/scenes/main_menu.rb index 93a7683..9f80ff1 100644 --- a/app/scenes/main_menu.rb +++ b/app/scenes/main_menu.rb @@ -11,7 +11,7 @@ class MainMenu < MenuScene }, { key: :settings, - on_select: ->(iargs) { Scene.push(iargs, :settings, reset: true) } + on_select: ->(iargs) { Scene.push(iargs, :settings, reset: true, reset_on_pop: true) } } ] @@ -22,13 +22,11 @@ class MainMenu < MenuScene } end - super args, opts, menu_options + super args, opts, title, menu_options end # called every tick of the game loop def tick(args) - draw_bg(args, DARK_PURPLE) - # actual menu logic is handled by the MenuScene super class super @@ -36,28 +34,30 @@ class MainMenu < MenuScene labels = [] labels << label( "v#{version}", - x: 32.from_left, y: 32.from_top, - size: SIZE_XS, align: ALIGN_LEFT - ) - labels << label( - title.upcase, x: args.grid.w / 2, y: args.grid.top - 100, - size: SIZE_LG, align: ALIGN_CENTER, font: FONT_BOLD_ITALIC - ) + x: 400.from_right, y: 150.from_bottom, + size: SIZE_XS, align: ALIGN_RIGHT, + font: FONT_DOTMATRIX + ).merge(YELLOW) + # labels << label( + # title.upcase, x: args.grid.w / 2, y: args.grid.top - 100, + # size: SIZE_LG, align: ALIGN_CENTER, font: FONT_BOLD_ITALIC + # ) labels << label( "#{text(:made_by)} #{dev_title}", - x: args.grid.left + 24, y: 48, - size: SIZE_XS, align: ALIGN_LEFT - ) - labels << label( - :controls_title, - x: args.grid.right - 24, y: 84, - size: SIZE_SM, align: ALIGN_RIGHT - ) - labels << label( - args.inputs.controller_one.connected ? :controls_gamepad : :controls_keyboard, - x: args.grid.right - 24, y: 48, - size: SIZE_XS, align: ALIGN_RIGHT - ) + x: 242.from_left, y: 150.from_bottom, + size: SIZE_XS, align: ALIGN_LEFT, + font: FONT_DOTMATRIX + ).merge(YELLOW) + # labels << label( + # :controls_title, + # x: args.grid.right - 24, y: 84, + # size: SIZE_SM, align: ALIGN_RIGHT + # ) + # labels << label( + # args.inputs.controller_one.connected ? :controls_gamepad : :controls_keyboard, + # x: args.grid.right - 24, y: 48, + # size: SIZE_XS, align: ALIGN_RIGHT + # ) args.outputs.labels << labels end diff --git a/app/scenes/menu.rb b/app/scenes/menu.rb index e0a6fc3..aa38b80 100644 --- a/app/scenes/menu.rb +++ b/app/scenes/menu.rb @@ -10,21 +10,28 @@ # } # ] class MenuScene < SceneInstance - def initialize(args, opts = {}, menu_options = []) + def initialize(args, opts = {}, title = title(), menu_options = []) super args, opts @menu_state ||= { current_option_i: 0, hold_delay: 0 } - @spacer ||= mobile? ? 100 : 60 + @spacer ||= mobile? ? 100 : 80 @menu_options ||= menu_options - @menu_y = opts.menu_y._?(420) + @menu_y = opts.menu_y._?(440) + @title ||= title + @rand_strings = (0..@menu_options.length).map do |i| + (0...@title.length).map { ('A'..'Z').to_a[rand(26)] }.join + end + @first_render = nil end def render_options(args) labels = [] @menu_options.each.with_index do |option, i| + active = @menu_state.current_option_i == i && (!mobile? || (mobile? && args.inputs.controller_one.connected)) + text = case option.kind when :toggle "#{text(option[:key])}: #{text_for_setting_val(args, option[:key])}" @@ -32,24 +39,36 @@ class MenuScene < SceneInstance text(option[:key]) end + if (args.state.tick_count - @first_render) < 60 * (1.5 + i) * 0.2 + if args.state.tick_count % 4 == 0 + @rand_strings[i] = (0...(rand(text.length >= 3 ? text.length : 3) + 3)).map { ('A'..'Z').to_a[rand(26)] }.join + end + text = @rand_strings[i] + active = false + end + l = label( - text, - x: args.grid.w / 2, + text.upcase, + x: (args.grid.w / 2) - 70, y: @menu_y + (@menu_options.length - (i * @spacer)), align: ALIGN_CENTER, - size: SIZE_MD + size: 16, + font: FONT_DOTMATRIX_BOLD ) l.key = option[:key] - l.width, l.height = args.gtk.calcstringbox(l.text, l.size_enum) - labels << l + l.width, l.height = args.gtk.calcstringbox(l.text, l.size_enum, l.font) - if @menu_state.current_option_i == i && (!mobile? || (mobile? && args.inputs.controller_one.connected)) - args.outputs.solids << { - x: l.x - (l.width / 1.4) - 24 + (Math.sin(args.state.tick_count / 8) * 4), - y: l.y - 22, - w: 16, - h: 16 - }.merge(WHITE) + labels << l.merge(active ? WHITE : YELLOW) + + if active + labels << label( + '.', + x: l.x - (l.width / 2) - 26 - (Math.sin(args.state.tick_count / 8) * 4), + y: l.y + 15, + align: ALIGN_CENTER, + size: 18, + font: FONT_DOTMATRIX + ).merge(WHITE) end button_border = { w: 340, h: 80, x: l.x - 170, y: l.y - 55 }.merge(WHITE) @@ -67,6 +86,18 @@ class MenuScene < SceneInstance # called every tick of the game loop def tick(args) super + @first_render = args.state.tick_count if @first_render.nil? + + Sprite.for(:menu).render(args) + + args.outputs.labels << label( + @title.to_s.upcase, + x: (args.grid.w / 2) - 70, + y: args.grid.top - 175, + align: ALIGN_CENTER, + size: SIZE_LG, + font: FONT_RUBIK_BLACK + ).merge(TRUE_BLACK) render_options(args) @@ -118,6 +149,7 @@ class MenuScene < SceneInstance @menu_state.current_option_i = 0 @menu_state.hold_delay = 0 + @first_render = nil end def text_for_setting_val(args, key) diff --git a/app/scenes/paused.rb b/app/scenes/paused.rb index 33967ff..f30812d 100644 --- a/app/scenes/paused.rb +++ b/app/scenes/paused.rb @@ -11,11 +11,11 @@ class PauseMenu < MenuScene }, { key: :settings, - on_select: ->(args) { Scene.push(args, :settings, reset: true) } + on_select: ->(args) { Scene.push(args, :settings, reset: true, reset_on_pop: true) } }, { key: :return_to_main_menu, - on_select: ->(args) { Scene.switch(args, :main_menu) } + on_select: ->(args) { Scene.switch(args, :main_menu, reset: true) } } ] @@ -26,21 +26,12 @@ class PauseMenu < MenuScene } end - super args, opts, menu_options + super args, opts, :paused, menu_options end # called every tick of the game loop def tick(args) super Music.pause(args) unless Music.stopped(args) || Music.paused(args) - - args.outputs.labels << label( - :paused, - x: args.grid.w / 2, - y: args.grid.top - 200, - align: ALIGN_CENTER, - size: SIZE_LG, - font: FONT_BOLD - ) end end diff --git a/app/scenes/settings.rb b/app/scenes/settings.rb index 4ea08f6..5b06bca 100644 --- a/app/scenes/settings.rb +++ b/app/scenes/settings.rb @@ -45,7 +45,7 @@ class SettingsMenu < MenuScene ) end - super args, opts, menu_options + super args, opts, :settings, menu_options end # called every tick of the game loop @@ -54,14 +54,5 @@ class SettingsMenu < MenuScene # actual menu logic is handled by the MenuScene super class super - - args.outputs.labels << label( - :settings, - x: args.grid.w / 2, - y: args.grid.top - 200, - align: ALIGN_CENTER, - size: SIZE_LG, - font: FONT_BOLD - ) end end diff --git a/app/text.rb b/app/text.rb index d790904..b2b9e20 100644 --- a/app/text.rb +++ b/app/text.rb @@ -16,10 +16,11 @@ TEXT = { paused: "Paused", quit: "Quit", resume: "Resume", - return_to_main_menu: "Return to Main Menu", + return_to_main_menu: "Main Menu", settings: "Settings", sfx: "Sound Effects", start: "Start", + cube_tube: "Cube tube", } # Gets the text for the passed in `key`. Raises if it does not exist. We don't @@ -31,12 +32,15 @@ end SIZE_XS = 0 SIZE_SM = 4 SIZE_MD = 6 -SIZE_LG = 10 +SIZE_LG = 14 FONT_REGULAR = "fonts/Atkinson-Hyperlegible-Regular-102.ttf" FONT_ITALIC = "fonts/Atkinson-Hyperlegible-Italic-102.ttf" FONT_BOLD = "fonts/Atkinson-Hyperlegible-Bold-102.ttf" FONT_BOLD_ITALIC = "fonts/Atkinson-Hyperlegible-BoldItalic-102.ttf" +FONT_DOTMATRIX = "fonts/DotMatrix.ttf" +FONT_DOTMATRIX_BOLD = "fonts/DotMatrix-Bold.ttf" +FONT_RUBIK_BLACK = "fonts/Rubik-Black.ttf" # Friendly method with sensible defaults for creating DRGTK label data # structures. diff --git a/app/util/scene.rb b/app/util/scene.rb index f56656c..fe055db 100644 --- a/app/util/scene.rb +++ b/app/util/scene.rb @@ -40,8 +40,10 @@ module Scene end # Change the current scene by pushing it onto the scene stack - def push(args, scene, reset: false) + def push(args, scene, reset: false, reset_on_pop: false) args.state.scene_stack ||= [] + prev_scene = args.state.scene_stack.last + prev_scene.reset_on_pop = reset_on_pop unless prev_scene.nil? the_scene = scene.is_a?(SceneInstance) ? scene : SCENES[scene].new(args) args.state.scene_stack.push(the_scene) @@ -49,10 +51,14 @@ module Scene end # Return to the previous scene on the stack - def pop(args, reset: false) - scene = args.state.scene_stack&.pop + def pop(args, reset: nil) + args.state.scene_stack&.pop + scene = args.state.scene_stack.last + scene = scene._?(default(args)) + reset = scene.reset_on_pop if reset.nil? + puts reset, scene, scene.reset_on_pop - switch(args, scene._?(default(args)), reset: reset, push_or_pop: true) + switch(args, scene, reset: reset, push_or_pop: true) end def default(args) diff --git a/fonts/DotMatrix-Bold.ttf b/fonts/DotMatrix-Bold.ttf new file mode 100644 index 0000000..14d252b Binary files /dev/null and b/fonts/DotMatrix-Bold.ttf differ diff --git a/fonts/DotMatrix.ttf b/fonts/DotMatrix.ttf new file mode 100644 index 0000000..d81f879 Binary files /dev/null and b/fonts/DotMatrix.ttf differ diff --git a/fonts/Rubik-Black.ttf b/fonts/Rubik-Black.ttf new file mode 100644 index 0000000..698fd02 Binary files /dev/null and b/fonts/Rubik-Black.ttf differ diff --git a/sprites/_list.rb b/sprites/_list.rb index 026219d..b54f310 100644 --- a/sprites/_list.rb +++ b/sprites/_list.rb @@ -24,5 +24,6 @@ module Sprite screen_s2: SpriteInstance.new({ w: 250, h: 210, path: 'sprites/screen-s2.png' }), screen_s3: SpriteInstance.new({ w: 250, h: 210, path: 'sprites/screen-s3.png' }), screen_s4: SpriteInstance.new({ w: 250, h: 210, path: 'sprites/screen-s4.png' }), + menu: SpriteInstance.new({ w: 1280, h: 720, path: 'sprites/menu.png' }), } end diff --git a/sprites/menu.png b/sprites/menu.png new file mode 100644 index 0000000..3c2f422 Binary files /dev/null and b/sprites/menu.png differ diff --git a/wip-assets/sprites/menu.pdn b/wip-assets/sprites/menu.pdn new file mode 100644 index 0000000..85d00f9 Binary files /dev/null and b/wip-assets/sprites/menu.pdn differ diff --git a/wip-assets/sprites/subway-title.vox b/wip-assets/sprites/subway-title.vox new file mode 100644 index 0000000..22c7f30 Binary files /dev/null and b/wip-assets/sprites/subway-title.vox differ diff --git a/wip-assets/sprites/tunnel-half.vox b/wip-assets/sprites/tunnel-half.vox index 379b802..d09b6ca 100644 Binary files a/wip-assets/sprites/tunnel-half.vox and b/wip-assets/sprites/tunnel-half.vox differ