glimmer-dsl-libui 0.2.19 → 0.2.23
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 +4 -4
- data/CHANGELOG.md +30 -0
- data/README.md +467 -35
- data/VERSION +1 -1
- data/examples/area_gallery.rb +1 -1
- data/examples/area_gallery2.rb +1 -1
- data/examples/area_gallery3.rb +1 -1
- data/examples/area_gallery4.rb +1 -1
- data/examples/meta_example.rb +1 -1
- data/examples/snake/model/apple.rb +33 -0
- data/examples/snake/model/game.rb +51 -0
- data/examples/snake/model/snake.rb +95 -0
- data/examples/snake/model/vertebra.rb +22 -0
- data/examples/snake/presenter/cell.rb +27 -0
- data/examples/snake/presenter/grid.rb +47 -0
- data/examples/snake.rb +90 -0
- data/examples/tetris/model/game.rb +3 -1
- data/examples/tetris.rb +127 -15
- data/examples/tic_tac_toe/board.rb +145 -0
- data/examples/tic_tac_toe/cell.rb +48 -0
- data/examples/tic_tac_toe.rb +85 -0
- data/glimmer-dsl-libui.gemspec +0 -0
- data/lib/glimmer/libui/control_proxy/window_proxy.rb +40 -1
- data/lib/glimmer/libui.rb +34 -6
- metadata +12 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.23
|
data/examples/area_gallery.rb
CHANGED
data/examples/area_gallery2.rb
CHANGED
data/examples/area_gallery3.rb
CHANGED
data/examples/area_gallery4.rb
CHANGED
data/examples/meta_example.rb
CHANGED
@@ -43,7 +43,7 @@ class MetaExample
|
|
43
43
|
|
44
44
|
def run_example(example)
|
45
45
|
Thread.new do
|
46
|
-
command = "ruby -r #{glimmer_dsl_libui_file} #{example} 2>&1"
|
46
|
+
command = "#{RbConfig.ruby} -r #{glimmer_dsl_libui_file} #{example} 2>&1"
|
47
47
|
result = ''
|
48
48
|
IO.popen(command) do |f|
|
49
49
|
sleep(0.0001) # yield to main thread
|
@@ -0,0 +1,33 @@
|
|
1
|
+
class Snake
|
2
|
+
module Model
|
3
|
+
class Apple
|
4
|
+
attr_reader :game
|
5
|
+
attr_accessor :row, :column
|
6
|
+
|
7
|
+
def initialize(game)
|
8
|
+
@game = game
|
9
|
+
end
|
10
|
+
|
11
|
+
# generates a new location from scratch or via dependency injection of what cell is (for testing purposes)
|
12
|
+
def generate(initial_row: nil, initial_column: nil)
|
13
|
+
if initial_row && initial_column
|
14
|
+
self.row, self.column = initial_row, initial_column
|
15
|
+
else
|
16
|
+
self.row, self.column = @game.height.times.zip(@game.width.times).reject do |row, column|
|
17
|
+
@game.snake.vertebrae.map {|v| [v.row, v.column]}.include?([row, column])
|
18
|
+
end.sample
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def remove
|
23
|
+
self.row = nil
|
24
|
+
self.column = nil
|
25
|
+
end
|
26
|
+
|
27
|
+
# inspect is overridden to prevent printing very long stack traces
|
28
|
+
def inspect
|
29
|
+
"#{super[0, 120]}... >"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
3
|
+
require_relative 'snake'
|
4
|
+
require_relative 'apple'
|
5
|
+
|
6
|
+
class Snake
|
7
|
+
module Model
|
8
|
+
class Game
|
9
|
+
WIDTH_DEFAULT = 40
|
10
|
+
HEIGHT_DEFAULT = 40
|
11
|
+
FILE_HIGH_SCORE = File.expand_path(File.join(Dir.home, '.glimmer-snake'))
|
12
|
+
|
13
|
+
attr_reader :width, :height
|
14
|
+
attr_accessor :snake, :apple, :over, :score, :high_score
|
15
|
+
alias over? over
|
16
|
+
|
17
|
+
def initialize(width = WIDTH_DEFAULT, height = HEIGHT_DEFAULT)
|
18
|
+
@width = width
|
19
|
+
@height = height
|
20
|
+
@snake = Snake.new(self)
|
21
|
+
@apple = Apple.new(self)
|
22
|
+
FileUtils.touch(FILE_HIGH_SCORE)
|
23
|
+
@high_score = File.read(FILE_HIGH_SCORE).to_i rescue 0
|
24
|
+
end
|
25
|
+
|
26
|
+
def score=(new_score)
|
27
|
+
@score = new_score
|
28
|
+
self.high_score = @score if @score > @high_score
|
29
|
+
end
|
30
|
+
|
31
|
+
def high_score=(new_high_score)
|
32
|
+
@high_score = new_high_score
|
33
|
+
File.write(FILE_HIGH_SCORE, @high_score.to_s)
|
34
|
+
rescue => e
|
35
|
+
puts e.full_message
|
36
|
+
end
|
37
|
+
|
38
|
+
def start
|
39
|
+
self.over = false
|
40
|
+
self.score = 0
|
41
|
+
self.snake.generate
|
42
|
+
self.apple.generate
|
43
|
+
end
|
44
|
+
|
45
|
+
# inspect is overridden to prevent printing very long stack traces
|
46
|
+
def inspect
|
47
|
+
"#{super[0, 75]}... >"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require_relative 'vertebra'
|
2
|
+
|
3
|
+
class Snake
|
4
|
+
module Model
|
5
|
+
class Snake
|
6
|
+
SCORE_EAT_APPLE = 50
|
7
|
+
RIGHT_TURN_MAP = {
|
8
|
+
north: :east,
|
9
|
+
east: :south,
|
10
|
+
south: :west,
|
11
|
+
west: :north
|
12
|
+
}
|
13
|
+
LEFT_TURN_MAP = RIGHT_TURN_MAP.invert
|
14
|
+
|
15
|
+
attr_accessor :collided
|
16
|
+
alias collided? collided
|
17
|
+
|
18
|
+
attr_reader :game
|
19
|
+
# vertebrae and joins are ordered from tail to head
|
20
|
+
attr_accessor :vertebrae
|
21
|
+
|
22
|
+
def initialize(game)
|
23
|
+
@game = game
|
24
|
+
end
|
25
|
+
|
26
|
+
# generates a new snake location and orientation from scratch or via dependency injection of what head_cell and orientation are (for testing purposes)
|
27
|
+
def generate(initial_row: nil, initial_column: nil, initial_orientation: nil)
|
28
|
+
self.collided = false
|
29
|
+
initial_vertebra = Vertebra.new(snake: self, row: initial_row, column: initial_column, orientation: initial_orientation)
|
30
|
+
self.vertebrae = [initial_vertebra]
|
31
|
+
end
|
32
|
+
|
33
|
+
def length
|
34
|
+
@vertebrae.length
|
35
|
+
end
|
36
|
+
|
37
|
+
def head
|
38
|
+
@vertebrae.last
|
39
|
+
end
|
40
|
+
|
41
|
+
def tail
|
42
|
+
@vertebrae.first
|
43
|
+
end
|
44
|
+
|
45
|
+
def remove
|
46
|
+
self.vertebrae.clear
|
47
|
+
self.joins.clear
|
48
|
+
end
|
49
|
+
|
50
|
+
def move
|
51
|
+
@old_tail = tail.dup
|
52
|
+
@new_head = head.dup
|
53
|
+
case @new_head.orientation
|
54
|
+
when :east
|
55
|
+
@new_head.column = (@new_head.column + 1) % @game.width
|
56
|
+
when :west
|
57
|
+
@new_head.column = (@new_head.column - 1) % @game.width
|
58
|
+
when :south
|
59
|
+
@new_head.row = (@new_head.row + 1) % @game.height
|
60
|
+
when :north
|
61
|
+
@new_head.row = (@new_head.row - 1) % @game.height
|
62
|
+
end
|
63
|
+
if @vertebrae.map {|v| [v.row, v.column]}.include?([@new_head.row, @new_head.column])
|
64
|
+
self.collided = true
|
65
|
+
@game.over = true
|
66
|
+
else
|
67
|
+
@vertebrae.append(@new_head)
|
68
|
+
@vertebrae.delete(tail)
|
69
|
+
if head.row == @game.apple.row && head.column == @game.apple.column
|
70
|
+
grow
|
71
|
+
@game.apple.generate
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def turn_right
|
77
|
+
head.orientation = RIGHT_TURN_MAP[head.orientation]
|
78
|
+
end
|
79
|
+
|
80
|
+
def turn_left
|
81
|
+
head.orientation = LEFT_TURN_MAP[head.orientation]
|
82
|
+
end
|
83
|
+
|
84
|
+
def grow
|
85
|
+
@game.score += SCORE_EAT_APPLE
|
86
|
+
@vertebrae.prepend(@old_tail)
|
87
|
+
end
|
88
|
+
|
89
|
+
# inspect is overridden to prevent printing very long stack traces
|
90
|
+
def inspect
|
91
|
+
"#{super[0, 150]}... >"
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
class Snake
|
2
|
+
module Model
|
3
|
+
class Vertebra
|
4
|
+
ORIENTATIONS = %i[north east south west]
|
5
|
+
# orientation is needed for snake occuppied cells (but not apple cells)
|
6
|
+
attr_reader :snake
|
7
|
+
attr_accessor :row, :column, :orientation
|
8
|
+
|
9
|
+
def initialize(snake: , row: , column: , orientation: )
|
10
|
+
@row = row || rand(snake.game.height)
|
11
|
+
@column = column || rand(snake.game.width)
|
12
|
+
@orientation = orientation || ORIENTATIONS.sample
|
13
|
+
@snake = snake
|
14
|
+
end
|
15
|
+
|
16
|
+
# inspect is overridden to prevent printing very long stack traces
|
17
|
+
def inspect
|
18
|
+
"#{super[0, 150]}... >"
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Snake
|
2
|
+
module Presenter
|
3
|
+
class Cell
|
4
|
+
COLOR_CLEAR = :white
|
5
|
+
COLOR_SNAKE = :green
|
6
|
+
COLOR_APPLE = :red
|
7
|
+
|
8
|
+
attr_reader :row, :column, :grid
|
9
|
+
attr_accessor :color
|
10
|
+
|
11
|
+
def initialize(grid: ,row: ,column: )
|
12
|
+
@row = row
|
13
|
+
@column = column
|
14
|
+
@grid = grid
|
15
|
+
end
|
16
|
+
|
17
|
+
def clear
|
18
|
+
self.color = COLOR_CLEAR unless color == COLOR_CLEAR
|
19
|
+
end
|
20
|
+
|
21
|
+
# inspect is overridden to prevent printing very long stack traces
|
22
|
+
def inspect
|
23
|
+
"#{super[0, 150]}... >"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'glimmer/data_binding/observer'
|
2
|
+
require_relative '../model/game'
|
3
|
+
require_relative 'cell'
|
4
|
+
|
5
|
+
class Snake
|
6
|
+
module Presenter
|
7
|
+
class Grid
|
8
|
+
attr_reader :game, :cells
|
9
|
+
|
10
|
+
def initialize(game = Model::Game.new)
|
11
|
+
@game = game
|
12
|
+
@cells = @game.height.times.map do |row|
|
13
|
+
@game.width.times.map do |column|
|
14
|
+
Cell.new(grid: self, row: row, column: column)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
Glimmer::DataBinding::Observer.proc do |new_vertebrae|
|
18
|
+
occupied_snake_positions = @game.snake.vertebrae.map {|v| [v.row, v.column]}
|
19
|
+
@cells.each_with_index do |row_cells, row|
|
20
|
+
row_cells.each_with_index do |cell, column|
|
21
|
+
if [@game.apple.row, @game.apple.column] == [row, column]
|
22
|
+
cell.color = Cell::COLOR_APPLE
|
23
|
+
elsif occupied_snake_positions.include?([row, column])
|
24
|
+
cell.color = Cell::COLOR_SNAKE
|
25
|
+
else
|
26
|
+
cell.clear
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end.observe(@game.snake, :vertebrae)
|
31
|
+
end
|
32
|
+
|
33
|
+
def clear
|
34
|
+
@cells.each do |row_cells|
|
35
|
+
row_cells.each do |cell|
|
36
|
+
cell.clear
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# inspect is overridden to prevent printing very long stack traces
|
42
|
+
def inspect
|
43
|
+
"#{super[0, 75]}... >"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/examples/snake.rb
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
require 'glimmer-dsl-libui'
|
2
|
+
require 'glimmer/data_binding/observer'
|
3
|
+
|
4
|
+
require_relative 'snake/presenter/grid'
|
5
|
+
|
6
|
+
class Snake
|
7
|
+
CELL_SIZE = 15
|
8
|
+
SNAKE_MOVE_DELAY = 0.1
|
9
|
+
include Glimmer
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@game = Model::Game.new
|
13
|
+
@grid = Presenter::Grid.new(@game)
|
14
|
+
@game.start
|
15
|
+
create_gui
|
16
|
+
register_observers
|
17
|
+
end
|
18
|
+
|
19
|
+
def launch
|
20
|
+
@main_window.show
|
21
|
+
end
|
22
|
+
|
23
|
+
def register_observers
|
24
|
+
@game.height.times do |row|
|
25
|
+
@game.width.times do |column|
|
26
|
+
Glimmer::DataBinding::Observer.proc do |new_color|
|
27
|
+
@cell_grid[row][column].fill = new_color
|
28
|
+
end.observe(@grid.cells[row][column], :color)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Glimmer::DataBinding::Observer.proc do |game_over|
|
33
|
+
Glimmer::LibUI.queue_main do
|
34
|
+
if game_over
|
35
|
+
msg_box('Game Over!', "Score: #{@game.score} | High Score: #{@game.high_score}")
|
36
|
+
@game.start
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end.observe(@game, :over)
|
40
|
+
|
41
|
+
Glimmer::LibUI.timer(SNAKE_MOVE_DELAY) do
|
42
|
+
unless @game.over?
|
43
|
+
@game.snake.move
|
44
|
+
@main_window.title = "Glimmer Snake (Score: #{@game.score} | High Score: #{@game.high_score})"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def create_gui
|
50
|
+
@cell_grid = []
|
51
|
+
@main_window = window('Glimmer Snake', @game.width * CELL_SIZE, @game.height * CELL_SIZE) {
|
52
|
+
resizable false
|
53
|
+
|
54
|
+
vertical_box {
|
55
|
+
padded false
|
56
|
+
|
57
|
+
@game.height.times do |row|
|
58
|
+
@cell_grid << []
|
59
|
+
horizontal_box {
|
60
|
+
padded false
|
61
|
+
|
62
|
+
@game.width.times do |column|
|
63
|
+
area {
|
64
|
+
@cell_grid.last << path {
|
65
|
+
square(0, 0, CELL_SIZE)
|
66
|
+
|
67
|
+
fill Presenter::Cell::COLOR_CLEAR
|
68
|
+
}
|
69
|
+
|
70
|
+
on_key_up do |area_key_event|
|
71
|
+
orientation_and_key = [@game.snake.head.orientation, area_key_event[:ext_key]]
|
72
|
+
case orientation_and_key
|
73
|
+
in [:north, :right] | [:east, :down] | [:south, :left] | [:west, :up]
|
74
|
+
@game.snake.turn_right
|
75
|
+
in [:north, :left] | [:west, :down] | [:south, :right] | [:east, :up]
|
76
|
+
@game.snake.turn_left
|
77
|
+
else
|
78
|
+
# No Op
|
79
|
+
end
|
80
|
+
end
|
81
|
+
}
|
82
|
+
end
|
83
|
+
}
|
84
|
+
end
|
85
|
+
}
|
86
|
+
}
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
Snake.new.launch
|
@@ -85,11 +85,13 @@ class Tetris
|
|
85
85
|
|
86
86
|
def clear_high_scores!
|
87
87
|
high_scores.clear
|
88
|
+
save_high_scores!
|
88
89
|
end
|
89
90
|
|
90
91
|
def add_high_score!
|
91
92
|
self.added_high_score = true
|
92
93
|
high_scores.prepend(PastGame.new("Player #{high_scores.count + 1}", score, lines, level))
|
94
|
+
save_high_scores!
|
93
95
|
end
|
94
96
|
|
95
97
|
def save_high_scores!
|
@@ -111,7 +113,7 @@ class Tetris
|
|
111
113
|
end
|
112
114
|
|
113
115
|
def tetris_dir
|
114
|
-
@tetris_dir ||= File.join(
|
116
|
+
@tetris_dir ||= File.join(Dir.home, '.glimmer-tetris')
|
115
117
|
end
|
116
118
|
|
117
119
|
def tetris_high_score_file
|
data/examples/tetris.rb
CHANGED
@@ -9,8 +9,6 @@ class Tetris
|
|
9
9
|
BEVEL_CONSTANT = 20
|
10
10
|
COLOR_GRAY = {r: 192, g: 192, b: 192}
|
11
11
|
|
12
|
-
attr_reader :game
|
13
|
-
|
14
12
|
def initialize
|
15
13
|
@game = Model::Game.new
|
16
14
|
end
|
@@ -23,8 +21,11 @@ class Tetris
|
|
23
21
|
end
|
24
22
|
|
25
23
|
def create_gui
|
24
|
+
menu_bar
|
25
|
+
|
26
26
|
@main_window = window('Glimmer Tetris') {
|
27
27
|
content_size Model::Game::PLAYFIELD_WIDTH * BLOCK_SIZE, Model::Game::PLAYFIELD_HEIGHT * BLOCK_SIZE + 98
|
28
|
+
resizable false
|
28
29
|
|
29
30
|
vertical_box {
|
30
31
|
label { # filler
|
@@ -43,8 +44,10 @@ class Tetris
|
|
43
44
|
def register_observers
|
44
45
|
Glimmer::DataBinding::Observer.proc do |game_over|
|
45
46
|
if game_over
|
47
|
+
@pause_menu_item.enabled = false
|
46
48
|
show_game_over_dialog
|
47
49
|
else
|
50
|
+
@pause_menu_item.enabled = true
|
48
51
|
start_moving_tetrominos_down
|
49
52
|
end
|
50
53
|
end.observe(@game, :game_over)
|
@@ -102,6 +105,78 @@ class Tetris
|
|
102
105
|
end.observe(@game, :level)
|
103
106
|
end
|
104
107
|
|
108
|
+
def menu_bar
|
109
|
+
menu('Game') {
|
110
|
+
@pause_menu_item = check_menu_item('Pause') {
|
111
|
+
enabled false
|
112
|
+
|
113
|
+
on_clicked do
|
114
|
+
@game.paused = @pause_menu_item.checked?
|
115
|
+
end
|
116
|
+
}
|
117
|
+
menu_item('Restart') {
|
118
|
+
on_clicked do
|
119
|
+
@game.restart!
|
120
|
+
end
|
121
|
+
}
|
122
|
+
separator_menu_item
|
123
|
+
menu_item('Exit') {
|
124
|
+
on_clicked do
|
125
|
+
exit(0)
|
126
|
+
end
|
127
|
+
}
|
128
|
+
quit_menu_item if OS.mac?
|
129
|
+
}
|
130
|
+
|
131
|
+
menu('View') {
|
132
|
+
menu_item('Show High Scores') {
|
133
|
+
on_clicked do
|
134
|
+
show_high_scores
|
135
|
+
end
|
136
|
+
}
|
137
|
+
menu_item('Clear High Scores') {
|
138
|
+
on_clicked {
|
139
|
+
@game.clear_high_scores!
|
140
|
+
}
|
141
|
+
}
|
142
|
+
}
|
143
|
+
|
144
|
+
menu('Options') {
|
145
|
+
radio_menu_item('Instant Down on Up Arrow') {
|
146
|
+
on_clicked do
|
147
|
+
@game.instant_down_on_up = true
|
148
|
+
end
|
149
|
+
}
|
150
|
+
radio_menu_item('Rotate Right on Up Arrow') {
|
151
|
+
on_clicked do
|
152
|
+
@game.rotate_right_on_up = true
|
153
|
+
end
|
154
|
+
}
|
155
|
+
radio_menu_item('Rotate Left on Up Arrow') {
|
156
|
+
checked true
|
157
|
+
|
158
|
+
on_clicked do
|
159
|
+
@game.rotate_left_on_up = true
|
160
|
+
end
|
161
|
+
}
|
162
|
+
}
|
163
|
+
|
164
|
+
menu('Help') {
|
165
|
+
if OS.mac?
|
166
|
+
about_menu_item {
|
167
|
+
on_clicked do
|
168
|
+
show_about_dialog
|
169
|
+
end
|
170
|
+
}
|
171
|
+
end
|
172
|
+
menu_item('About') {
|
173
|
+
on_clicked do
|
174
|
+
show_about_dialog
|
175
|
+
end
|
176
|
+
}
|
177
|
+
}
|
178
|
+
end
|
179
|
+
|
105
180
|
def playfield(playfield_width: , playfield_height: , block_size: , &extra_content)
|
106
181
|
blocks = []
|
107
182
|
vertical_box {
|
@@ -162,26 +237,38 @@ class Tetris
|
|
162
237
|
on_key_down do |key_event|
|
163
238
|
case key_event
|
164
239
|
in ext_key: :down
|
165
|
-
|
240
|
+
if OS.windows?
|
241
|
+
# rate limit downs in Windows as they go too fast when key is held
|
242
|
+
@queued_downs ||= 0
|
243
|
+
if @queued_downs < 2
|
244
|
+
@queued_downs += 1
|
245
|
+
Glimmer::LibUI.timer(0.01, repeat: false) do
|
246
|
+
@game.down! if @queued_downs < 2
|
247
|
+
@queued_downs -= 1
|
248
|
+
end
|
249
|
+
end
|
250
|
+
else
|
251
|
+
@game.down!
|
252
|
+
end
|
166
253
|
in key: ' '
|
167
|
-
game.down!(instant: true)
|
254
|
+
@game.down!(instant: true)
|
168
255
|
in ext_key: :up
|
169
|
-
case game.up_arrow_action
|
256
|
+
case @game.up_arrow_action
|
170
257
|
when :instant_down
|
171
|
-
game.down!(instant: true)
|
258
|
+
@game.down!(instant: true)
|
172
259
|
when :rotate_right
|
173
|
-
game.rotate!(:right)
|
260
|
+
@game.rotate!(:right)
|
174
261
|
when :rotate_left
|
175
|
-
game.rotate!(:left)
|
262
|
+
@game.rotate!(:left)
|
176
263
|
end
|
177
264
|
in ext_key: :left
|
178
|
-
game.left!
|
265
|
+
@game.left!
|
179
266
|
in ext_key: :right
|
180
|
-
game.right!
|
267
|
+
@game.right!
|
181
268
|
in modifier: :shift
|
182
|
-
game.rotate!(:right)
|
269
|
+
@game.rotate!(:right)
|
183
270
|
in modifier: :control
|
184
|
-
game.rotate!(:left)
|
271
|
+
@game.rotate!(:left)
|
185
272
|
else
|
186
273
|
# Do Nothing
|
187
274
|
end
|
@@ -246,17 +333,42 @@ class Tetris
|
|
246
333
|
end
|
247
334
|
|
248
335
|
def start_moving_tetrominos_down
|
249
|
-
|
250
|
-
@
|
336
|
+
unless @tetrominos_start_moving_down
|
337
|
+
@tetrominos_start_moving_down = true
|
338
|
+
Glimmer::LibUI.timer(@game.delay) do
|
339
|
+
@game.down! if !@game.game_over? && !@game.paused?
|
340
|
+
end
|
251
341
|
end
|
252
342
|
end
|
253
343
|
|
254
344
|
def show_game_over_dialog
|
255
345
|
Glimmer::LibUI.queue_main do
|
256
|
-
msg_box('Game Over', "Score: #{@game.high_scores.first.score}\nLines: #{@game.high_scores.first.lines}\nLevel: #{@game.high_scores.first.level}")
|
346
|
+
msg_box('Game Over!', "Score: #{@game.high_scores.first.score}\nLines: #{@game.high_scores.first.lines}\nLevel: #{@game.high_scores.first.level}")
|
257
347
|
@game.restart!
|
258
348
|
end
|
259
349
|
end
|
350
|
+
|
351
|
+
def show_high_scores
|
352
|
+
Glimmer::LibUI.queue_main do
|
353
|
+
game_paused = !!@game.paused
|
354
|
+
@game.paused = true
|
355
|
+
if @game.high_scores.empty?
|
356
|
+
high_scores_string = "No games have been scored yet."
|
357
|
+
else
|
358
|
+
high_scores_string = @game.high_scores.map do |high_score|
|
359
|
+
"#{high_score.name} | Score: #{high_score.score} | Lines: #{high_score.lines} | Level: #{high_score.level}"
|
360
|
+
end.join("\n")
|
361
|
+
end
|
362
|
+
msg_box('High Scores', high_scores_string)
|
363
|
+
@game.paused = game_paused
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
def show_about_dialog
|
368
|
+
Glimmer::LibUI.queue_main do
|
369
|
+
msg_box('About', 'Glimmer Tetris - Glimmer DSL for LibUI Example - Copyright (c) 2021 Andy Maleh')
|
370
|
+
end
|
371
|
+
end
|
260
372
|
end
|
261
373
|
|
262
374
|
Tetris.new.launch
|