Implemented a lot of changes

(I really should commit more often)
Added graphics, sound, etc...
This commit is contained in:
Gordon Pedersen 2023-03-21 13:40:53 +11:00
parent 02572450c7
commit 1c863f9090
36 changed files with 179 additions and 62 deletions

View file

@ -13,13 +13,9 @@ module Scene
# changed to so any data is cleared out # changed to so any data is cleared out
# ex: # ex:
# Scene.switch(args, :gameplay) # Scene.switch(args, :gameplay)
def switch(args, scene, reset: false, return_to: nil) def switch(args, scene, reset: false, push_or_pop: false)
args.state.scene_to_return_to = return_to if return_to # if we're here /not/ from push or pop, clear the scene stack
args.state.scene_stack.clear unless push_or_pop
if scene == :back && args.state.scene_to_return_to
scene = args.state.scene_to_return_to
args.state.scene_to_return_to = nil
end
if reset if reset
args.state.send(scene)&.current_option_i = nil args.state.send(scene)&.current_option_i = nil
@ -30,7 +26,22 @@ module Scene
end end
args.state.scene = scene args.state.scene = scene
raise FinishTick.new raise FinishTick, 'finish tick early'
end
# Change the current scene and push the previous scene onto the stack
def push(args, scene, reset: false)
puts "Pushing #{scene}"
args.state.scene_stack ||= []
args.state.scene_stack.push(args.state.scene)
switch(args, scene, reset: reset, push_or_pop: true)
end
# Return to the previous scene on the stack
def pop(args, reset: false)
scene = !args.state.scene_stack || args.state.scene_stack.empty? ? :back : args.state.scene_stack.pop
switch(args, scene, reset: reset, push_or_pop: true)
end end
end end
end end

View file

