tetris_pavliad1 1.0.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 639a433ef0f1442237b6f448da486ffea0a074c00169c701838cdf3690b4297f
4
+ data.tar.gz: 695d79d3a643e21f7c3f76d1a58c996d8273aa8ab27708de39796871bd987233
5
+ SHA512:
6
+ metadata.gz: c41aabaf0969ed78784dd4fe65783b996def5a0e919e58eae80b9a88753fd1484b0bbd7d7200eab33aee60be76477357a86fe266b29a2ece448ed5bb37444d4a
7
+ data.tar.gz: 3539b7706e555e72e1e42e94f02d6ad3782c6e1749924264786bfb7bb9c134b79301a0e2eadba4888c064408c085b88c8dd95460c0dcbc8ded9ecbd803dc0978
data/bin/tetris ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'tetris'
4
+
5
+ Tetris.new.show
data/lib/game.rb ADDED
@@ -0,0 +1,184 @@
1
+ require 'player'
2
+ require 'menuitem'
3
+
4
+ class Game
5
+ EMPTY = Gosu::Color::BLACK
6
+
7
+ attr_reader :score, :game_over, :current_difficulty
8
+
9
+ def initialize(window, x, y, height, width, block_size, difficulty)
10
+ @window = window
11
+ @x = x
12
+ @y = y
13
+ @height = height
14
+ @width = width
15
+ @block_size = block_size
16
+ @difficulty = difficulty
17
+ @current_difficulty = difficulty.zero? ? 1 : difficulty
18
+
19
+ @data = Array.new(height) { Array.new(width, EMPTY) }
20
+
21
+ @ticks = 0
22
+ @score = 0
23
+ @game_over = false
24
+
25
+ create_new_player_entity
26
+
27
+ end
28
+
29
+ def update
30
+ return if game_over
31
+
32
+ @ticks += 1
33
+ threshold = 60.0 - 5 * @current_difficulty
34
+ if @ticks >= threshold
35
+ move(0, 1)
36
+ @ticks = 0
37
+ end
38
+ end
39
+
40
+ def create_new_player_entity
41
+ entities = [Triangle, Square, El, ElTwo, Tower, Zet, ZetTwo]
42
+ random = rand(0..entities.size - 1)
43
+ @player = entities[random].new(@width / 2, 0)
44
+ @player.x = @player.x - @player.width / 2
45
+
46
+ if collision?
47
+ @game_over = true
48
+ @window.add_score(@score)
49
+ end
50
+
51
+ end
52
+
53
+ def is_within_bounds(x_offset, y_offset)
54
+ @player.x + x_offset >= 0 &&
55
+ @player.x + x_offset + @player.width - 1 < @width &&
56
+ @player.y + y_offset >= 0 &&
57
+ @player.y + y_offset + @player.height - 1 < @height
58
+ end
59
+
60
+ def collision?
61
+ (0..@player.width - 1).each do |x|
62
+ (0..@player.height - 1).each do |y|
63
+ next unless @player.is_brick(x, y)
64
+
65
+ return true if @data[@player.y + y][@player.x + x] != EMPTY
66
+ end
67
+ end
68
+
69
+ false
70
+ end
71
+
72
+ def move(x_offset, y_offset)
73
+ return if !is_within_bounds(x_offset, y_offset) || game_over
74
+
75
+ @player.x = @player.x + x_offset
76
+ @player.y = @player.y + y_offset
77
+
78
+ if collision?
79
+ @player.x = @player.x + x_offset * -1
80
+ @player.y = @player.y + y_offset * -1
81
+
82
+ if y_offset == 1
83
+ imprint_player_to_grid
84
+ create_new_player_entity
85
+ end
86
+ elsif @player.y + @player.height >= @height
87
+ imprint_player_to_grid
88
+ create_new_player_entity
89
+ end
90
+
91
+ end
92
+
93
+ def compare_color(a, b)
94
+ a.alpha == b.alpha &&
95
+ a.red == b.red &&
96
+ a.green == b.green &&
97
+ a.blue == b.blue
98
+ end
99
+
100
+ def full_row?(row_id)
101
+ @data[row_id].filter { |x| !compare_color(x, EMPTY) }.size == @width
102
+ end
103
+
104
+ def imprint_player_to_grid
105
+ (0..@player.width - 1).each do |x|
106
+ (0..@player.height - 1).each do |y|
107
+ next unless @player.is_brick(x, y)
108
+
109
+ @data[@player.y + y][@player.x + x] = @player.color
110
+ end
111
+ end
112
+
113
+ (@player.y..@player.y + @player.height - 1).each do |row_id|
114
+ score_and_update_row(row_id) if full_row?(row_id)
115
+ end
116
+ end
117
+
118
+ def fast_move
119
+ @player.y += 1 while !collision? && is_within_bounds(0, 1)
120
+
121
+ @player.y = @player.y - 1
122
+ move(0, 1)
123
+ end
124
+
125
+ def rotate
126
+ @player.rotate
127
+
128
+ @player.rotate_rollback if !is_within_bounds(0, 0) || collision?
129
+ end
130
+
131
+ def score_and_update_row(row_id)
132
+ @data.delete_at(row_id)
133
+ @data.prepend(Array.new(@width, EMPTY))
134
+ @score += @current_difficulty
135
+
136
+ @current_difficulty += 1 if @difficulty.zero? && @current_difficulty < Difficulty::MAX_DIFFICULTY
137
+ end
138
+
139
+ def draw(context)
140
+ context.draw_rect(@x, @y, @width * @block_size, @height * @block_size, Gosu::Color::GRAY)
141
+ (0..@width - 1).each do |x|
142
+ (0..@height - 1).each do |y|
143
+ next if @data[y][x] == EMPTY
144
+
145
+ draw_brick(context, x, y, @data[y][x])
146
+ end
147
+ end
148
+
149
+ draw_player(context)
150
+
151
+ if game_over
152
+ context.font.draw_text('Game over!', 250, 100, ZOrder::UI, 1.0, 1.0, Gosu::Color::YELLOW)
153
+ end
154
+ end
155
+
156
+ def draw_player(context)
157
+ return if game_over
158
+
159
+ (0..@player.width - 1).each do |x|
160
+ (0..@player.height - 1).each do |y|
161
+ next unless @player.is_brick(x, y)
162
+
163
+ draw_brick(context, @player.x + x, @player.y + y, @player.color)
164
+ end
165
+ end
166
+ end
167
+
168
+ def draw_brick(context, x, y, color)
169
+ outer_color = Gosu::Color.new(color.alpha / 2, color.red, color.green, color.blue)
170
+
171
+ context.draw_rect(@x + x * @block_size,
172
+ @y + y * @block_size,
173
+ @block_size,
174
+ @block_size,
175
+ outer_color)
176
+
177
+ padding = 2
178
+ context.draw_rect(@x + x * @block_size + padding,
179
+ @y + y * @block_size + padding,
180
+ @block_size - 2 * padding,
181
+ @block_size - 2 * padding,
182
+ color)
183
+ end
184
+ end
data/lib/menuitem.rb ADDED
@@ -0,0 +1,108 @@
1
+ require 'gosu'
2
+
3
+ class MenuItem
4
+ def initialize(x, y, window)
5
+ @x = x
6
+ @y = y
7
+ @window = window
8
+ @selected = false
9
+ end
10
+
11
+ def button_down(id)
12
+ on_enter if [Gosu::KB_ENTER, 40].include?(id) # 40 = big enter
13
+ end
14
+
15
+ def unselect
16
+ @selected = false
17
+ end
18
+
19
+ def select
20
+ @selected = true
21
+ end
22
+
23
+ def on_enter; end
24
+
25
+ def draw
26
+ @window.font.draw_text(@text.to_s, @x, @y, ZOrder::UI, 1.0, 1.0, @selected ? Gosu::Color::RED : Gosu::Color::YELLOW)
27
+ end
28
+ end
29
+
30
+ class NewGame < MenuItem
31
+ def initialize(x, y, window)
32
+ super(x, y, window)
33
+ @text = 'New Game'
34
+ end
35
+
36
+ def on_enter
37
+ @window.new_game
38
+ end
39
+ end
40
+
41
+ class Continue < MenuItem
42
+ def initialize(x, y, window)
43
+ super(x, y, window)
44
+ @text = 'Continue'
45
+ end
46
+
47
+ def on_enter
48
+ @window.continue
49
+ end
50
+ end
51
+
52
+ class HighScore < MenuItem
53
+ def initialize(x, y, window)
54
+ super(x, y, window)
55
+ @text = 'High Score'
56
+ end
57
+
58
+ def on_enter
59
+ @window.high_score
60
+ end
61
+ end
62
+
63
+ class Quit < MenuItem
64
+ def initialize(x, y, window)
65
+ super(x, y, window)
66
+ @text = 'Quit'
67
+ end
68
+
69
+ def on_enter
70
+ @window.close
71
+ end
72
+ end
73
+
74
+ class Difficulty < MenuItem
75
+ MAX_DIFFICULTY = 10
76
+
77
+ attr_reader :difficulty
78
+
79
+ def initialize(x, y, window)
80
+ super(x, y, window)
81
+ @difficulty = 0
82
+ update_text
83
+ end
84
+
85
+ def button_down(id)
86
+ case id
87
+ when Gosu::KB_LEFT
88
+ change_difficulty(-1)
89
+ when Gosu::KB_RIGHT
90
+ change_difficulty(1)
91
+ else
92
+ super
93
+ end
94
+ end
95
+
96
+ def change_difficulty(direction)
97
+ if direction.positive?
98
+ @difficulty += 1 if @difficulty < MAX_DIFFICULTY
99
+ elsif @difficulty.positive?
100
+ @difficulty -= 1
101
+ end
102
+ update_text
103
+ end
104
+
105
+ def update_text
106
+ @text = "Difficulty: #{@difficulty.zero? ? 'Dynamic' : @difficulty}"
107
+ end
108
+ end
data/lib/player.rb ADDED
@@ -0,0 +1,99 @@
1
+ class Player
2
+
3
+ attr_accessor :x, :y
4
+ attr_reader :color
5
+
6
+ def initialize(x, y)
7
+ @x = x
8
+ @y = y
9
+ @color = Gosu::Color::BLACK
10
+ @data = nil
11
+ end
12
+
13
+ def is_brick(x, y)
14
+ raise 'Error player bounds' if x.negative? || x > width - 1 || y.negative? || y > height - 1
15
+
16
+ @data[y][x] == 1
17
+ end
18
+
19
+ def width
20
+ @data[0].size
21
+ end
22
+
23
+ def height
24
+ @data.size
25
+ end
26
+
27
+ def rotate
28
+ @data = @data.reverse.transpose
29
+ end
30
+
31
+ def rotate_rollback
32
+ @data = @data.transpose.reverse
33
+ end
34
+ end
35
+
36
+ class Triangle < Player
37
+ def initialize(x, y)
38
+ super(x, y)
39
+ @color = Gosu::Color::BLUE
40
+ @data = [[0, 1, 0],
41
+ [1, 1, 1]]
42
+ end
43
+
44
+ end
45
+
46
+ class Square < Player
47
+ def initialize(x, y)
48
+ super(x, y)
49
+ @color = Gosu::Color::RED
50
+ @data = [[1, 1],
51
+ [1, 1]]
52
+ end
53
+ end
54
+
55
+ class El < Player
56
+ def initialize(x, y)
57
+ super(x, y)
58
+ @color = Gosu::Color::YELLOW
59
+ @data = [[1, 1, 1],
60
+ [1, 0, 0]]
61
+ end
62
+ end
63
+
64
+ class ElTwo < Player
65
+ def initialize(x, y)
66
+ super(x, y)
67
+ @color = Gosu::Color.argb(0xFF, 0xFF, 0xA5, 0x00)
68
+ @data = [[1, 0, 0],
69
+ [1, 1, 1]]
70
+ end
71
+ end
72
+
73
+ class Tower < Player
74
+ def initialize(x, y)
75
+ super(x, y)
76
+ @color = Gosu::Color::FUCHSIA
77
+ @data = [[1, 1, 1, 1]]
78
+ end
79
+ end
80
+
81
+ class Zet < Player
82
+ def initialize(x, y)
83
+ super(x, y)
84
+ @color = Gosu::Color::GREEN
85
+ @data = [[1, 1, 0],
86
+ [0, 1, 1]]
87
+ end
88
+ end
89
+
90
+
91
+ class ZetTwo < Player
92
+ def initialize(x, y)
93
+ super(x, y)
94
+ @color = Gosu::Color::CYAN
95
+ @data = [[0, 1, 1],
96
+ [1, 1, 0]]
97
+ end
98
+ end
99
+
data/lib/scene.rb ADDED
@@ -0,0 +1,185 @@
1
+ # frozen_string_literal: true
2
+ require 'gosu'
3
+ require 'menuitem'
4
+ require 'game'
5
+
6
+ module ZOrder
7
+ BACKGROUND, STARS, PLAYER, UI = *0..3
8
+ end
9
+
10
+ class Scene
11
+ attr_reader :window
12
+
13
+ def initialize(window)
14
+ @window = window
15
+ end
16
+
17
+ def update; end
18
+
19
+ def draw; end
20
+
21
+ def button_down(id) end
22
+ end
23
+
24
+ class MainMenuScene < Scene
25
+
26
+ def initialize(window)
27
+ super(window)
28
+
29
+ @continue = Continue.new(150, 50, window)
30
+ @new_game = NewGame.new(150, 100, window)
31
+ @difficulty = Difficulty.new(150, 150, window)
32
+ @high_score = HighScore.new(150, 200, window)
33
+ @quit = Quit.new(150, 250, window)
34
+
35
+ @menu_items = [@new_game,
36
+ @difficulty,
37
+ @high_score,
38
+ @quit]
39
+ @selected_item = 0
40
+ @menu_items[0].select
41
+ end
42
+
43
+ def difficulty
44
+ @difficulty.difficulty
45
+ end
46
+
47
+ def add_continue
48
+ if @menu_items.size == 5
49
+ @menu_items[@selected_item].unselect
50
+ @selected_item = 0
51
+ else
52
+ @menu_items[0].unselect
53
+ @menu_items.prepend(@continue)
54
+ end
55
+
56
+ @menu_items[0].select
57
+ end
58
+
59
+ def remove_continue
60
+ @menu_items[0].unselect
61
+ @menu_items.drop(1)
62
+ @menu_items[0].select
63
+ @selected_item = 0
64
+ end
65
+
66
+ def button_down(id)
67
+ case id
68
+ when Gosu::KB_DOWN
69
+ down
70
+ when Gosu::KB_UP
71
+ up
72
+ else
73
+ @menu_items[@selected_item].button_down(id)
74
+ end
75
+ end
76
+
77
+ def draw
78
+ @menu_items.each(&:draw)
79
+ end
80
+
81
+ def down
82
+ @menu_items[@selected_item].unselect
83
+
84
+ @selected_item = if @selected_item == @menu_items.size - 1
85
+ 0
86
+ else
87
+ @selected_item + 1
88
+ end
89
+
90
+ @menu_items[@selected_item].select
91
+ end
92
+
93
+ def up
94
+ @menu_items[@selected_item].unselect
95
+
96
+ @selected_item = if @selected_item.zero?
97
+ @menu_items.size - 1
98
+ else
99
+ @selected_item - 1
100
+ end
101
+
102
+ @menu_items[@selected_item].select
103
+ end
104
+ end
105
+
106
+ class GameScene < Scene
107
+ WIDTH = 10
108
+ HEIGHT = 20
109
+ BLOCK_SIZE = 20 # pixels
110
+
111
+ def initialize(window, difficulty)
112
+ super(window)
113
+ @game = Game.new(window,10, 50, HEIGHT, WIDTH, BLOCK_SIZE, difficulty)
114
+ @ticks = 0
115
+ end
116
+
117
+ def update
118
+ @game.update
119
+ end
120
+
121
+ def button_down(id)
122
+
123
+ case id
124
+ when Gosu::KB_ESCAPE
125
+ @window.menu
126
+ when Gosu::KB_LEFT
127
+ @game.move(-1, 0)
128
+ when Gosu::KB_RIGHT
129
+ @game.move(1, 0)
130
+ when Gosu::KB_UP
131
+ @game.rotate
132
+ when Gosu::KB_DOWN
133
+ @game.move(0, 1)
134
+ when Gosu::KB_SPACE
135
+ @game.fast_move
136
+ end
137
+ end
138
+
139
+ def game_running?
140
+ !@game.game_over
141
+ end
142
+
143
+ def draw
144
+ @window.font.draw_text("Score: #{@game.score}", 10, 10, ZOrder::UI, 1.0, 1.0, Gosu::Color::YELLOW)
145
+ @window.font.draw_text("Speed: #{@game.current_difficulty}", 250, 10, ZOrder::UI, 1.0, 1.0, Gosu::Color::YELLOW)
146
+ @game.draw(@window)
147
+ end
148
+
149
+ end
150
+
151
+ class HighScoreScene < Scene
152
+ WIDTH = 10
153
+ HEIGHT = 20
154
+ BLOCK_SIZE = 20 # pixels
155
+
156
+ def initialize(window)
157
+ super(window)
158
+ @list = [0]
159
+
160
+ end
161
+
162
+ def add_score(score)
163
+ @list.append(score)
164
+ @list = @list.sort.reverse
165
+ end
166
+
167
+ def button_down(id)
168
+ @window.menu if id == Gosu::KB_ESCAPE
169
+ end
170
+
171
+ def draw
172
+
173
+ i = 1
174
+ x = 150
175
+ y = 10
176
+ @list.each do |l|
177
+ @window.font.draw_text("#{i}. #{l}", x, y, ZOrder::UI, 1.0, 1.0, Gosu::Color::YELLOW)
178
+ i += 1
179
+ y += 50
180
+ return if i >= 10
181
+ end
182
+
183
+ end
184
+
185
+ end
data/lib/tetris.rb ADDED
@@ -0,0 +1,60 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'scene'
4
+
5
+ class Tetris < Gosu::Window
6
+ attr_reader :font
7
+
8
+ WIDTH = 480
9
+ HEIGHT = 480
10
+ FONT_SIZE = 40
11
+
12
+ def initialize
13
+ super WIDTH, HEIGHT
14
+ self.caption = "Tetris"
15
+ @font = Gosu::Font.new(FONT_SIZE)
16
+ @menu_scene = MainMenuScene.new(self)
17
+ @hs_scene = HighScoreScene.new(self)
18
+ @game_scene = nil
19
+ @scene = @menu_scene
20
+ end
21
+
22
+ def update
23
+ @scene.update
24
+ end
25
+
26
+ def draw
27
+ @scene.draw
28
+ end
29
+
30
+ def button_down(id)
31
+ @scene.button_down id
32
+ end
33
+
34
+ def new_game
35
+ @menu_scene.add_continue
36
+ @game_scene = GameScene.new(self, @menu_scene.difficulty)
37
+ @scene = @game_scene
38
+ end
39
+
40
+ def high_score
41
+ @scene = @hs_scene
42
+ end
43
+
44
+ def add_score(score)
45
+ @hs_scene.add_score(score)
46
+ end
47
+
48
+ def continue
49
+ @scene = @game_scene
50
+ end
51
+
52
+ def game_running?
53
+ @game_scene&.game_running?
54
+ end
55
+
56
+ def menu
57
+ #code to pause game
58
+ @scene = @menu_scene
59
+ end
60
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tetris_pavliad1
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Adam Pavlis
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2021-02-12 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: gosu
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ description: Semestral work for subject NI-RUB of Adam Pavlis (pavliad1@fit.cvut.cz)
28
+ email: pavliad1@fit.cvut.cz
29
+ executables:
30
+ - tetris
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - bin/tetris
35
+ - lib/game.rb
36
+ - lib/menuitem.rb
37
+ - lib/player.rb
38
+ - lib/scene.rb
39
+ - lib/tetris.rb
40
+ homepage: https://rubygems.org/gems/tetris_pavliad1
41
+ licenses:
42
+ - MIT
43
+ metadata: {}
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - ">="
51
+ - !ruby/object:Gem::Version
52
+ version: '0'
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - ">="
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubygems_version: 3.0.3
60
+ signing_key:
61
+ specification_version: 4
62
+ summary: Simple imitation of classic Tetris
63
+ test_files: []