minigl 2.2.2 → 2.2.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -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