@ -1,37 +1,33 @@
# frozen_string_literal: true
# Extension to the scene class for the cube tube scene
module Scene module Scene
class << self class << self
def tick_cube_tube(args) def tick_cube_tube(args)
# call the gameplay scene tick method (handles pause menu, etc)
tick_gameplay(args) tick_gameplay(args)
args.state.game ||= BlockTubeGame.new args args.state.game ||= CubeTubeGame.new args
args.state.game.tick args.state.game.tick
end end
end end
end end
#
class BlockTubeGame class CubeTubeGame
def initialize args def initialize args
@args = args @args = args
@blocksize = 30 @blocksize = 30
@grid_w = 10 @grid_w = 10
@grid_h = 20 @grid_h = 20
@grid_x = (720 - (@grid_w * @blocksize)) / 2 @grid_x = 115
@grid_y = ((1280 - (@grid_h * @blocksize)) / 2) + 150 @grid_y = ((1280 - (@grid_h * @blocksize)) / 2) + 143
@start_grid_x = @grid_x
@start_grid_y = @grid_y
@bg_x = 0
@bg_w = 1335
@next_piece_box = [-1, -9, 7, 7] @next_piece_box = [2, -9.5, 7, 7]
@color_index = [
[000, 000, 000],
[255, 000, 000],
[000, 255, 000],
[000, 000, 255],
[255, 255, 000],
[000, 255, 255],
[255, 000, 255],
[255, 127, 000],
[127, 127, 127],
]
@sprite_index = [ @sprite_index = [
Sprite.for(:black), Sprite.for(:black),
@ -61,12 +57,14 @@ class BlockTubeGame
@lines_to_clear = [] @lines_to_clear = []
@line_clear_timer = 0 @line_clear_timer = 0
@music_queue = []
reset_game reset_game
end end
def reset_game def reset_game
@lines = 0 @lines = 0
@level = 9 @level = 0
@current_speed = get_speed @current_speed = get_speed
@next_move = @current_speed @next_move = @current_speed
@gameover = false @gameover = false
@ -80,12 +78,16 @@ class BlockTubeGame
@lines_to_clear = [] @lines_to_clear = []
@line_clear_timer = 0 @line_clear_timer = 0
for x in 0..@grid_w-1 do @bg_x = 0
each 0..@grid_w - 1 do |x|
@grid[x] = [] @grid[x] = []
for y in 0..@grid_h-1 do each 0..@grid_h - 1 do |y|
@grid[x][y] = 0 @grid[x][y] = 0
end end
end end
@music_queue = [:music1, :music2]
end end
def render_grid_border x, y, w, h, color def render_grid_border x, y, w, h, color
@ -103,28 +105,54 @@ class BlockTubeGame
def render_background def render_background
# draw a solid black background # draw a solid black background
@args.outputs.solids << [ @args.outputs.solids << [
0, 0,
0, 0,
1280, 1280,
1280, 1280,
*@color_index[0] 0, 0, 0
]
@bg_x += (@level+1)*2 unless @gameover
if(@bg_x >= @bg_w)
@bg_x %= @bg_w
end
@args.outputs.sprites << [@bg_x,0,@bg_w,720,Sprite.for(:tunnel)]
@args.outputs.sprites << [@bg_x-@bg_w,0,@bg_w,720,Sprite.for(:tunnel)]
@args.outputs.sprites << [
0,
@grid_x - 64,
1597,
540,
Sprite.for(:train)
]
end
def render_foreground
@args.outputs.sprites << [
0,
@grid_x - 64,
1597,
540,
Sprite.for(:train_fore)
] ]
end end
# x and y are positions in the grid, not pixels # x and y are positions in the grid, not pixels
def render_block x, y, color def render_block x, y, color
@args.outputs.sprites << [ @args.outputs.sprites << [
(1280 - @grid_y) - (y * @blocksize), (1280 - @grid_y) - (y * @blocksize) - 6,
@grid_x + (x * @blocksize), @grid_x + (x * @blocksize),
@blocksize, @blocksize, @blocksize + 6, @blocksize,
@sprite_index[color] @sprite_index[color]
] ]
end end
def render_grid def render_grid
render_grid_border -1, -1, @grid_w + 2, @grid_h + 2, 8 #render_grid_border -1, -1, @grid_w + 2, @grid_h + 2, 8
for x in 0..@grid_w-1 do for x in 0..@grid_w-1 do
for y in 0..@grid_h-1 do for y in 0..@grid_h-1 do
@ -148,14 +176,41 @@ class BlockTubeGame
end end
def render_next_piece def render_next_piece
screen_x = @grid_y + 400
screen_y = @grid_x + 80
screen_w = 250
screen_h = 200
@args.outputs.sprites << [
screen_x, screen_y + 10, screen_w, screen_h + 10,
Sprite.for(:screen)
]
next_piece = @line_clear_timer <= 0 ? @next_piece : @current_piece next_piece = @line_clear_timer <= 0 ? @next_piece : @current_piece
render_grid_border *@next_piece_box, 8 # render_grid_border *@next_piece_box, 8
centerx = (@next_piece_box[2] - next_piece.length) / 2 centerx = (@next_piece_box[2] - next_piece.length) / 2
centery = (@next_piece_box[3] - next_piece[0].length) / 2 centery = (@next_piece_box[3] - next_piece[0].length) / 2
render_piece next_piece, @next_piece_box[0] + centerx, @next_piece_box[1] + centery render_piece next_piece, @next_piece_box[0] + centerx, @next_piece_box[1] + centery
@args.outputs.labels << [ 892, 431, "Next piece", 10, 255, 255, 255, 255 ] @args.outputs.labels << [screen_x + 33, screen_y + screen_h - 8, "Next piece", 8, 255, 255, 255, 255 ]
screen_s = case (@args.state.tick_count % 32)
when 0..7
:screen_s1
when 8..15
:screen_s2
when 16..23
:screen_s3
when 24..31
:screen_s4
end
@args.outputs.sprites << [
screen_x, screen_y + 10, screen_w, screen_h + 10,
Sprite.for(screen_s)
]
end end
def render_score def render_score
@ -174,6 +229,7 @@ class BlockTubeGame
render_next_piece render_next_piece
render_current_piece render_current_piece
render_grid render_grid
render_foreground
render_score render_score
render_gameover if @showgameover render_gameover if @showgameover
end end
@ -245,17 +301,23 @@ class BlockTubeGame
if full # no empty space in the row if full # no empty space in the row
@lines_to_clear.push y @lines_to_clear.push y
@lines += 1 @lines += 1
@level += 1 if (@lines%10).floor == 0
@line_clear_timer = 70 @line_clear_timer = 70
if (@lines%10).floor == 0
@level += 1
@args.audio[:music].looping = false
end
end end
end end
select_next_piece select_next_piece
if @lines_to_clear.empty? if @lines_to_clear.empty?
play_sfx(@args, :drop)
if current_piece_colliding if current_piece_colliding
@gameover = true @gameover = true
stop_music(@args)
end end
else else
play_sfx(@args, :clear)
@current_speed = get_speed @current_speed = get_speed
end end
@ -283,6 +345,7 @@ class BlockTubeGame
end end
def rotate_current_piece_left def rotate_current_piece_left
play_sfx(@args, :rotate)
@current_piece = @current_piece.transpose.map(&:reverse) @current_piece = @current_piece.transpose.map(&:reverse)
if(@current_piece_x + @current_piece.length) >= @grid_w if(@current_piece_x + @current_piece.length) >= @grid_w
@current_piece_x = @grid_w - @current_piece.length @current_piece_x = @grid_w - @current_piece.length
@ -290,6 +353,7 @@ class BlockTubeGame
end end
def rotate_current_piece_right def rotate_current_piece_right
play_sfx(@args, :rotate)
@current_piece = @current_piece.transpose.map(&:reverse) @current_piece = @current_piece.transpose.map(&:reverse)
@current_piece = @current_piece.transpose.map(&:reverse) @current_piece = @current_piece.transpose.map(&:reverse)
@current_piece = @current_piece.transpose.map(&:reverse) @current_piece = @current_piece.transpose.map(&:reverse)
@ -330,9 +394,18 @@ class BlockTubeGame
return return
end end
if @line_clear_timer > 0 if @args.audio[:music]
resume_music(@args) if @args.audio[:music].paused
@args.audio[:music].pitch = 1 + (@level * 0.125)
else
music = @music_queue.shift
@music_queue.push music
play_music(@args, music)
end
if @line_clear_timer.positive?
@line_clear_timer -= 1 @line_clear_timer -= 1
if @line_clear_timer == 0 if @line_clear_timer.zero?
for y in @lines_to_clear for y in @lines_to_clear
for i in y.downto(1) do for i in y.downto(1) do
for j in 0..@grid_w-1 for j in 0..@grid_w-1
@ -343,6 +416,7 @@ class BlockTubeGame
@grid[i][0] = 0 @grid[i][0] = 0
end end
end end
play_sfx(@args, :drop)
@lines_to_clear = [] @lines_to_clear = []
end end
return return
@ -352,21 +426,35 @@ class BlockTubeGame
if @current_piece_x > 0 if @current_piece_x > 0
@current_piece_x -= 1 @current_piece_x -= 1
if current_piece_colliding if current_piece_colliding
play_sfx(@args, :move_deny)
@current_piece_x += 1 @current_piece_x += 1
else
play_sfx(@args, :move)
end end
else
play_sfx(@args, :move_deny)
end end
end end
if k.key_down.up || k.key_down.w || c.key_down.up if k.key_down.up || k.key_down.w || c.key_down.up
if (@current_piece_x + @current_piece.length) < @grid_w if (@current_piece_x + @current_piece.length) < @grid_w
@current_piece_x += 1 @current_piece_x += 1
if current_piece_colliding if current_piece_colliding
play_sfx(@args, :move_deny)
@current_piece_x -= 1 @current_piece_x -= 1
else
play_sfx(@args, :move)
end end
else
play_sfx(@args, :move_deny)
end end
end end
if k.key_down.left || k.key_held.left || k.key_down.a || k.key_held.a || c.key_down.left || c.key_held.left if k.key_down.left || k.key_held.left || k.key_down.a || k.key_held.a || c.key_down.left || c.key_held.left
@next_move -= @current_speed / 3 @next_move -= @current_speed / 3
end end
if k.key_down.plus || k.key_down.equal_sign
@level += 1
@current_speed = get_speed
end
if k.key_down.q || c.key_down.a if k.key_down.q || c.key_down.a
rotate_current_piece_left rotate_current_piece_left
@ -375,6 +463,13 @@ class BlockTubeGame
rotate_current_piece_right rotate_current_piece_right
end end
case @args.state.tick_count % (@current_speed * 6)
when 0..3, (@current_speed * 2)..((@current_speed * 2) + 3)
@grid_x = @start_grid_x + 3
else
@grid_x = @start_grid_x
end
@next_move -= 1 @next_move -= 1
if @next_move <= 0 if @next_move <= 0
@next_move = @current_speed @next_move = @current_speed

View file

@ -28,7 +28,7 @@ module Scene
def pause(args) def pause(args)
play_sfx(args, :select) play_sfx(args, :select)
return Scene.switch(args, :paused, reset: true) return Scene.push(args, :paused, reset: true)
end end
def tick_pause_button(args, sprites) def tick_pause_button(args, sprites)

View file

@ -10,7 +10,7 @@ module Scene
}, },
{ {
key: :settings, key: :settings,
on_select: -> (args) { Scene.switch(args, :settings, reset: true, return_to: :main_menu) } on_select: -> (args) { Scene.push(args, :settings, reset: true) }
}, },
] ]

