minigl 1.3.3 → 1.3.4

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