Finished refactoring the pause and gameplay scenes
This commit is contained in:
parent
2065a6b4d6
commit
ba376238b2
7 changed files with 473 additions and 497 deletions
|
@ -5,7 +5,7 @@ module Scene
|
||||||
DEFAULT: MainMenu,
|
DEFAULT: MainMenu,
|
||||||
main_menu: MainMenu,
|
main_menu: MainMenu,
|
||||||
settings: SettingsMenu,
|
settings: SettingsMenu,
|
||||||
#paused: PauseMenu,
|
paused: PauseMenu,
|
||||||
#cube_tube: CubeTube
|
cube_tube: CubeTubeGame
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,20 +1,10 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
# Extension to the scene class for the cube tube scene
|
# this is the main gameplay!
|
||||||
module Scene
|
class CubeTubeGame < GameplayScene
|
||||||
class << self
|
def initialize(args, opts = {})
|
||||||
def tick_cube_tube(args)
|
super
|
||||||
# call the gameplay scene tick method (handles pause menu, etc)
|
|
||||||
tick_gameplay(args)
|
|
||||||
args.state.game ||= CubeTubeGame.new args
|
|
||||||
args.state.game.tick
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
#
|
|
||||||
class CubeTubeGame
|
|
||||||
def initialize args
|
|
||||||
@args = args
|
@args = args
|
||||||
|
|
||||||
@blocksize = 30
|
@blocksize = 30
|
||||||
|
@ -59,10 +49,371 @@ class CubeTubeGame
|
||||||
|
|
||||||
@current_music = :music1
|
@current_music = :music1
|
||||||
|
|
||||||
reset_game
|
reset(args)
|
||||||
end
|
end
|
||||||
|
|
||||||
def reset_game
|
def render_background
|
||||||
|
# draw a solid black background
|
||||||
|
@args.outputs.solids << [
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
1280,
|
||||||
|
1280,
|
||||||
|
0, 0, 0
|
||||||
|
]
|
||||||
|
|
||||||
|
@bg_x += (@level + 1) * 2 unless @gameover
|
||||||
|
@bg_x %= @bg_w if @bg_x >= @bg_w
|
||||||
|
|
||||||
|
Sprite.for(:tunnel).render(@args, { x: @bg_x, y: 0, w: @bg_w, h: 720 })
|
||||||
|
Sprite.for(:tunnel).render(@args, { x: @bg_x - @bg_w, y: 0, w: @bg_w, h: 720 })
|
||||||
|
|
||||||
|
Sprite.for(:train).render(@args, { x: 0, y: @grid_x - 64 })
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_foreground
|
||||||
|
Sprite.for(:train_fore).render(@args, { x: 0, y: @grid_x - 64 })
|
||||||
|
end
|
||||||
|
|
||||||
|
# x and y are positions in the grid, not pixels
|
||||||
|
def render_block(x, y, color)
|
||||||
|
@sprite_index[color].render(
|
||||||
|
@args,
|
||||||
|
{
|
||||||
|
x: (1280 - @grid_y) - (y * @blocksize) - 6,
|
||||||
|
y: @grid_x + (x * @blocksize),
|
||||||
|
w: @blocksize + 6,
|
||||||
|
h: @blocksize
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_grid
|
||||||
|
(0..@grid_w - 1).each do |x|
|
||||||
|
(0..@grid_h - 1).each do |y|
|
||||||
|
if @grid[x][y] != 0 && (!@lines_to_clear.include?(y) || (@line_clear_timer % 14) < 7)
|
||||||
|
render_block(x, y, @grid[x][y])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_piece(piece, piece_x, piece_y)
|
||||||
|
(0..piece.length - 1).each do |x|
|
||||||
|
(0..piece[x].length - 1).each do |y|
|
||||||
|
render_block(piece_x + x, piece_y + y, piece[x][y]) if piece[x][y] != 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_current_piece
|
||||||
|
render_piece(@current_piece, @current_piece_x, @current_piece_y) if @line_clear_timer <= 0
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_next_piece
|
||||||
|
screen_x = @grid_y + 400
|
||||||
|
screen_y = @grid_x + 80
|
||||||
|
screen_w = 250
|
||||||
|
screen_h = 200
|
||||||
|
|
||||||
|
Sprite.for(:screen).render(@args, { x: screen_x, y: screen_y + 10, w: screen_w, h: screen_h + 10 })
|
||||||
|
|
||||||
|
next_piece = @line_clear_timer <= 0 ? @next_piece : @current_piece
|
||||||
|
centerx = (@next_piece_box[2] - next_piece.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
|
||||||
|
|
||||||
|
@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
|
||||||
|
|
||||||
|
Sprite.for(screen_s).render(@args, { x: screen_x, y: screen_y + 10, w: screen_w, h: screen_h + 10 })
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_score
|
||||||
|
@args.outputs.labels << [200, 600, "Lines: #{@lines}", 10, 255, 255, 255, 255]
|
||||||
|
@args.outputs.labels << [400, 600, "Level: #{@level}", 10, 255, 255, 255, 255]
|
||||||
|
end
|
||||||
|
|
||||||
|
def render_gameover
|
||||||
|
@args.outputs.solids << [0, 245, 1280, 200, 0, 0, 0, 255]
|
||||||
|
@args.outputs.labels << [200, 450, 'GAME OVER', 100, 255, 255, 255, 255]
|
||||||
|
end
|
||||||
|
|
||||||
|
def render
|
||||||
|
render_background
|
||||||
|
render_next_piece
|
||||||
|
render_current_piece
|
||||||
|
render_grid
|
||||||
|
render_foreground
|
||||||
|
render_score
|
||||||
|
render_gameover if @showgameover
|
||||||
|
end
|
||||||
|
|
||||||
|
def current_piece_colliding
|
||||||
|
(0..@current_piece.length - 1).each do |x|
|
||||||
|
(0..@current_piece[x].length - 1).each do |y|
|
||||||
|
next if @current_piece[x][y].zero?
|
||||||
|
if (@current_piece_y + y >= @grid_h) ||
|
||||||
|
((@current_piece_y + y) >= 0 && @grid[@current_piece_x + x][@current_piece_y + y] != 0)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def get_speed
|
||||||
|
case @level
|
||||||
|
when 0 then 53
|
||||||
|
when 1 then 49
|
||||||
|
when 2 then 45
|
||||||
|
when 3 then 41
|
||||||
|
when 4 then 37
|
||||||
|
when 5 then 33
|
||||||
|
when 6 then 28
|
||||||
|
when 7 then 22
|
||||||
|
when 8 then 17
|
||||||
|
when 9 then 11
|
||||||
|
when 10 then 10
|
||||||
|
when 11 then 9
|
||||||
|
when 12 then 8
|
||||||
|
when 13 then 7
|
||||||
|
when 14..15 then 6
|
||||||
|
when 16..17 then 5
|
||||||
|
when 18..19 then 4
|
||||||
|
else 3
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def change_music
|
||||||
|
@current_music = @current_music == :music1 ? :music2 : :music1
|
||||||
|
Music.queue_up(@current_music)
|
||||||
|
end
|
||||||
|
|
||||||
|
def line_full?(row)
|
||||||
|
(0..@grid_w - 1).each do |x|
|
||||||
|
return false if @grid[x][row].zero?
|
||||||
|
end
|
||||||
|
true
|
||||||
|
end
|
||||||
|
|
||||||
|
def plant_current_piece
|
||||||
|
(0..@current_piece.length - 1).each do |x|
|
||||||
|
(0..@current_piece[x].length - 1).each do |y|
|
||||||
|
next if @current_piece[x][y].zero?
|
||||||
|
|
||||||
|
@grid[@current_piece_x + x][@current_piece_y + y] = @current_piece[x][y]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
@lines_to_clear = []
|
||||||
|
|
||||||
|
# see if any rows need to be cleared out
|
||||||
|
(0..@grid_h - 1).each do |y|
|
||||||
|
next unless line_full?(y)
|
||||||
|
|
||||||
|
# no empty space in the row
|
||||||
|
@lines_to_clear.push y
|
||||||
|
@lines += 1
|
||||||
|
@line_clear_timer = 70
|
||||||
|
if (@lines % 10).floor.zero?
|
||||||
|
@level += 1
|
||||||
|
change_music
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
select_next_piece
|
||||||
|
if @lines_to_clear.empty?
|
||||||
|
Sound.play(@args, :drop)
|
||||||
|
if current_piece_colliding
|
||||||
|
@gameover = true
|
||||||
|
Music.stop(@args)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Sound.play(@args, :clear)
|
||||||
|
@current_speed = get_speed
|
||||||
|
end
|
||||||
|
|
||||||
|
@next_move = @current_speed + 2
|
||||||
|
end
|
||||||
|
|
||||||
|
def select_next_piece
|
||||||
|
@current_piece = @next_piece
|
||||||
|
|
||||||
|
@current_piece_x = 4
|
||||||
|
@current_piece_y = -1
|
||||||
|
|
||||||
|
r = (rand 7) + 1
|
||||||
|
@next_piece =
|
||||||
|
case r
|
||||||
|
when 1 then [[r, 0], [r, r], [0, r]]
|
||||||
|
when 2 then [[0, r], [r, r], [r, 0]]
|
||||||
|
when 3 then [[r, r, r], [r, 0, 0]]
|
||||||
|
when 4 then [[r, r], [r, r] ]
|
||||||
|
when 5 then [[r], [r], [r], [r]]
|
||||||
|
when 6 then [[r, 0], [r, r], [r, 0]]
|
||||||
|
when 7 then [[r, 0, 0], [r, r, r]]
|
||||||
|
end
|
||||||
|
select_next_piece if @current_piece.nil?
|
||||||
|
end
|
||||||
|
|
||||||
|
def rotate_current_piece_left
|
||||||
|
Sound.play(@args, :rotate)
|
||||||
|
@current_piece = @current_piece.transpose.map(&:reverse)
|
||||||
|
@current_piece_x = @grid_w - @current_piece.length if (@current_piece_x + @current_piece.length) >= @grid_w
|
||||||
|
end
|
||||||
|
|
||||||
|
def rotate_current_piece_right
|
||||||
|
Sound.play(@args, :rotate)
|
||||||
|
@current_piece = @current_piece.transpose.map(&:reverse)
|
||||||
|
@current_piece = @current_piece.transpose.map(&:reverse)
|
||||||
|
@current_piece = @current_piece.transpose.map(&:reverse)
|
||||||
|
end
|
||||||
|
|
||||||
|
def fill_grid
|
||||||
|
b = false
|
||||||
|
(0..@grid_h - 1).each do |y|
|
||||||
|
(0..@grid_w - 1).each do |x|
|
||||||
|
if @grid[x][y].zero?
|
||||||
|
@grid[x][y] = (rand 7) + 1
|
||||||
|
b = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil if b
|
||||||
|
end
|
||||||
|
@showgameover = true
|
||||||
|
end
|
||||||
|
|
||||||
|
def restart_game
|
||||||
|
reset(@args)
|
||||||
|
end
|
||||||
|
|
||||||
|
def move_current_piece_up
|
||||||
|
if (@current_piece_x + @current_piece.length) < @grid_w
|
||||||
|
@current_piece_x += 1
|
||||||
|
if current_piece_colliding
|
||||||
|
Sound.play(@args, :move_deny)
|
||||||
|
@current_piece_x -= 1
|
||||||
|
else
|
||||||
|
Sound.play(@args, :move)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Sound.play(@args, :move_deny)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def move_current_piece_down
|
||||||
|
if @current_piece_x.positive?
|
||||||
|
@current_piece_x -= 1
|
||||||
|
if current_piece_colliding
|
||||||
|
Sound.play(@args, :move_deny)
|
||||||
|
@current_piece_x += 1
|
||||||
|
else
|
||||||
|
Sound.play(@args, :move)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
Sound.play(@args, :move_deny)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def iterate_line_clear
|
||||||
|
return false unless @line_clear_timer.positive?
|
||||||
|
|
||||||
|
@line_clear_timer -= 1
|
||||||
|
return true unless @line_clear_timer.zero?
|
||||||
|
|
||||||
|
@lines_to_clear.each do |y|
|
||||||
|
y.downto(1).each do |i|
|
||||||
|
(0..@grid_w - 1).each do |j|
|
||||||
|
@grid[j][i] = @grid[j][i - 1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
(0..@grid_w - 1).each do |i|
|
||||||
|
@grid[i][0] = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
Sound.play(@args, :drop)
|
||||||
|
@lines_to_clear = []
|
||||||
|
false
|
||||||
|
end
|
||||||
|
|
||||||
|
def iterate_input
|
||||||
|
restart_game if Input.pressed?(@args, :primary) && @gameover && @showgameover
|
||||||
|
return if @gameover
|
||||||
|
|
||||||
|
move_current_piece_down if Input.pressed?(@args, :down)
|
||||||
|
move_current_piece_up if Input.pressed?(@args, :up)
|
||||||
|
@next_move -= @current_speed / 3 if Input.pressed_or_held?(@args, :left)
|
||||||
|
rotate_current_piece_left if Input.pressed?(@args, :rotate_left)
|
||||||
|
rotate_current_piece_right if Input.pressed?(@args, :rotate_right)
|
||||||
|
end
|
||||||
|
|
||||||
|
# train bounce effect
|
||||||
|
def iterate_train_bounce
|
||||||
|
# TODO: time it better to the music
|
||||||
|
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
|
||||||
|
end
|
||||||
|
|
||||||
|
def iterate_movement
|
||||||
|
@next_move -= 1
|
||||||
|
return unless @next_move <= 0
|
||||||
|
|
||||||
|
@next_move = @current_speed
|
||||||
|
@current_piece_y += 1
|
||||||
|
|
||||||
|
return unless current_piece_colliding
|
||||||
|
|
||||||
|
@current_piece_y -= 1
|
||||||
|
plant_current_piece
|
||||||
|
end
|
||||||
|
|
||||||
|
def iterate
|
||||||
|
# input first
|
||||||
|
iterate_input
|
||||||
|
|
||||||
|
fill_grid if @gameover && !@showgameover
|
||||||
|
# skip the rest if it's game over
|
||||||
|
return if @gameover
|
||||||
|
|
||||||
|
# resume music if it's paused
|
||||||
|
Music.resume(@args) if !Music.stopped(@args) && Music.paused(@args)
|
||||||
|
|
||||||
|
iterate_train_bounce
|
||||||
|
|
||||||
|
# if we're currently animating a line clear, then skip the movement logic
|
||||||
|
return if iterate_line_clear
|
||||||
|
|
||||||
|
iterate_movement
|
||||||
|
end
|
||||||
|
|
||||||
|
# called every tick of the game loop
|
||||||
|
def tick(args)
|
||||||
|
iterate
|
||||||
|
render
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
# custom logic to reset this scene
|
||||||
|
def reset(args)
|
||||||
|
super
|
||||||
|
|
||||||
@lines = 0
|
@lines = 0
|
||||||
@level = 0
|
@level = 0
|
||||||
@current_speed = get_speed
|
@current_speed = get_speed
|
||||||
|
@ -88,393 +439,7 @@ class CubeTubeGame
|
||||||
end
|
end
|
||||||
|
|
||||||
@current_music = :music1
|
@current_music = :music1
|
||||||
Music.play(@args, @current_music)
|
Music.play(args, @current_music)
|
||||||
Music.set_volume(args, args.state.setting.music ? 0.8 : 0.0)
|
Music.set_volume(args, args.state.setting.music ? 0.8 : 0.0)
|
||||||
end
|
end
|
||||||
|
|
||||||
def render_grid_border x, y, w, h, color
|
|
||||||
|
|
||||||
for i in x..(x+w)-1 do
|
|
||||||
render_block i, y, color
|
|
||||||
render_block i, (y + h - 1), color
|
|
||||||
end
|
|
||||||
|
|
||||||
for i in y..(y+h)-1 do
|
|
||||||
render_block x, i, color
|
|
||||||
render_block (x + w - 1), i, color
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_background
|
|
||||||
# draw a solid black background
|
|
||||||
@args.outputs.solids << [
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
1280,
|
|
||||||
1280,
|
|
||||||
0, 0, 0
|
|
||||||
]
|
|
||||||
|
|
||||||
@bg_x += (@level+1)*2 unless @gameover
|
|
||||||
if(@bg_x >= @bg_w)
|
|
||||||
@bg_x %= @bg_w
|
|
||||||
end
|
|
||||||
|
|
||||||
Sprite.for(:tunnel).render(@args, { x: @bg_x, y: 0, w: @bg_w, h: 720 })
|
|
||||||
Sprite.for(:tunnel).render(@args, { x: @bg_x - @bg_w, y: 0, w: @bg_w, h: 720 })
|
|
||||||
|
|
||||||
Sprite.for(:train).render(@args, { x: 0, y: @grid_x - 64 })
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_foreground
|
|
||||||
Sprite.for(:train_fore).render(@args, { x: 0, y: @grid_x - 64 })
|
|
||||||
end
|
|
||||||
|
|
||||||
# x and y are positions in the grid, not pixels
|
|
||||||
def render_block x, y, color
|
|
||||||
@sprite_index[color].render(
|
|
||||||
@args,
|
|
||||||
{
|
|
||||||
x: (1280 - @grid_y) - (y * @blocksize) - 6,
|
|
||||||
y: @grid_x + (x * @blocksize),
|
|
||||||
w: @blocksize + 6,
|
|
||||||
h: @blocksize
|
|
||||||
}
|
|
||||||
)
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_grid
|
|
||||||
|
|
||||||
#render_grid_border -1, -1, @grid_w + 2, @grid_h + 2, 8
|
|
||||||
|
|
||||||
for x in 0..@grid_w-1 do
|
|
||||||
for y in 0..@grid_h-1 do
|
|
||||||
render_block x, y, @grid[x][y] if @grid[x][y] != 0 && (!@lines_to_clear.include?(y) || (@line_clear_timer % 14) < 7)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_piece piece, piece_x, piece_y
|
|
||||||
|
|
||||||
for x in 0..piece.length-1 do
|
|
||||||
for y in 0..piece[x].length-1 do
|
|
||||||
render_block piece_x + x, piece_y + y, piece[x][y] if piece[x][y] != 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_current_piece
|
|
||||||
render_piece @current_piece, @current_piece_x, @current_piece_y if @line_clear_timer <= 0
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_next_piece
|
|
||||||
|
|
||||||
screen_x = @grid_y + 400
|
|
||||||
screen_y = @grid_x + 80
|
|
||||||
screen_w = 250
|
|
||||||
screen_h = 200
|
|
||||||
|
|
||||||
Sprite.for(:screen).render(@args, { x: screen_x, y: screen_y + 10, w: screen_w, h: screen_h + 10 })
|
|
||||||
|
|
||||||
next_piece = @line_clear_timer <= 0 ? @next_piece : @current_piece
|
|
||||||
# render_grid_border *@next_piece_box, 8
|
|
||||||
centerx = (@next_piece_box[2] - next_piece.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
|
|
||||||
|
|
||||||
@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
|
|
||||||
|
|
||||||
Sprite.for(screen_s).render(@args, { x: screen_x, y: screen_y + 10, w: screen_w, h: screen_h + 10 })
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_score
|
|
||||||
@args.outputs.labels << [ 200, 600, "Lines: #{@lines}", 10, 255, 255, 255, 255 ]
|
|
||||||
@args.outputs.labels << [ 400, 600, "Level: #{@level}", 10, 255, 255, 255, 255 ]
|
|
||||||
@args.outputs.labels << [ 400, 563, "(Speed: #{(1/(@current_speed/60)).round 2} L/s)", 0.1, 255, 255, 255, 255 ]
|
|
||||||
end
|
|
||||||
|
|
||||||
def render_gameover
|
|
||||||
@args.outputs.solids << [ 0, 245, 1280, 200, 0, 0, 0, 255]
|
|
||||||
@args.outputs.labels << [ 200, 450, "GAME OVER", 100, 255, 255, 255, 255 ]
|
|
||||||
end
|
|
||||||
|
|
||||||
def render
|
|
||||||
render_background
|
|
||||||
render_next_piece
|
|
||||||
render_current_piece
|
|
||||||
render_grid
|
|
||||||
render_foreground
|
|
||||||
render_score
|
|
||||||
render_gameover if @showgameover
|
|
||||||
end
|
|
||||||
|
|
||||||
def current_piece_colliding
|
|
||||||
for x in 0..@current_piece.length-1 do
|
|
||||||
for y in 0..@current_piece[x].length-1 do
|
|
||||||
if (@current_piece[x][y] != 0) && ((@current_piece_y + y >= @grid_h) || ((@current_piece_y + y) >= 0 && @grid[@current_piece_x + x][@current_piece_y + y] != 0 ))
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
def get_speed
|
|
||||||
return case @level
|
|
||||||
when 0 then 53
|
|
||||||
when 1 then 49
|
|
||||||
when 2 then 45
|
|
||||||
when 3 then 41
|
|
||||||
when 4 then 37
|
|
||||||
when 5 then 33
|
|
||||||
when 6 then 28
|
|
||||||
when 7 then 22
|
|
||||||
when 8 then 17
|
|
||||||
when 9 then 11
|
|
||||||
when 10 then 10
|
|
||||||
when 11 then 9
|
|
||||||
when 12 then 8
|
|
||||||
when 13 then 7
|
|
||||||
when 14 then 6
|
|
||||||
when 15 then 6
|
|
||||||
when 16 then 5
|
|
||||||
when 17 then 5
|
|
||||||
when 18 then 4
|
|
||||||
when 19 then 4
|
|
||||||
when 20 then 3
|
|
||||||
else 3
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def change_music
|
|
||||||
if @current_music == :music1
|
|
||||||
@current_music = :music2
|
|
||||||
else
|
|
||||||
@current_music = :music1
|
|
||||||
end
|
|
||||||
queue = Music.queue
|
|
||||||
Music.queue_up(@current_music)
|
|
||||||
end
|
|
||||||
|
|
||||||
def plant_current_piece
|
|
||||||
rows_to_check = []
|
|
||||||
|
|
||||||
for x in 0..@current_piece.length-1 do
|
|
||||||
for y in 0..@current_piece[x].length-1 do
|
|
||||||
if @current_piece[x][y] != 0
|
|
||||||
col = @current_piece_x + x
|
|
||||||
row = @current_piece_y + y
|
|
||||||
@grid[col][row] = @current_piece[x][y]
|
|
||||||
rows_to_check << row if !rows_to_check.include? row
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
@lines_to_clear = []
|
|
||||||
|
|
||||||
# see if any rows need to be cleared out
|
|
||||||
for y in 0..@grid_h-1
|
|
||||||
full = true
|
|
||||||
for x in 0..@grid_w-1
|
|
||||||
if @grid[x][y] == 0
|
|
||||||
full = false
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if full # no empty space in the row
|
|
||||||
@lines_to_clear.push y
|
|
||||||
@lines += 1
|
|
||||||
@line_clear_timer = 70
|
|
||||||
if (@lines%10).floor == 0
|
|
||||||
@level += 1
|
|
||||||
change_music
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
select_next_piece
|
|
||||||
if @lines_to_clear.empty?
|
|
||||||
Sound.play(@args, :drop)
|
|
||||||
if current_piece_colliding
|
|
||||||
@gameover = true
|
|
||||||
Music.stop(@args)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Sound.play(@args, :clear)
|
|
||||||
@current_speed = get_speed
|
|
||||||
end
|
|
||||||
|
|
||||||
@next_move = @current_speed + 2
|
|
||||||
end
|
|
||||||
|
|
||||||
def select_next_piece
|
|
||||||
|
|
||||||
@current_piece = @next_piece
|
|
||||||
|
|
||||||
@current_piece_x = 4
|
|
||||||
@current_piece_y = -1
|
|
||||||
|
|
||||||
r = (rand 7) + 1
|
|
||||||
@next_piece = case r
|
|
||||||
when 1 then [ [r, 0], [r, r], [0, r]]
|
|
||||||
when 2 then [ [0, r], [r, r], [r, 0]]
|
|
||||||
when 3 then [ [r, r, r], [r, 0, 0]]
|
|
||||||
when 4 then [ [r, r], [r, r] ]
|
|
||||||
when 5 then [ [r], [r], [r], [r]]
|
|
||||||
when 6 then [ [r, 0], [r, r], [r, 0]]
|
|
||||||
when 7 then [ [r, 0, 0], [r, r, r]]
|
|
||||||
end
|
|
||||||
select_next_piece if @current_piece == nil
|
|
||||||
end
|
|
||||||
|
|
||||||
def rotate_current_piece_left
|
|
||||||
Sound.play(@args, :rotate)
|
|
||||||
@current_piece = @current_piece.transpose.map(&:reverse)
|
|
||||||
if(@current_piece_x + @current_piece.length) >= @grid_w
|
|
||||||
@current_piece_x = @grid_w - @current_piece.length
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def rotate_current_piece_right
|
|
||||||
Sound.play(@args, :rotate)
|
|
||||||
@current_piece = @current_piece.transpose.map(&:reverse)
|
|
||||||
@current_piece = @current_piece.transpose.map(&:reverse)
|
|
||||||
@current_piece = @current_piece.transpose.map(&:reverse)
|
|
||||||
end
|
|
||||||
|
|
||||||
def fill_grid
|
|
||||||
b = false
|
|
||||||
for y in 0..@grid_h-1 do
|
|
||||||
for x in 0..@grid_w-1 do
|
|
||||||
if @grid[x][y] == 0
|
|
||||||
@grid[x][y] = (rand 7) + 1
|
|
||||||
b = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return if b
|
|
||||||
end
|
|
||||||
@showgameover = true
|
|
||||||
end
|
|
||||||
|
|
||||||
def restart_game
|
|
||||||
reset_game
|
|
||||||
end
|
|
||||||
|
|
||||||
def iterate
|
|
||||||
|
|
||||||
# check input first
|
|
||||||
k = @args.inputs.keyboard
|
|
||||||
c = @args.inputs.controller_one
|
|
||||||
|
|
||||||
if @gameover
|
|
||||||
if @showgameover
|
|
||||||
if k.key_down.space || k.key_down.enter || c.key_down.start
|
|
||||||
restart_game
|
|
||||||
end
|
|
||||||
else
|
|
||||||
fill_grid
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
unless Music.stopped(@args)
|
|
||||||
Music.resume(@args) if Music.paused(@args)
|
|
||||||
end
|
|
||||||
|
|
||||||
if @line_clear_timer.positive?
|
|
||||||
@line_clear_timer -= 1
|
|
||||||
if @line_clear_timer.zero?
|
|
||||||
for y in @lines_to_clear
|
|
||||||
for i in y.downto(1) do
|
|
||||||
for j in 0..@grid_w-1
|
|
||||||
@grid[j][i] = @grid[j][i-1]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
for i in 0..@grid_w-1
|
|
||||||
@grid[i][0] = 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
Sound.play(@args, :drop)
|
|
||||||
@lines_to_clear = []
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if k.key_down.down || k.key_down.s || c.key_down.down
|
|
||||||
if @current_piece_x > 0
|
|
||||||
@current_piece_x -= 1
|
|
||||||
if current_piece_colliding
|
|
||||||
Sound.play(@args, :move_deny)
|
|
||||||
@current_piece_x += 1
|
|
||||||
else
|
|
||||||
Sound.play(@args, :move)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Sound.play(@args, :move_deny)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if k.key_down.up || k.key_down.w || c.key_down.up
|
|
||||||
if (@current_piece_x + @current_piece.length) < @grid_w
|
|
||||||
@current_piece_x += 1
|
|
||||||
if current_piece_colliding
|
|
||||||
Sound.play(@args, :move_deny)
|
|
||||||
@current_piece_x -= 1
|
|
||||||
else
|
|
||||||
Sound.play(@args, :move)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
Sound.play(@args, :move_deny)
|
|
||||||
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
|
|
||||||
@next_move -= @current_speed / 3
|
|
||||||
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
|
|
||||||
rotate_current_piece_left
|
|
||||||
end
|
|
||||||
if k.key_down.e || c.key_down.b
|
|
||||||
rotate_current_piece_right
|
|
||||||
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
|
|
||||||
if @next_move <= 0
|
|
||||||
@next_move = @current_speed
|
|
||||||
@current_piece_y += 1
|
|
||||||
if current_piece_colliding
|
|
||||||
@current_piece_y -= 1
|
|
||||||
plant_current_piece
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def tick
|
|
||||||
iterate
|
|
||||||
render
|
|
||||||
end
|
|
||||||
end
|
end
|
|
@ -1,54 +1,51 @@
|
||||||
module Scene
|
# frozen_string_literal: true
|
||||||
class << self
|
|
||||||
# This is your main entrypoint into the actual fun part of your game!
|
|
||||||
def tick_gameplay(args)
|
|
||||||
labels = []
|
|
||||||
sprites = []
|
|
||||||
|
|
||||||
# focus tracking
|
# This is a base class for the main gameplay, handling things like pausing
|
||||||
if !args.state.has_focus && args.inputs.keyboard.has_focus
|
class GameplayScene < SceneInstance
|
||||||
args.state.has_focus = true
|
def initialize(_args, opts = {})
|
||||||
elsif args.state.has_focus && !args.inputs.keyboard.has_focus
|
super
|
||||||
args.state.has_focus = false
|
end
|
||||||
end
|
|
||||||
|
|
||||||
# auto-pause & input-based pause
|
# called every tick of the game loop
|
||||||
if !args.state.has_focus || Input.pressed?(args, :pause)
|
def tick(args)
|
||||||
return pause(args)
|
super
|
||||||
end
|
|
||||||
|
|
||||||
tick_pause_button(args, sprites) if mobile?
|
# focus tracking
|
||||||
|
if !args.state.has_focus && args.inputs.keyboard.has_focus
|
||||||
draw_bg(args, BLACK)
|
args.state.has_focus = true
|
||||||
|
elsif args.state.has_focus && !args.inputs.keyboard.has_focus
|
||||||
# labels << label("GAMEPLAY", x: 40, y: args.grid.top - 40, size: SIZE_LG, font: FONT_BOLD)
|
args.state.has_focus = false
|
||||||
args.outputs.labels << labels
|
|
||||||
args.outputs.sprites << sprites
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def pause(args)
|
# auto-pause & input-based pause
|
||||||
Sound.play(args, :select)
|
return pause(args) if !args.state.has_focus || Input.pressed?(args, :pause)
|
||||||
return Scene.push(args, :paused, reset: true)
|
|
||||||
end
|
|
||||||
|
|
||||||
def tick_pause_button(args, sprites)
|
tick_pause_button(args) if mobile?
|
||||||
pause_button = {
|
|
||||||
x: 72.from_right,
|
draw_bg(args, BLACK)
|
||||||
y: 72.from_top,
|
end
|
||||||
w: 52,
|
|
||||||
h: 52,
|
def pause(args)
|
||||||
path: Sprite.for(:pause),
|
Sound.play(args, :select)
|
||||||
}
|
Scene.push(args, :paused, reset: true)
|
||||||
pause_rect = pause_button.dup
|
end
|
||||||
pause_padding = 12
|
|
||||||
pause_rect.x -= pause_padding
|
def tick_pause_button(args)
|
||||||
pause_rect.y -= pause_padding
|
pause_button = {
|
||||||
pause_rect.w += pause_padding * 2
|
x: 72.from_right,
|
||||||
pause_rect.h += pause_padding * 2
|
y: 72.from_top,
|
||||||
if args.inputs.mouse.down && args.inputs.mouse.inside_rect?(pause_rect)
|
w: 52,
|
||||||
return pause(args)
|
h: 52,
|
||||||
end
|
path: Sprite.for(:pause)
|
||||||
sprites << pause_button
|
}
|
||||||
end
|
pause_rect = pause_button.dup
|
||||||
|
pause_padding = 12
|
||||||
|
pause_rect.x -= pause_padding
|
||||||
|
pause_rect.y -= pause_padding
|
||||||
|
pause_rect.w += pause_padding * 2
|
||||||
|
pause_rect.h += pause_padding * 2
|
||||||
|
return pause(args) if args.inputs.mouse.down && args.inputs.mouse.inside_rect?(pause_rect)
|
||||||
|
|
||||||
|
args.outputs.sprites << pause_button
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -55,7 +55,7 @@ class MenuScene < SceneInstance
|
||||||
button_border = { w: 340, h: 80, x: l.x - 170, y: l.y - 55 }.merge(WHITE)
|
button_border = { w: 340, h: 80, x: l.x - 170, y: l.y - 55 }.merge(WHITE)
|
||||||
(args.outputs.borders << button_border) if mobile?
|
(args.outputs.borders << button_border) if mobile?
|
||||||
if args.inputs.mouse.up && args.inputs.mouse.inside_rect?(button_border)
|
if args.inputs.mouse.up && args.inputs.mouse.inside_rect?(button_border)
|
||||||
o = options.find { |o| o[:key] == l[:key] }
|
o = @menu_options.find { |o| o[:key] == l[:key] }
|
||||||
Sound.play(args, :menu)
|
Sound.play(args, :menu)
|
||||||
o[:on_select].call(args) if o
|
o[:on_select].call(args) if o
|
||||||
end
|
end
|
||||||
|
@ -105,6 +105,11 @@ class MenuScene < SceneInstance
|
||||||
@menu_options[@menu_state.current_option_i][:on_select].call(args)
|
@menu_options[@menu_state.current_option_i][:on_select].call(args)
|
||||||
Sound.play(args, :select)
|
Sound.play(args, :select)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if Input.pressed?(args, :secondary) && !Scene.stack(args).empty?
|
||||||
|
Sound.play(args, :select)
|
||||||
|
Scene.pop(args)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# custom logic to reset this scene
|
# custom logic to reset this scene
|
||||||
|
|
|
@ -1,42 +1,46 @@
|
||||||
module Scene
|
# frozen_string_literal: true
|
||||||
class << self
|
|
||||||
# scene reached from gameplay when the player needs a break
|
|
||||||
def tick_paused(args)
|
|
||||||
draw_bg(args, DARK_YELLOW)
|
|
||||||
|
|
||||||
options = [
|
# This is the pause menu, triggered by a button press when the player wants a
|
||||||
{
|
# break from gameplay.
|
||||||
key: :resume,
|
class PauseMenu < MenuScene
|
||||||
on_select: -> (args) { Scene.pop(args) }
|
def initialize(args, opts = {})
|
||||||
},
|
menu_options = [
|
||||||
{
|
{
|
||||||
key: :settings,
|
key: :resume,
|
||||||
on_select: -> (args) { Scene.push(args, :settings, reset: true) }
|
on_select: ->(args) { Scene.pop(args) }
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: :return_to_main_menu,
|
key: :settings,
|
||||||
on_select: -> (args) { Scene.switch(args, :main_menu) }
|
on_select: ->(args) { Scene.push(args, :settings, reset: true) }
|
||||||
},
|
},
|
||||||
]
|
{
|
||||||
|
key: :return_to_main_menu,
|
||||||
|
on_select: ->(args) { Scene.switch(args, :main_menu) }
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
if args.gtk.platform?(:desktop)
|
if args.gtk.platform?(:desktop)
|
||||||
options << {
|
menu_options << {
|
||||||
key: :quit,
|
key: :quit,
|
||||||
on_select: -> (args) { args.gtk.request_quit }
|
on_select: ->(args) { args.gtk.request_quit }
|
||||||
}
|
}
|
||||||
end
|
|
||||||
|
|
||||||
Menu.tick(args, :paused, options)
|
|
||||||
|
|
||||||
Music.pause(args) unless Music.stopped(args)
|
|
||||||
|
|
||||||
if Input.pressed?(args, :secondary)
|
|
||||||
Sound.play(args, :select)
|
|
||||||
options.find { |o| o[:key] == :resume }[:on_select].call(args)
|
|
||||||
|
|
||||||
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)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
super args, opts, 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
|
||||||
end
|
end
|
||||||
|
|
|
@ -55,11 +55,6 @@ class SettingsMenu < MenuScene
|
||||||
# actual menu logic is handled by the MenuScene super class
|
# actual menu logic is handled by the MenuScene super class
|
||||||
super
|
super
|
||||||
|
|
||||||
if Input.pressed?(args, :secondary)
|
|
||||||
Sound.play(args, :select)
|
|
||||||
@menu_options.find { |o| o[:key] == :back }[:on_select].call(args)
|
|
||||||
end
|
|
||||||
|
|
||||||
args.outputs.labels << label(
|
args.outputs.labels << label(
|
||||||
:settings,
|
:settings,
|
||||||
x: args.grid.w / 2,
|
x: args.grid.w / 2,
|
||||||
|
|
|
@ -23,6 +23,12 @@ module Scene
|
||||||
# if `scene` is not a `SceneInstance`, it's probably a symbol representing
|
# if `scene` is not a `SceneInstance`, it's probably a symbol representing
|
||||||
# the scene we're switching to, so go get it.
|
# the scene we're switching to, so go get it.
|
||||||
the_scene = scene.is_a?(SceneInstance) ? scene : SCENES[scene].new(args)
|
the_scene = scene.is_a?(SceneInstance) ? scene : SCENES[scene].new(args)
|
||||||
|
puts '---'
|
||||||
|
puts 'switching to'
|
||||||
|
puts scene unless scene.is_a?(SceneInstance)
|
||||||
|
puts SCENES[scene] unless scene.is_a?(SceneInstance)
|
||||||
|
puts the_scene
|
||||||
|
puts '---'
|
||||||
|
|
||||||
# if the stack is empty (e.g. we just cleared it), then push this scene
|
# if the stack is empty (e.g. we just cleared it), then push this scene
|
||||||
args.state.scene_stack.push(the_scene) if args.state.scene_stack.empty?
|
args.state.scene_stack.push(the_scene) if args.state.scene_stack.empty?
|
||||||
|
@ -53,5 +59,9 @@ module Scene
|
||||||
args.state.scene_stack ||= []
|
args.state.scene_stack ||= []
|
||||||
SCENES[:DEFAULT].new(args)
|
SCENES[:DEFAULT].new(args)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def stack(args)
|
||||||
|
args.state.scene_stack ||= []
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in a new issue