View file

@ -7,11 +7,11 @@ module Scene
options = [ options = [
{ {
key: :resume, key: :resume,
on_select: -> (args) { Scene.switch(args, :gameplay) } on_select: -> (args) { Scene.pop(args) }
}, },
{ {
key: :settings, key: :settings,
on_select: -> (args) { Scene.switch(args, :settings, reset: true, return_to: :paused) } on_select: -> (args) { Scene.push(args, :settings, reset: true) }
}, },
{ {
key: :return_to_main_menu, key: :return_to_main_menu,
@ -28,9 +28,14 @@ module Scene
Menu.tick(args, :paused, options) Menu.tick(args, :paused, options)
if args.audio[:music] && !args.audio[:music].paused
pause_music(args)
end
if secondary_down?(args.inputs) if secondary_down?(args.inputs)
play_sfx(args, :select) play_sfx(args, :select)
options.find { |o| o[:key] == :resume }[:on_select].call(args) options.find { |o| o[:key] == :resume }[:on_select].call(args)
end end
args.outputs.labels << label(:paused, x: args.grid.w / 2, y: args.grid.top - 200, align: ALIGN_CENTER, size: SIZE_LG, font: FONT_BOLD) args.outputs.labels << label(:paused, x: args.grid.w / 2, y: args.grid.top - 200, align: ALIGN_CENTER, size: SIZE_LG, font: FONT_BOLD)

View file

@ -29,7 +29,7 @@ module Scene
}, },
{ {
key: :back, key: :back,
on_select: -> (args) { Scene.switch(args, :back) } on_select: -> (args) { Scene.pop(args) }
}, },
] ]

