minigl 2.2.2 → 2.2.3

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.
@@ -1,256 +1,256 @@
1
- require_relative 'global'
2
-
3
- module MiniGL
4
- # This class provides easy control of a tile map, i.e., a map consisting of
5
- # a grid of equally sized tiles. It also provides viewport control, through
6
- # its camera property and methods.
7
- class Map
8
- SQRT_2_DIV_2 = Math.sqrt(2) / 2 # :nodoc:
9
- MINUS_PI_DIV_4 = -Math::PI / 4 # :nodoc:
10
-
11
- # A Vector where x is the tile width and y is the tile height.
12
- attr_reader :tile_size
13
-
14
- # A Vector where x is the horizontal tile count and y the vertical count.
15
- attr_reader :size
16
-
17
- # A Rectangle representing the region of the map that is currently
18
- # visible.
19
- attr_reader :cam
20
-
21
- # Creates a new map.
22
- #
23
- # Parameters:
24
- # [t_w] The width of the tiles.
25
- # [t_h] The height of the tiles.
26
- # [t_x_count] The horizontal count of tiles in the map.
27
- # [t_y_count] The vertical count of tiles in the map.
28
- # [scr_w] Width of the viewport for the map.
29
- # [scr_h] Height of the viewport for the map.
30
- # [isometric] Whether to use a isometric map. By default, an ortogonal map
31
- # is used.
32
- # [limit_cam] Whether the camera should respect the bounds of the map
33
- # (i.e., when given coordinates that would imply regions
34
- # outside the map to appear in the screen, the camera would
35
- # move to the nearest position where only the map shows up
36
- # in the screen).
37
- def initialize(t_w, t_h, t_x_count, t_y_count, scr_w = 800, scr_h = 600, isometric = false, limit_cam = true)
38
- @tile_size = Vector.new t_w, t_h
39
- @size = Vector.new t_x_count, t_y_count
40
- @cam = Rectangle.new 0, 0, scr_w, scr_h
41
- @limit_cam = limit_cam
42
- @isometric = isometric
43
- if isometric
44
- initialize_isometric
45
- elsif limit_cam
46
- @max_x = t_x_count * t_w - scr_w
47
- @max_y = t_y_count * t_h - scr_h
48
- end
49
- set_camera 0, 0
50
- end
51
-
52
- # Returns a Vector with the total size of the map, in pixels (x for the
53
- # width and y for the height).
54
- def get_absolute_size
55
- return Vector.new(@tile_size.x * @size.x, @tile_size.y * @size.y) unless @isometric
56
- avg = (@size.x + @size.y) * 0.5
57
- Vector.new (avg * @tile_size.x).to_i, (avg * @tile_size.y).to_i
58
- end
59
-
60
- # Returns a Vector with the coordinates of the center of the map.
61
- def get_center
62
- abs_size = get_absolute_size
63
- Vector.new(abs_size.x * 0.5, abs_size.y * 0.5)
64
- end
65
-
66
- # Returns the position in the screen corresponding to the given tile
67
- # indices.
68
- #
69
- # Parameters:
70
- # [map_x] The index of the tile in the horizontal direction. It must be in
71
- # the interval <code>0..t_x_count</code>.
72
- # [map_y] The index of the tile in the vertical direction. It must be in
73
- # the interval <code>0..t_y_count</code>.
74
- def get_screen_pos(map_x, map_y)
75
- return Vector.new(map_x * @tile_size.x - @cam.x, map_y * @tile_size.y - @cam.y) unless @isometric
76
- Vector.new ((map_x - map_y - 1) * @tile_size.x * 0.5) - @cam.x + @x_offset,
77
- ((map_x + map_y) * @tile_size.y * 0.5) - @cam.y
78
- end
79
-
80
- # Returns the tile in the map that corresponds to the given position in
81
- # the screen, as a Vector, where x is the horizontal index and y the
82
- # vertical index.
83
- #
84
- # Parameters:
85
- # [scr_x] The x-coordinate in the screen.
86
- # [scr_y] The y-coordinate in the screen.
87
- def get_map_pos(scr_x, scr_y)
88
- return Vector.new((scr_x + @cam.x) / @tile_size.x, (scr_y + @cam.y) / @tile_size.y) unless @isometric
89
-
90
- # Obtém a posição transformada para as coordenadas isométricas
91
- v = get_isometric_position scr_x, scr_y
92
-
93
- # Depois divide pelo tamanho do quadrado para achar a posição da matriz
94
- Vector.new((v.x * @inverse_square_size).to_i, (v.y * @inverse_square_size).to_i)
95
- end
96
-
97
- # Verifies whether a tile is inside the map.
98
- #
99
- # Parameters:
100
- # [v] A Vector representing the tile, with x as the horizontal index and
101
- # y as the vertical index.
102
- def is_in_map(v)
103
- v.x >= 0 && v.y >= 0 && v.x < @size.x && v.y < @size.y
104
- end
105
-
106
- # Sets the top left corner of the viewport to the given position of the
107
- # map. Note that this is not the position in the screen.
108
- #
109
- # Parameters:
110
- # [cam_x] The x-coordinate inside the map, in pixels (not a tile index).
111
- # [cam_y] The y-coordinate inside the map, in pixels (not a tile index).
112
- def set_camera(cam_x, cam_y)
113
- @cam.x = cam_x
114
- @cam.y = cam_y
115
- set_bounds
116
- end
117
-
118
- # Moves the viewport by the given amount of pixels.
119
- #
120
- # Parameters:
121
- # [x] The amount of pixels to move horizontally. Negative values will
122
- # cause the camera to move to the left.
123
- # [y] The amount of pixels to move vertically. Negative values will cause
124
- # the camera to move up.
125
- def move_camera(x, y)
126
- @cam.x += x
127
- @cam.y += y
128
- set_bounds
129
- end
130
-
131
- # Iterates through the currently visible tiles, providing the horizontal
132
- # tile index, the vertical tile index, the x-coordinate (in pixels) and
133
- # the y-coordinate (in pixels), of each tile, in that order, to a given
134
- # block of code.
135
- #
136
- # Example:
137
- #
138
- # map.foreach do |i, j, x, y|
139
- # draw_tile tiles[i][j], x, y
140
- # end
141
- def foreach
142
- for j in @min_vis_y..@max_vis_y
143
- for i in @min_vis_x..@max_vis_x
144
- pos = get_screen_pos i, j
145
- yield i, j, pos.x, pos.y
146
- end
147
- end
148
- end
149
-
150
- private
151
-
152
- def set_bounds
153
- if @limit_cam
154
- if @isometric
155
- v1 = get_isometric_position(0, 0)
156
- v2 = get_isometric_position(@cam.w - 1, 0)
157
- v3 = get_isometric_position(@cam.w - 1, @cam.h - 1)
158
- v4 = get_isometric_position(0, @cam.h - 1)
159
- if v1.x < -@max_offset
160
- offset = -(v1.x + @max_offset)
161
- @cam.x += offset * SQRT_2_DIV_2
162
- @cam.y += offset * SQRT_2_DIV_2 / @tile_ratio
163
- v1.x = -@max_offset
164
- end
165
- if v2.y < -@max_offset
166
- offset = -(v2.y + @max_offset)
167
- @cam.x -= offset * SQRT_2_DIV_2
168
- @cam.y += offset * SQRT_2_DIV_2 / @tile_ratio
169
- v2.y = -@max_offset
170
- end
171
- if v3.x > @iso_abs_size.x + @max_offset
172
- offset = v3.x - @iso_abs_size.x - @max_offset
173
- @cam.x -= offset * SQRT_2_DIV_2
174
- @cam.y -= offset * SQRT_2_DIV_2 / @tile_ratio
175
- v3.x = @iso_abs_size.x + @max_offset
176
- end
177
- if v4.y > @iso_abs_size.y + @max_offset
178
- offset = v4.y - @iso_abs_size.y - @max_offset
179
- @cam.x += offset * SQRT_2_DIV_2
180
- @cam.y -= offset * SQRT_2_DIV_2 / @tile_ratio
181
- v4.y = @iso_abs_size.y + @max_offset
182
- end
183
- else
184
- @cam.x = @max_x if @cam.x > @max_x
185
- @cam.x = 0 if @cam.x < 0
186
- @cam.y = @max_y if @cam.y > @max_y
187
- @cam.y = 0 if @cam.y < 0
188
- end
189
- end
190
-
191
- @cam.x = @cam.x.round
192
- @cam.y = @cam.y.round
193
- if @isometric
194
- @min_vis_x = get_map_pos(0, 0).x
195
- @min_vis_y = get_map_pos(@cam.w - 1, 0).y
196
- @max_vis_x = get_map_pos(@cam.w - 1, @cam.h - 1).x
197
- @max_vis_y = get_map_pos(0, @cam.h - 1).y
198
- else
199
- @min_vis_x = @cam.x / @tile_size.x
200
- @min_vis_y = @cam.y / @tile_size.y
201
- @max_vis_x = (@cam.x + @cam.w - 1) / @tile_size.x
202
- @max_vis_y = (@cam.y + @cam.h - 1) / @tile_size.y
203
- end
204
-
205
- if @min_vis_y < 0; @min_vis_y = 0
206
- elsif @min_vis_y > @size.y - 1; @min_vis_y = @size.y - 1; end
207
-
208
- if @max_vis_y < 0; @max_vis_y = 0
209
- elsif @max_vis_y > @size.y - 1; @max_vis_y = @size.y - 1; end
210
-
211
- if @min_vis_x < 0; @min_vis_x = 0
212
- elsif @min_vis_x > @size.x - 1; @min_vis_x = @size.x - 1; end
213
-
214
- if @max_vis_x < 0; @max_vis_x = 0
215
- elsif @max_vis_x > @size.x - 1; @max_vis_x = @size.x - 1; end
216
- end
217
-
218
- def initialize_isometric
219
- @x_offset = (@size.y * 0.5 * @tile_size.x).round
220
- @tile_ratio = @tile_size.x.to_f / @tile_size.y
221
- square_size = @tile_size.x * SQRT_2_DIV_2
222
- @inverse_square_size = 1 / square_size
223
- @iso_abs_size = Vector.new(square_size * @size.x, square_size * @size.y)
224
- a = (@size.x + @size.y) * 0.5 * @tile_size.x
225
- @isometric_offset_x = (a - square_size * @size.x) * 0.5
226
- @isometric_offset_y = (a - square_size * @size.y) * 0.5
227
- if @limit_cam
228
- actual_cam_h = @cam.h * @tile_ratio
229
- @max_offset = actual_cam_h < @cam.w ? actual_cam_h : @cam.w
230
- @max_offset *= SQRT_2_DIV_2
231
- end
232
- end
233
-
234
- def get_isometric_position(scr_x, scr_y)
235
- # Escreve a posição em relação a origem (no centro do mapa)
236
- center = get_center
237
- position = Vector.new scr_x + @cam.x - center.x, scr_y + @cam.y - center.y
238
-
239
- # Multiplica por tile_ratio para obter tiles quadrados
240
- position.y *= @tile_ratio
241
-
242
- # O centro do mapa também é deslocado
243
- center.y *= @tile_ratio
244
-
245
- # Rotaciona o vetor posição -45°
246
- position.rotate! MINUS_PI_DIV_4
247
-
248
- # Retorna a referência da posição para o canto da tela
249
- position += center
250
-
251
- # O mapa quadrado está centralizado no centro do losango, precisa retornar ao canto da tela
252
- position.x -= @isometric_offset_x; position.y -= @isometric_offset_y
253
- position
254
- end
255
- end
256
- end
1
+ require_relative 'global'
2
+
3
+ module MiniGL
4
+ # This class provides easy control of a tile map, i.e., a map consisting of
5
+ # a grid of equally sized tiles. It also provides viewport control, through
6
+ # its camera property and methods.
7
+ class Map
8
+ SQRT_2_DIV_2 = Math.sqrt(2) / 2 # :nodoc:
9
+ MINUS_PI_DIV_4 = -Math::PI / 4 # :nodoc:
10
+
11
+ # A Vector where x is the tile width and y is the tile height.
12
+ attr_reader :tile_size
13
+
14
+ # A Vector where x is the horizontal tile count and y the vertical count.
15
+ attr_reader :size
16
+
17
+ # A Rectangle representing the region of the map that is currently
18
+ # visible.
19
+ attr_reader :cam
20
+
21
+ # Creates a new map.
22
+ #
23
+ # Parameters:
24
+ # [t_w] The width of the tiles.
25
+ # [t_h] The height of the tiles.
26
+ # [t_x_count] The horizontal count of tiles in the map.
27
+ # [t_y_count] The vertical count of tiles in the map.
28
+ # [scr_w] Width of the viewport for the map.
29
+ # [scr_h] Height of the viewport for the map.
30
+ # [isometric] Whether to use a isometric map. By default, an ortogonal map
31
+ # is used.
32
+ # [limit_cam] Whether the camera should respect the bounds of the map
33
+ # (i.e., when given coordinates that would imply regions
34
+ # outside the map to appear in the screen, the camera would
35
+ # move to the nearest position where only the map shows up
36
+ # in the screen).
37
+ def initialize(t_w, t_h, t_x_count, t_y_count, scr_w = 800, scr_h = 600, isometric = false, limit_cam = true)
38
+ @tile_size = Vector.new t_w, t_h
39
+ @size = Vector.new t_x_count, t_y_count
40
+ @cam = Rectangle.new 0, 0, scr_w, scr_h
41
+ @limit_cam = limit_cam
42
+ @isometric = isometric
43
+ if isometric
44
+ initialize_isometric
45
+ elsif limit_cam
46
+ @max_x = t_x_count * t_w - scr_w
47
+ @max_y = t_y_count * t_h - scr_h
48
+ end
49
+ set_camera 0, 0
50
+ end
51
+
52
+ # Returns a Vector with the total size of the map, in pixels (x for the
53
+ # width and y for the height).
54
+ def get_absolute_size
55
+ return Vector.new(@tile_size.x * @size.x, @tile_size.y * @size.y) unless @isometric
56
+ avg = (@size.x + @size.y) * 0.5
57
+ Vector.new (avg * @tile_size.x).to_i, (avg * @tile_size.y).to_i
58
+ end
59
+
60
+ # Returns a Vector with the coordinates of the center of the map.
61
+ def get_center
62
+ abs_size = get_absolute_size
63
+ Vector.new(abs_size.x * 0.5, abs_size.y * 0.5)
64
+ end
65
+
66
+ # Returns the position in the screen corresponding to the given tile
67
+ # indices.
68
+ #
69
+ # Parameters:
70
+ # [map_x] The index of the tile in the horizontal direction. It must be in
71
+ # the interval <code>0..t_x_count</code>.
72
+ # [map_y] The index of the tile in the vertical direction. It must be in
73
+ # the interval <code>0..t_y_count</code>.
74
+ def get_screen_pos(map_x, map_y)
75
+ return Vector.new(map_x * @tile_size.x - @cam.x, map_y * @tile_size.y - @cam.y) unless @isometric
76
+ Vector.new ((map_x - map_y - 1) * @tile_size.x * 0.5) - @cam.x + @x_offset,
77
+ ((map_x + map_y) * @tile_size.y * 0.5) - @cam.y
78
+ end
79
+
80
+ # Returns the tile in the map that corresponds to the given position in
81
+ # the screen, as a Vector, where x is the horizontal index and y the
82
+ # vertical index.
83
+ #
84
+ # Parameters:
85
+ # [scr_x] The x-coordinate in the screen.
86
+ # [scr_y] The y-coordinate in the screen.
87
+ def get_map_pos(scr_x, scr_y)
88
+ return Vector.new((scr_x + @cam.x) / @tile_size.x, (scr_y + @cam.y) / @tile_size.y) unless @isometric
89
+
90
+ # Obtém a posição transformada para as coordenadas isométricas
91
+ v = get_isometric_position scr_x, scr_y
92
+
93
+ # Depois divide pelo tamanho do quadrado para achar a posição da matriz
94
+ Vector.new((v.x * @inverse_square_size).to_i, (v.y * @inverse_square_size).to_i)
95
+ end
96
+
97
+ # Verifies whether a tile is inside the map.
98
+ #
99
+ # Parameters:
100
+ # [v] A Vector representing the tile, with x as the horizontal index and
101
+ # y as the vertical index.
102
+ def is_in_map(v)
103
+ v.x >= 0 && v.y >= 0 && v.x < @size.x && v.y < @size.y
104
+ end
105
+
106
+ # Sets the top left corner of the viewport to the given position of the
107
+ # map. Note that this is not the position in the screen.
108
+ #
109
+ # Parameters:
110
+ # [cam_x] The x-coordinate inside the map, in pixels (not a tile index).
111
+ # [cam_y] The y-coordinate inside the map, in pixels (not a tile index).
112
+ def set_camera(cam_x, cam_y)
113
+ @cam.x = cam_x
114
+ @cam.y = cam_y
115
+ set_bounds
116
+ end
117
+
118
+ # Moves the viewport by the given amount of pixels.
119
+ #
120
+ # Parameters:
121
+ # [x] The amount of pixels to move horizontally. Negative values will
122
+ # cause the camera to move to the left.
123
+ # [y] The amount of pixels to move vertically. Negative values will cause
124
+ # the camera to move up.
125
+ def move_camera(x, y)
126
+ @cam.x += x
127
+ @cam.y += y
128
+ set_bounds
129
+ end
130
+
131
+ # Iterates through the currently visible tiles, providing the horizontal
132
+ # tile index, the vertical tile index, the x-coordinate (in pixels) and
133
+ # the y-coordinate (in pixels), of each tile, in that order, to a given
134
+ # block of code.
135
+ #
136
+ # Example:
137
+ #
138
+ # map.foreach do |i, j, x, y|
139
+ # draw_tile tiles[i][j], x, y
140
+ # end
141
+ def foreach
142
+ for j in @min_vis_y..@max_vis_y
143
+ for i in @min_vis_x..@max_vis_x
144
+ pos = get_screen_pos i, j
145
+ yield i, j, pos.x, pos.y
146
+ end
147
+ end
148
+ end
149
+
150
+ private
151
+
152
+ def set_bounds
153
+ if @limit_cam
154
+ if @isometric
155
+ v1 = get_isometric_position(0, 0)
156
+ v2 = get_isometric_position(@cam.w - 1, 0)
157
+ v3 = get_isometric_position(@cam.w - 1, @cam.h - 1)
158
+ v4 = get_isometric_position(0, @cam.h - 1)
159
+ if v1.x < -@max_offset
160
+ offset = -(v1.x + @max_offset)
161
+ @cam.x += offset * SQRT_2_DIV_2
162
+ @cam.y += offset * SQRT_2_DIV_2 / @tile_ratio
163
+ v1.x = -@max_offset
164
+ end
165
+ if v2.y < -@max_offset
166
+ offset = -(v2.y + @max_offset)
167
+ @cam.x -= offset * SQRT_2_DIV_2
168
+ @cam.y += offset * SQRT_2_DIV_2 / @tile_ratio
169
+ v2.y = -@max_offset
170
+ end
171
+ if v3.x > @iso_abs_size.x + @max_offset
172
+ offset = v3.x - @iso_abs_size.x - @max_offset
173
+ @cam.x -= offset * SQRT_2_DIV_2
174
+ @cam.y -= offset * SQRT_2_DIV_2 / @tile_ratio
175
+ v3.x = @iso_abs_size.x + @max_offset
176
+ end
177
+ if v4.y > @iso_abs_size.y + @max_offset
178
+ offset = v4.y - @iso_abs_size.y - @max_offset
179
+ @cam.x += offset * SQRT_2_DIV_2
180
+ @cam.y -= offset * SQRT_2_DIV_2 / @tile_ratio
181
+ v4.y = @iso_abs_size.y + @max_offset
182
+ end
183
+ else
184
+ @cam.x = @max_x if @cam.x > @max_x
185
+ @cam.x = 0 if @cam.x < 0
186
+ @cam.y = @max_y if @cam.y > @max_y
187
+ @cam.y = 0 if @cam.y < 0
188
+ end
189
+ end
190
+
191
+ @cam.x = @cam.x.round
192
+ @cam.y = @cam.y.round
193
+ if @isometric
194
+ @min_vis_x = get_map_pos(0, 0).x
195
+ @min_vis_y = get_map_pos(@cam.w - 1, 0).y
196
+ @max_vis_x = get_map_pos(@cam.w - 1, @cam.h - 1).x
197
+ @max_vis_y = get_map_pos(0, @cam.h - 1).y
198
+ else
199
+ @min_vis_x = @cam.x / @tile_size.x
200
+ @min_vis_y = @cam.y / @tile_size.y
201
+ @max_vis_x = (@cam.x + @cam.w - 1) / @tile_size.x
202
+ @max_vis_y = (@cam.y + @cam.h - 1) / @tile_size.y
203
+ end
204
+
205
+ if @min_vis_y < 0; @min_vis_y = 0
206
+ elsif @min_vis_y > @size.y - 1; @min_vis_y = @size.y - 1; end
207
+
208
+ if @max_vis_y < 0; @max_vis_y = 0
209
+ elsif @max_vis_y > @size.y - 1; @max_vis_y = @size.y - 1; end
210
+
211
+ if @min_vis_x < 0; @min_vis_x = 0
212
+ elsif @min_vis_x > @size.x - 1; @min_vis_x = @size.x - 1; end
213
+
214
+ if @max_vis_x < 0; @max_vis_x = 0
215
+ elsif @max_vis_x > @size.x - 1; @max_vis_x = @size.x - 1; end
216
+ end
217
+
218
+ def initialize_isometric
219
+ @x_offset = (@size.y * 0.5 * @tile_size.x).round
220
+ @tile_ratio = @tile_size.x.to_f / @tile_size.y
221
+ square_size = @tile_size.x * SQRT_2_DIV_2
222
+ @inverse_square_size = 1 / square_size
223
+ @iso_abs_size = Vector.new(square_size * @size.x, square_size * @size.y)
224
+ a = (@size.x + @size.y) * 0.5 * @tile_size.x
225
+ @isometric_offset_x = (a - square_size * @size.x) * 0.5
226
+ @isometric_offset_y = (a - square_size * @size.y) * 0.5
227
+ if @limit_cam
228
+ actual_cam_h = @cam.h * @tile_ratio
229
+ @max_offset = actual_cam_h < @cam.w ? actual_cam_h : @cam.w
230
+ @max_offset *= SQRT_2_DIV_2
231
+ end
232
+ end
233
+
234
+ def get_isometric_position(scr_x, scr_y)
235
+ # Escreve a posição em relação a origem (no centro do mapa)
236
+ center = get_center
237
+ position = Vector.new scr_x + @cam.x - center.x, scr_y + @cam.y - center.y
238
+
239
+ # Multiplica por tile_ratio para obter tiles quadrados
240
+ position.y *= @tile_ratio
241
+
242
+ # O centro do mapa também é deslocado
243
+ center.y *= @tile_ratio
244
+
245
+ # Rotaciona o vetor posição -45°
246
+ position.rotate! MINUS_PI_DIV_4
247
+
248
+ # Retorna a referência da posição para o canto da tela
249
+ position += center
250
+
251
+ # O mapa quadrado está centralizado no centro do losango, precisa retornar ao canto da tela
252
+ position.x -= @isometric_offset_x; position.y -= @isometric_offset_y
253
+ position
254
+ end
255
+ end
256
+ end