minigl 1.3.3 → 1.3.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d6075180b99d1cf18a53a683353828675ed18ca8
4
- data.tar.gz: c01f4bd208021a2bff3f2c1aa3f86eac0c7ff093
3
+ metadata.gz: f2d4aee75d7720a8a267a10b165430543f95768f
4
+ data.tar.gz: 6f5617de1e50714495a7f9e2f86213c33b7a8fb3
5
5
  SHA512:
6
- metadata.gz: 6981a60cbd32da81a0c96553536dd77b440ccd913cd1a612a23b64292051ec69924e6ed2058df2de72ef75a5db4f5869edec3ded25963d8012b999b17575285a
7
- data.tar.gz: 15e2fc67ac2b072da7e3a80b026fe5787b2df7804451aedd28d4e5a0f9e70dfd6ec299be7463b38e354279b87c27a6a9660d4fa00aaae6ae7f32fcad35d534ad
6
+ metadata.gz: f27a68517fb4284d1cf04c07e1c50402150915abc683432ef410c7c71ce2aba12bb951941a5a14e0a50372e155312812d97065c90f308b4c8aadbcb533d264fb
7
+ data.tar.gz: 7282c90ab81911f85445f54af4cd32e0ebd99f920fc346768c364028faddd913d04698db13aa73c9571d82b1dd70cffaf0fdf397960c9e079f1cf4968a874118
data/README.md CHANGED
@@ -4,6 +4,7 @@ MiniGL is a minimal **2D Game** Library, available as a Ruby gem, and built on
4
4
  top of the [Gosu](http://www.libgosu.org/) gem.
5
5
 
6
6
  It provides the following features:
7
+
7
8
  * Resource management (images, sounds, ...)
8
9
  * Input manipulation (keyboard, mouse, ...)
9
10
  * UI (text, buttons, text fields, ...)
@@ -13,6 +14,15 @@ It provides the following features:
13
14
  More functionalities are coming. Feel free to contribute! You can send feedback
14
15
  to victordavidsantos@gmail.com.
15
16
 
17
+ ## Installing
18
+
19
+ MiniGL was built on top of the Gosu gem, version 0.7.50. This gem has its own
20
+ dependencies for compiling extensions. Visit
21
+ [this page](https://github.com/jlnr/gosu/wiki/Getting-Started-on-Linux) for
22
+ details.
23
+
24
+ After installing Gosu, you can just `gem install minigl`.
25
+
16
26
  Please note:
17
27
 
18
28
  * The test package is not complete! Most of the functionality
@@ -22,11 +32,10 @@ this [working game example](https://github.com/victords/aventura-do-saber).
22
32
  * An auxiliary, tutorial-like documentation is under construction
23
33
  [here](https://github.com/victords/minigl/wiki).
24
34
 
25
- **Version 1.3.3**
26
-
27
- * Added `mass` attribute to the GameObject class and Movement module.
28
- * Added readers for the attributes of `Ramp`.
29
- * Added z-index support to all drawing functions.
35
+ **Version 1.3.4**
30
36
 
31
- **WARNING**: this version can generate incompatibility, because the `move`
32
- method of `Movement` now requires the calling object to have a `mass` attribute.
37
+ * Fixed issue when running the game from a directory other than the directory
38
+ of the game script.
39
+ * Added `prefix=` method to `Res`, allowing specification of the prefix for
40
+ the 'data' directory.
41
+ * Added the `limit_cam` and `isometric` options to the `Map` class.
data/lib/minigl/global.rb CHANGED
@@ -5,24 +5,24 @@ module AGL
5
5
  # A Struct with two attributes, x and y (in this order), representing a point
6
6
  # in a bidimensional space.
7
7
  Vector = Struct.new :x, :y
8
-
8
+
9
9
  # This class represents a rectangle by its x and y coordinates and width and
10
10
  # height.
11
11
  class Rectangle
12
12
  # The x-coordinate of the rectangle.
13
13
  attr_accessor :x
14
-
14
+
15
15
  # The y-coordinate of the rectangle.
16
16
  attr_accessor :y
17
-
17
+
18
18
  # The width of the rectangle.
19
19
  attr_accessor :w
20
-
20
+
21
21
  # The height of the rectangle.
22
22
  attr_accessor :h
23
-
23
+
24
24
  # Creates a new rectangle.
25
- #
25
+ #
26
26
  # Parameters:
27
27
  # [x] The x-coordinate of the rectangle.
28
28
  # [y] The y-coordinate of the rectangle.
@@ -31,22 +31,22 @@ module AGL
31
31
  def initialize x, y, w, h
32
32
  @x = x; @y = y; @w = w; @h = h
33
33
  end
34
-
34
+
35
35
  # Returns whether this rectangle intersects another.
36
- #
36
+ #
37
37
  # Parameters:
38
38
  # [r] The rectangle to check intersection with.
39
39
  def intersects r
40
40
  @x < r.x + r.w && @x + @w > r.x && @y < r.y + r.h && @y + @h > r.y
41
41
  end
42
42
  end
43
-
43
+
44
44
  # The main class for a MiniGL game, holds references to globally accessible
45
45
  # objects and constants.
46
46
  class Game
47
47
  # Initializes a MiniGL game. This method must be called before any feature
48
48
  # provided by the library can be used.
49
- #
49
+ #
50
50
  # Parameters:
51
51
  # [window] An instance of a class which inherits from
52
52
  # <code>Gosu::Window</code>. This will be the game window, used
@@ -72,31 +72,31 @@ module AGL
72
72
  @@kb_held_delay = kb_held_delay
73
73
  @@kb_held_interval = kb_held_interval
74
74
  @@double_click_delay = double_click_delay
75
-
75
+
76
76
  KB.initialize
77
77
  Mouse.initialize
78
78
  Res.initialize
79
79
  end
80
-
80
+
81
81
  # Returns a reference to the game window.
82
82
  def self.window; @@window; end
83
-
83
+
84
84
  # Returns a Vector representing the force of gravity. See +initialize+ for
85
85
  # details.
86
86
  def self.gravity; @@gravity; end
87
-
87
+
88
88
  # Returns the value of kb_held_delay. See +initialize+ for details.
89
89
  def self.kb_held_delay; @@kb_held_delay; end
90
-
90
+
91
91
  # Returns the value of kb_held_interval. See +initialize+ for details.
92
92
  def self.kb_held_interval; @@kb_held_interval; end
93
-
93
+
94
94
  # Returns the value of double_click_delay. See +initialize+ for details.
95
95
  def self.double_click_delay; @@double_click_delay; end
96
96
  end
97
-
97
+
98
98
  #class JSHelper
99
-
99
+
100
100
  # Exposes methods for controlling keyboard events.
101
101
  class KB
102
102
  # This is called by <code>Game.initialize</code>. Don't call it
@@ -127,7 +127,7 @@ module AGL
127
127
  @@held_timer = {}
128
128
  @@held_interval = {}
129
129
  end
130
-
130
+
131
131
  # Updates the state of all keys.
132
132
  def self.update
133
133
  @@held_timer.each do |k, v|
@@ -137,12 +137,12 @@ module AGL
137
137
  @@held_timer.delete k
138
138
  end
139
139
  end
140
-
140
+
141
141
  @@held_interval.each do |k, v|
142
142
  if v < Game.kb_held_interval; @@held_interval[k] += 1
143
143
  else; @@held_interval[k] = 0; end
144
144
  end
145
-
145
+
146
146
  @@prev_down = @@down.clone
147
147
  @@down.clear
148
148
  @@keys.each do |k|
@@ -155,10 +155,10 @@ module AGL
155
155
  end
156
156
  end
157
157
  end
158
-
158
+
159
159
  # Returns whether the given key is down in the current frame and was not
160
160
  # down in the frame before.
161
- #
161
+ #
162
162
  # Parameters:
163
163
  # [key] Code of the key to be checked. The available codes are <code>
164
164
  # Gosu::KbUp, Gosu::KbDown, Gosu::KbReturn, Gosu::KbEscape,
@@ -181,34 +181,34 @@ module AGL
181
181
  def self.key_pressed? key
182
182
  @@prev_down.index(key).nil? and @@down.index(key)
183
183
  end
184
-
184
+
185
185
  # Returns whether the given key is down in the current frame.
186
- #
186
+ #
187
187
  # Parameters:
188
188
  # [key] Code of the key to be checked. See +key_pressed?+ for details.
189
189
  def self.key_down? key
190
190
  @@down.index(key)
191
191
  end
192
-
192
+
193
193
  # Returns whether the given key is not down in the current frame but was
194
194
  # down in the frame before.
195
- #
195
+ #
196
196
  # Parameters:
197
197
  # [key] Code of the key to be checked. See +key_pressed?+ for details.
198
198
  def self.key_released? key
199
199
  @@prev_down.index(key) and @@down.index(key).nil?
200
200
  end
201
-
201
+
202
202
  # Returns whether the given key is being held down. See
203
203
  # <code>Game.initialize</code> for details.
204
- #
204
+ #
205
205
  # Parameters:
206
206
  # [key] Code of the key to be checked. See +key_pressed?+ for details.
207
207
  def self.key_held? key
208
208
  @@held_interval[key] == Game.kb_held_interval
209
209
  end
210
210
  end
211
-
211
+
212
212
  # Exposes methods for controlling mouse events.
213
213
  class Mouse
214
214
  # This is called by <code>Game.initialize</code>. Don't call it
@@ -219,18 +219,18 @@ module AGL
219
219
  @@dbl_click = {}
220
220
  @@dbl_click_timer = {}
221
221
  end
222
-
222
+
223
223
  # Updates the mouse position and the state of all buttons.
224
224
  def self.update
225
225
  @@prev_down = @@down.clone
226
226
  @@down.clear
227
227
  @@dbl_click.clear
228
-
228
+
229
229
  @@dbl_click_timer.each do |k, v|
230
230
  if v < Game.double_click_delay; @@dbl_click_timer[k] += 1
231
231
  else; @@dbl_click_timer.delete k; end
232
232
  end
233
-
233
+
234
234
  k1 = [Gosu::MsLeft, Gosu::MsMiddle, Gosu::MsRight]
235
235
  k2 = [:left, :middle, :right]
236
236
  for i in 0..2
@@ -242,57 +242,57 @@ module AGL
242
242
  @@dbl_click_timer[k2[i]] = 0
243
243
  end
244
244
  end
245
-
245
+
246
246
  @@x = Game.window.mouse_x.round
247
247
  @@y = Game.window.mouse_y.round
248
248
  end
249
-
249
+
250
250
  # Returns the x-coordinate of the mouse cursor in the screen.
251
251
  def self.x; @@x; end
252
-
252
+
253
253
  # Returns the y-coordinate of the mouse cursor in the screen.
254
254
  def self.y; @@y; end
255
-
255
+
256
256
  # Returns whether the given button is down in the current frame and was
257
257
  # not down in the frame before.
258
- #
258
+ #
259
259
  # Parameters:
260
260
  # [btn] Button to be checked. Valid values are +:left+, +:middle+ and
261
261
  # +:right+
262
262
  def self.button_pressed? btn
263
263
  @@down[btn] and not @@prev_down[btn]
264
264
  end
265
-
265
+
266
266
  # Returns whether the given button is down in the current frame.
267
- #
267
+ #
268
268
  # Parameters:
269
269
  # [btn] Button to be checked. Valid values are +:left+, +:middle+ and
270
270
  # +:right+
271
271
  def self.button_down? btn
272
272
  @@down[btn]
273
273
  end
274
-
274
+
275
275
  # Returns whether the given button is not down in the current frame, but
276
276
  # was down in the frame before.
277
- #
277
+ #
278
278
  # Parameters:
279
279
  # [btn] Button to be checked. Valid values are +:left+, +:middle+ and
280
280
  # +:right+
281
281
  def self.button_released? btn
282
282
  @@prev_down[btn] and not @@down[btn]
283
283
  end
284
-
284
+
285
285
  # Returns whether the given button has just been double clicked.
286
- #
286
+ #
287
287
  # Parameters:
288
288
  # [btn] Button to be checked. Valid values are +:left+, +:middle+ and
289
289
  # +:right+
290
290
  def self.double_click? btn
291
291
  @@dbl_click[btn]
292
292
  end
293
-
293
+
294
294
  # Returns whether the mouse cursor is currently inside the given area.
295
- #
295
+ #
296
296
  # Parameters:
297
297
  # [x] The x-coordinate of the top left corner of the area.
298
298
  # [y] The y-coordinate of the top left corner of the area.
@@ -302,7 +302,7 @@ module AGL
302
302
  @@x >= x and @@x < x + w and @@y >= y and @@y < y + h
303
303
  end
304
304
  end
305
-
305
+
306
306
  # This class is responsible for resource management. It keeps references to
307
307
  # all loaded resources until a call to +clear+ is made. Resources can be
308
308
  # loaded as global, so that their references won't be removed even when
@@ -328,10 +328,19 @@ module AGL
328
328
  @@global_songs = Hash.new
329
329
  @@fonts = Hash.new
330
330
  @@global_fonts = Hash.new
331
- end
332
-
331
+ @@prefix = File.expand_path(File.dirname($0)) + '/'
332
+ puts @@prefix
333
+ end
334
+
335
+ # Set a custom prefix for loading resources. By default, the prefix is the
336
+ # directory of the game script.
337
+ def self.prefix= value
338
+ value += '/' if value[-1] != '/'
339
+ @@prefix = value
340
+ end
341
+
333
342
  # Returns a <code>Gosu::Image</code> object.
334
- #
343
+ #
335
344
  # Parameters:
336
345
  # [id] A string or symbol representing the path to the image. If the file
337
346
  # is inside 'data/img', only the file name is needed. If it's inside
@@ -350,16 +359,16 @@ module AGL
350
359
  def self.img id, global = false, tileable = false, ext = ".png"
351
360
  if global; a = @@global_imgs; else; a = @@imgs; end
352
361
  return a[id] if a[id]
353
- s = "data/img/" + id.to_s.split('_').join('/') + ext
362
+ s = @@prefix + "data/img/" + id.to_s.split('_').join('/') + ext
354
363
  img = Gosu::Image.new Game.window, s, tileable
355
364
  a[id] = img
356
365
  end
357
-
366
+
358
367
  # Returns an array of <code>Gosu::Image</code> objects, using the image as
359
368
  # a spritesheet. The image with index 0 will be the top left sprite, and
360
369
  # the following indices raise first from left to right and then from top
361
370
  # to bottom.
362
- #
371
+ #
363
372
  # Parameters:
364
373
  # [id] A string or symbol representing the path to the image. See +img+
365
374
  # for details.
@@ -373,16 +382,16 @@ module AGL
373
382
  def self.imgs id, sprite_cols, sprite_rows, global = false, ext = ".png"
374
383
  if global; a = @@global_imgs; else; a = @@imgs; end
375
384
  return a[id] if a[id]
376
- s = "data/img/" + id.to_s.split('_').join('/') + ext
385
+ s = @@prefix + "data/img/" + id.to_s.split('_').join('/') + ext
377
386
  imgs = Gosu::Image.load_tiles Game.window, s, -sprite_cols, -sprite_rows, false
378
387
  a[id] = imgs
379
388
  end
380
-
389
+
381
390
  # Returns an array of <code>Gosu::Image</code> objects, using the image as
382
391
  # a tileset. Works the same as +imgs+, except you must provide the tile
383
392
  # size instead of the number of columns and rows, and that the images will
384
393
  # be loaded as tileable.
385
- #
394
+ #
386
395
  # Parameters:
387
396
  # [id] A string or symbol representing the path to the image. It must be
388
397
  # specified the same way as in +img+, but the base directory is
@@ -397,14 +406,14 @@ module AGL
397
406
  def self.tileset id, tile_width = 32, tile_height = 32, global = false, ext = ".png"
398
407
  if global; a = @@global_tilesets; else; a = @@tilesets; end
399
408
  return a[id] if a[id]
400
- s = "data/tileset/" + id.to_s.split('_').join('/') + ext
409
+ s = @@prefix + "data/tileset/" + id.to_s.split('_').join('/') + ext
401
410
  tileset = Gosu::Image.load_tiles Game.window, s, tile_width, tile_height, true
402
411
  a[id] = tileset
403
412
  end
404
-
413
+
405
414
  # Returns a <code>Gosu::Sample</code> object. This should be used for
406
415
  # simple and short sound effects.
407
- #
416
+ #
408
417
  # Parameters:
409
418
  # [id] A string or symbol representing the path to the sound. It must be
410
419
  # specified the same way as in +img+, but the base directory is
@@ -417,14 +426,14 @@ module AGL
417
426
  def self.sound id, global = false, ext = ".wav"
418
427
  if global; a = @@global_sounds; else; a = @@sounds; end
419
428
  return a[id] if a[id]
420
- s = "data/sound/" + id.to_s.split('_').join('/') + ext
429
+ s = @@prefix + "data/sound/" + id.to_s.split('_').join('/') + ext
421
430
  sound = Gosu::Sample.new Game.window, s
422
431
  a[id] = sound
423
432
  end
424
-
433
+
425
434
  # Returns a <code>Gosu::Song</code> object. This should be used for the
426
435
  # background musics of your game.
427
- #
436
+ #
428
437
  # Parameters:
429
438
  # [id] A string or symbol representing the path to the song. It must be
430
439
  # specified the same way as in +img+, but the base directory is
@@ -437,15 +446,15 @@ module AGL
437
446
  def self.song id, global = false, ext = ".ogg"
438
447
  if global; a = @@global_songs; else; a = @@songs; end
439
448
  return a[id] if a[id]
440
- s = "data/song/" + id.to_s.split('_').join('/') + ext
449
+ s = @@prefix + "data/song/" + id.to_s.split('_').join('/') + ext
441
450
  song = Gosu::Song.new Game.window, s
442
451
  a[id] = song
443
452
  end
444
-
453
+
445
454
  # Returns a <code>Gosu::Font</code> object. Fonts are needed to draw text
446
455
  # and used by MiniGL elements like buttons, text fields and TextHelper
447
456
  # objects.
448
- #
457
+ #
449
458
  # Parameters:
450
459
  # [id] A string or symbol representing the path to the song. It must be
451
460
  # specified the same way as in +img+, but the base directory is
@@ -461,11 +470,11 @@ module AGL
461
470
  if global; a = @@global_fonts; else; a = @@fonts; end
462
471
  id_size = "#{id}_#{size}"
463
472
  return a[id_size] if a[id_size]
464
- s = "data/font/" + id.to_s.split('_').join('/') + ext
473
+ s = @@prefix + "data/font/" + id.to_s.split('_').join('/') + ext
465
474
  font = Gosu::Font.new Game.window, s, size
466
475
  a[id_size] = font
467
476
  end
468
-
477
+
469
478
  # Releases the memory used by all non-global resources.
470
479
  def self.clear
471
480
  @@imgs.clear
data/lib/minigl/map.rb CHANGED
@@ -7,16 +7,16 @@ module AGL
7
7
  class Map
8
8
  # A Vector where x is the tile width and y is the tile height.
9
9
  attr_reader :tile_size
10
-
10
+
11
11
  # A Vector where x is the horizontal tile count and y the vertical count.
12
12
  attr_reader :size
13
-
13
+
14
14
  # A Rectangle representing the region of the map that is currently
15
15
  # visible.
16
16
  attr_reader :cam
17
-
17
+
18
18
  # Creates a new map.
19
- #
19
+ #
20
20
  # Parameters:
21
21
  # [t_w] The width of the tiles.
22
22
  # [t_h] The height of the tiles.
@@ -24,60 +24,85 @@ module AGL
24
24
  # [t_y_count] The vertical count of tiles in the map.
25
25
  # [scr_w] Width of the viewport for the map.
26
26
  # [scr_h] Height of the viewport for the map.
27
- def initialize t_w, t_h, t_x_count, t_y_count, scr_w = 800, scr_h = 600
27
+ # [isometric] Whether to use a isometric map. By default, an ortogonal map
28
+ # is used.
29
+ # [limit_cam] Whether the camera should respect the bounds of the map
30
+ # (i.e., when given coordinates that would imply regions
31
+ # outside the map to appear in the screen, the camera would
32
+ # move to the nearest position where only the map shows up
33
+ # in the screen).
34
+ def initialize t_w, t_h, t_x_count, t_y_count, scr_w = 800, scr_h = 600, isometric = false, limit_cam = true
28
35
  @tile_size = Vector.new t_w, t_h
29
36
  @size = Vector.new t_x_count, t_y_count
30
37
  @cam = Rectangle.new 0, 0, scr_w, scr_h
31
- @max_x = t_x_count * t_w - scr_w
32
- @max_y = t_y_count * t_h - scr_h
38
+ @limit_cam = limit_cam
39
+ @isometric = isometric
40
+ if isometric
41
+ initialize_isometric
42
+ elsif limit_cam
43
+ @max_x = t_x_count * t_w - scr_w
44
+ @max_y = t_y_count * t_h - scr_h
45
+ end
46
+ set_camera 0, 0
33
47
  end
34
-
48
+
35
49
  # Returns a Vector with the total size of the map, in pixels (x for the
36
50
  # width and y for the height).
37
51
  def get_absolute_size
38
- Vector.new(@tile_size.x * @size.x, @tile_size.y * @size.y)
52
+ return Vector.new(@tile_size.x * @size.x, @tile_size.y * @size.y) unless @isometric
53
+ avg = (@size.x + @size.y) * 0.5
54
+ Vector.new (avg * @tile_size.x).to_i, (avg * @tile_size.y).to_i
39
55
  end
40
-
56
+
41
57
  # Returns a Vector with the coordinates of the center of the map.
42
58
  def get_center
43
- Vector.new(@tile_size.x * @size.x / 2, @tile_size.y * @size.y / 2)
59
+ abs_size = get_absolute_size
60
+ Vector.new(abs_size.x * 0.5, abs_size.y * 0.5)
44
61
  end
45
-
62
+
46
63
  # Returns the position in the screen corresponding to the given tile
47
64
  # indices.
48
- #
65
+ #
49
66
  # Parameters:
50
67
  # [map_x] The index of the tile in the horizontal direction. It must be in
51
68
  # the interval <code>0..t_x_count</code>.
52
69
  # [map_y] The index of the tile in the vertical direction. It must be in
53
70
  # the interval <code>0..t_y_count</code>.
54
71
  def get_screen_pos map_x, map_y
55
- Vector.new(map_x * @tile_size.x - @cam.x, map_y * @tile_size.y - @cam.y)
72
+ return Vector.new(map_x * @tile_size.x - @cam.x, map_y * @tile_size.y - @cam.y) unless @isometric
73
+ Vector.new ((map_x - map_y - 1) * @tile_size.x * 0.5) - @cam.x + @x_offset,
74
+ ((map_x + map_y) * @tile_size.y * 0.5) - @cam.y
56
75
  end
57
-
76
+
58
77
  # Returns the tile in the map that corresponds to the given position in
59
78
  # the screen, as a Vector, where x is the horizontal index and y the
60
79
  # vertical index.
61
- #
80
+ #
62
81
  # Parameters:
63
82
  # [scr_x] The x-coordinate in the screen.
64
83
  # [scr_y] The y-coordinate in the screen.
65
84
  def get_map_pos scr_x, scr_y
66
- Vector.new((scr_x + @cam.x) / @tile_size.x, (scr_y + @cam.y) / @tile_size.y)
85
+ return Vector.new((scr_x + @cam.x) / @tile_size.x, (scr_y + @cam.y) / @tile_size.y) unless @isometric
86
+
87
+ # Obtém a posição transformada para as coordenadas isométricas
88
+ v = get_isometric_position scr_x, scr_y
89
+
90
+ # Depois divide pelo tamanho do quadrado para achar a posição da matriz
91
+ Vector.new((v.x * @inverse_square_size).to_i, (v.y * @inverse_square_size).to_i)
67
92
  end
68
-
93
+
69
94
  # Verifies whether a tile is inside the map.
70
- #
95
+ #
71
96
  # Parameters:
72
97
  # [v] A Vector representing the tile, with x as the horizontal index and
73
98
  # y as the vertical index.
74
99
  def is_in_map v
75
100
  v.x >= 0 && v.y >= 0 && v.x < @size.x && v.y < @size.y
76
101
  end
77
-
102
+
78
103
  # Sets the top left corner of the viewport to the given position of the
79
104
  # map. Note that this is not the position in the screen.
80
- #
105
+ #
81
106
  # Parameters:
82
107
  # [cam_x] The x-coordinate inside the map, in pixels (not a tile index).
83
108
  # [cam_y] The y-coordinate inside the map, in pixels (not a tile index).
@@ -86,9 +111,9 @@ module AGL
86
111
  @cam.y = cam_y
87
112
  set_bounds
88
113
  end
89
-
114
+
90
115
  # Moves the viewport by the given amount of pixels.
91
- #
116
+ #
92
117
  # Parameters:
93
118
  # [x] The amount of pixels to move horizontally. Negative values will
94
119
  # cause the camera to move to the left.
@@ -99,7 +124,7 @@ module AGL
99
124
  @cam.y += y
100
125
  set_bounds
101
126
  end
102
-
127
+
103
128
  # Iterates through the currently visible tiles, providing the horizontal
104
129
  # tile index, the vertical tile index, the x-coordinate (in pixels) and
105
130
  # the y-coordinate (in pixels), of each tile, in that order, to a given
@@ -113,37 +138,124 @@ module AGL
113
138
  def foreach
114
139
  for j in @min_vis_y..@max_vis_y
115
140
  for i in @min_vis_x..@max_vis_x
116
- yield i, j, i * @tile_size.x - @cam.x, j * @tile_size.y - @cam.y
141
+ pos = get_screen_pos i, j
142
+ yield i, j, pos.x, pos.y
117
143
  end
118
144
  end
119
145
  end
120
-
146
+
121
147
  private
122
-
148
+ Sqrt2Div2 = Math.sqrt(2) / 2
149
+ MinusPiDiv4 = -Math::PI / 4
150
+
123
151
  def set_bounds
124
- @cam.x = @cam.x.round
125
- @cam.y = @cam.y.round
126
- @cam.x = 0 if @cam.x < 0
127
- @cam.x = @max_x if @cam.x > @max_x
128
- @cam.y = 0 if @cam.y < 0
129
- @cam.y = @max_y if @cam.y > @max_y
130
-
131
- @min_vis_x = @cam.x / @tile_size.x
132
- @min_vis_y = @cam.y / @tile_size.y
133
- @max_vis_x = (@cam.x + @cam.w - 1) / @tile_size.x
134
- @max_vis_y = (@cam.y + @cam.h - 1) / @tile_size.y
135
-
152
+ if @isometric
153
+ v1 = get_isometric_position(0, 0)
154
+ v2 = get_isometric_position(@cam.w - 1, 0)
155
+ v3 = get_isometric_position(@cam.w - 1, @cam.h - 1)
156
+ v4 = get_isometric_position(0, @cam.h - 1)
157
+
158
+ if @limit_cam
159
+ if v1.x < -@max_offset
160
+ offset = -(v1.x + @max_offset)
161
+ @cam.x += offset * Sqrt2Div2
162
+ @cam.y += offset * Sqrt2Div2 / @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 * Sqrt2Div2
168
+ @cam.y += offset * Sqrt2Div2 / @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 * Sqrt2Div2
174
+ @cam.y -= offset * Sqrt2Div2 / @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 * Sqrt2Div2
180
+ @cam.y -= offset * Sqrt2Div2 / @tile_ratio
181
+ v4.y = @iso_abs_size.y + @max_offset
182
+ end
183
+ end
184
+
185
+ @min_vis_x = get_map_pos(0, 0).x
186
+ @min_vis_y = get_map_pos(@cam.w - 1, 0).y
187
+ @max_vis_x = get_map_pos(@cam.w - 1, @cam.h - 1).x
188
+ @max_vis_y = get_map_pos(0, @cam.h - 1).y
189
+ else
190
+ if @limit_cam
191
+ @cam.x = 0 if @cam.x < 0
192
+ @cam.x = @max_x if @cam.x > @max_x
193
+ @cam.y = 0 if @cam.y < 0
194
+ @cam.y = @max_y if @cam.y > @max_y
195
+ end
196
+ @min_vis_x = @cam.x / @tile_size.x
197
+ @min_vis_y = @cam.y / @tile_size.y
198
+ @max_vis_x = (@cam.x + @cam.w - 1) / @tile_size.x
199
+ @max_vis_y = (@cam.y + @cam.h - 1) / @tile_size.y
200
+ end
201
+ @cam.x = @cam.x.round
202
+ @cam.y = @cam.y.round
203
+
136
204
  if @min_vis_y < 0; @min_vis_y = 0
137
205
  elsif @min_vis_y > @size.y - 1; @min_vis_y = @size.y - 1; end
138
-
206
+
139
207
  if @max_vis_y < 0; @max_vis_y = 0
140
208
  elsif @max_vis_y > @size.y - 1; @max_vis_y = @size.y - 1; end
141
-
209
+
142
210
  if @min_vis_x < 0; @min_vis_x = 0
143
211
  elsif @min_vis_x > @size.x - 1; @min_vis_x = @size.x - 1; end
144
-
212
+
145
213
  if @max_vis_x < 0; @max_vis_x = 0
146
214
  elsif @max_vis_x > @size.x - 1; @max_vis_x = @size.x - 1; end
147
215
  end
216
+
217
+ def initialize_isometric
218
+ @x_offset = (@size.y * 0.5 * @tile_size.x).round
219
+ @tile_ratio = @tile_size.x.to_f / @tile_size.y
220
+ square_size = @tile_size.x * Sqrt2Div2
221
+ @inverse_square_size = 1 / square_size
222
+ @iso_abs_size = Vector.new(square_size * @size.x, square_size * @size.y)
223
+ a = (@size.x + @size.y) * 0.5 * @tile_size.x
224
+ @isometric_offset_x = (a - square_size * @size.x) * 0.5
225
+ @isometric_offset_y = (a - square_size * @size.y) * 0.5
226
+ if @limit_cam
227
+ actual_cam_h = @cam.h * @tile_ratio
228
+ @max_offset = actual_cam_h < @cam.w ? actual_cam_h : @cam.w
229
+ @max_offset *= Sqrt2Div2
230
+ end
231
+ end
232
+
233
+ def get_isometric_position scr_x, scr_y
234
+ # Escreve a posição em relação a origem (no centro do mapa)
235
+ center = get_center
236
+ position = Vector.new scr_x + @cam.x - center.x, scr_y + @cam.y - center.y
237
+
238
+ # Multiplica por tile_ratio para obter tiles quadrados
239
+ position.y *= @tile_ratio
240
+
241
+ # O centro do mapa também é deslocado
242
+ center.y *= @tile_ratio
243
+
244
+ # Rotaciona o vetor posição -45°
245
+ position = rotate position, MinusPiDiv4
246
+
247
+ # Retorna a referência da posição para o canto da tela
248
+ position.x += center.x; position.y += center.y
249
+
250
+ # O mapa quadrado está centralizado no centro do losango, precisa retornar ao canto da tela
251
+ position.x -= @isometric_offset_x; position.y -= @isometric_offset_y
252
+ position
253
+ end
254
+
255
+ def rotate v, angle
256
+ sin = Math.sin angle
257
+ cos = Math.cos angle
258
+ Vector.new cos * v.x - sin * v.y, sin * v.x + cos * v.y
259
+ end
148
260
  end
149
261
  end
@@ -6,8 +6,9 @@ class SpriteTest < Test::Unit::TestCase
6
6
  def setup
7
7
  @window = Gosu::Window.new 800, 600, false
8
8
  Game.initialize @window
9
+ Res.prefix = File.expand_path(File.dirname(__FILE__))
9
10
  end
10
-
11
+
11
12
  def test_sprite_position
12
13
  s = Sprite.new 10, 20, :image
13
14
  assert_equal 10, s.x
@@ -16,7 +17,7 @@ class SpriteTest < Test::Unit::TestCase
16
17
  assert_equal -100, s.x
17
18
  assert_equal 200, s.y
18
19
  end
19
-
20
+
20
21
  def test_sprite_animation
21
22
  s = Sprite.new 10, 20, :image, 3, 1
22
23
  indices = [0, 1, 2]
@@ -32,8 +33,9 @@ class GameObjectTest < Test::Unit::TestCase
32
33
  def setup
33
34
  @window = Gosu::Window.new 800, 600, false
34
35
  Game.initialize @window
36
+ Res.prefix = File.expand_path(File.dirname(__FILE__))
35
37
  end
36
-
38
+
37
39
  def test_game_object_attributes
38
40
  o = GameObject.new 10, 20, 3, 1, :image
39
41
  assert_equal 10, o.x
@@ -45,7 +47,7 @@ class GameObjectTest < Test::Unit::TestCase
45
47
  assert_equal 0, o.stored_forces.x
46
48
  assert_equal 0, o.stored_forces.y
47
49
  end
48
-
50
+
49
51
  def test_game_object_animation
50
52
  o = GameObject.new 10, 20, 3, 1, :image, nil, 3, 1
51
53
  indices = [0, 1, 2]
data/test/iso_game.rb ADDED
@@ -0,0 +1,40 @@
1
+ require_relative '../lib/minigl'
2
+ include AGL
3
+
4
+ class MyGame < Gosu::Window
5
+ def initialize
6
+ super 800, 600, false
7
+ Game.initialize self
8
+
9
+ @tile1 = Res.img :tile2
10
+ @tile2 = Res.img :tile2b
11
+ @map = Map.new 25, 17, 200, 200, 800, 600, true
12
+ @p = Vector.new -1, -1
13
+ end
14
+
15
+ def needs_cursor?
16
+ true
17
+ end
18
+
19
+ def update
20
+ KB.update
21
+ Mouse.update
22
+ p = @map.get_map_pos Mouse.x, Mouse.y
23
+ @p = p if @map.is_in_map p
24
+
25
+ @map.move_camera 0, -5 if KB.key_down? Gosu::KbUp
26
+ @map.move_camera 5, 0 if KB.key_down? Gosu::KbRight
27
+ @map.move_camera 0, 5 if KB.key_down? Gosu::KbDown
28
+ @map.move_camera -5, 0 if KB.key_down? Gosu::KbLeft
29
+ @map.set_camera 0, 0 if KB.key_down? Gosu::KbReturn
30
+ end
31
+
32
+ def draw
33
+ @map.foreach do |i, j, x, y|
34
+ if i == @p.x and j == @p.y; @tile2.draw x, y, 0
35
+ else; @tile1.draw x, y, 0; end
36
+ end
37
+ end
38
+ end
39
+
40
+ MyGame.new.show
data/test/res_tests.rb CHANGED
@@ -2,12 +2,13 @@ require 'test/unit'
2
2
  require_relative '../lib/minigl'
3
3
  include AGL
4
4
 
5
- class SpriteTest < Test::Unit::TestCase
5
+ class ResTest < Test::Unit::TestCase
6
6
  def setup
7
7
  @window = Gosu::Window.new 800, 600, false
8
8
  Game.initialize @window
9
+ Res.prefix = File.expand_path(File.dirname(__FILE__))
9
10
  end
10
-
11
+
11
12
  def test_tileset
12
13
  t1 = Res.tileset :tileset1
13
14
  assert_equal 9, t1.length
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minigl
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.3
4
+ version: 1.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor David Santos
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-10-07 00:00:00.000000000 Z
11
+ date: 2014-10-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gosu
@@ -39,13 +39,6 @@ files:
39
39
  - LICENSE
40
40
  - README.md
41
41
  - Rakefile
42
- - data/font/font1.ttf
43
- - data/img/btn.png
44
- - data/img/check.png
45
- - data/img/image.png
46
- - data/img/img1.png
47
- - data/img/text.png
48
- - data/tileset/tileset1.png
49
42
  - lib/minigl.rb
50
43
  - lib/minigl/forms.rb
51
44
  - lib/minigl/game_object.rb
@@ -55,6 +48,7 @@ files:
55
48
  - lib/minigl/text.rb
56
49
  - test/game.rb
57
50
  - test/game_object_tests.rb
51
+ - test/iso_game.rb
58
52
  - test/map_tests.rb
59
53
  - test/movement_tests.rb
60
54
  - test/res_tests.rb
@@ -86,5 +80,6 @@ test_files:
86
80
  - test/movement_tests.rb
87
81
  - test/map_tests.rb
88
82
  - test/game.rb
83
+ - test/iso_game.rb
89
84
  - test/res_tests.rb
90
85
  - test/game_object_tests.rb
data/data/font/font1.ttf DELETED
Binary file
data/data/img/btn.png DELETED
Binary file
data/data/img/check.png DELETED
Binary file
data/data/img/image.png DELETED
Binary file
data/data/img/img1.png DELETED
Binary file
data/data/img/text.png DELETED
Binary file
Binary file