View file

@ -28,3 +28,8 @@ end
def resume_music(args) def resume_music(args)
args.audio[:music].paused = false args.audio[:music].paused = false
end end
# stop the currently playing music track
def stop_music(args)
args.audio.delete(:music)
end

View file

@ -2,24 +2,25 @@ module Sprite
# annoying to track but useful for reloading with +i+ in debug mode; would be # annoying to track but useful for reloading with +i+ in debug mode; would be
# nice to define a different way # nice to define a different way
SPRITES = { SPRITES = {
bullet: 'sprites/bullet.png', train: 'sprites/train-1.png',
enemy: 'sprites/enemy.png', train_fore: 'sprites/train-2.png',
enemy_king: 'sprites/enemy_king.png', screen: 'sprites/screen.png',
enemy_super: 'sprites/enemy_super.png', screen_s1: 'sprites/screen-s1.png',
exp_chip: 'sprites/exp_chip.png', screen_s2: 'sprites/screen-s2.png',
familiar: 'sprites/familiar.png', screen_s3: 'sprites/screen-s3.png',
player: 'sprites/player.png', screen_s4: 'sprites/screen-s4.png',
tunnel: 'sprites/tunnel.png',
pause: 'sprites/pause.png', pause: 'sprites/pause.png',
gray: 'sprites/square/gray.png', gray: 'sprites/box/gray.png',
black: 'sprites/square/black.png', black: 'sprites/box/black.png',
white: 'sprites/square/white.png', white: 'sprites/box/white.png',
red: 'sprites/square/red.png', red: 'sprites/box/red.png',
green: 'sprites/square/green.png', green: 'sprites/box/green.png',
blue: 'sprites/square/blue.png', blue: 'sprites/box/blue.png',
yellow: 'sprites/square/yellow.png', yellow: 'sprites/box/yellow.png',
indigo: 'sprites/square/indigo.png', indigo: 'sprites/box/indigo.png',
violet: 'sprites/square/violet.png', violet: 'sprites/box/violet.png',
orange: 'sprites/square/orange.png' orange: 'sprites/box/orange.png'
} }
class << self class << self

View file

@ -11,7 +11,7 @@ def tick(args)
args.outputs.background_color = TRUE_BLACK.values args.outputs.background_color = TRUE_BLACK.values
args.state.has_focus ||= true args.state.has_focus ||= true
args.state.scene ||= :main_menu Scene.push(args, :main_menu, reset: true) if !args.state.scene
track_swipe(args) if mobile? track_swipe(args) if mobile?

BIN
sounds/clear.wav Normal file

Binary file not shown.

BIN
sounds/drop.wav Normal file

Binary file not shown.

Binary file not shown.

BIN
sounds/move.wav Normal file

Binary file not shown.

BIN
sounds/move_deny.wav Normal file

Binary file not shown.

BIN
sounds/music1.ogg Normal file

Binary file not shown.

BIN
sounds/music2.ogg Normal file

Binary file not shown.

BIN
sounds/rotate.wav Normal file

Binary file not shown.

Binary file not shown.

BIN
sprites/box/black.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.1 KiB

BIN
sprites/box/blue.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

BIN
sprites/box/gray.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
sprites/box/green.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

BIN
sprites/box/indigo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
sprites/box/orange.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
sprites/box/red.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
sprites/box/violet.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

BIN
sprites/box/white.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

BIN
sprites/box/yellow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
sprites/screen-s1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
sprites/screen-s2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
sprites/screen-s3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
sprites/screen-s4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

BIN
sprites/screen.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.2 KiB

BIN
sprites/train-1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 616 KiB

BIN
sprites/train-2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

BIN
sprites/tunnel.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB