minigl 2.3.7 → 2.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6623569ecf1fbd81357b4fe2e06b22024c2ce05829298750e1574e08a02b2706
4
- data.tar.gz: ded142065a95df7c458d873a6c2049f4229f3fd40863872fdf19033f07331635
3
+ metadata.gz: a0cbb7ddb129a7fea30f09ad6d5c89b3cef8b9b9b83d5f7f9eeacc76b09227ca
4
+ data.tar.gz: 7297a8c63e1df8cf85d6d61ccfa4fd80cdf8676dc06fe8467aca522ab10bbe38
5
5
  SHA512:
6
- metadata.gz: 6cbb8a59c7b77104a1a8bba97d2ab740520cc6987eda4761e438b8b36fcd30b85eaacaa6caab32884118f52dadf3b763718017114db25b09b6f416dd7e1d5588
7
- data.tar.gz: 6b3db4da549096602dc258f26101f665713422f510f5623cf7e53bdb1940226dd4a97740e44446a60554e6e1ea29abfb981355ac3caa2006e8111b32dc3aa9d2
6
+ metadata.gz: 0ceda66b6723094d415a11d23cd3c0c5b69a496fe655f7f7a72cb7298bd5606f38d8755d9868a7e878e6a27a56350c2dbe9e513e4d3c247c7ac504a9356bd9b5
7
+ data.tar.gz: 8d1dd2b962d597547d54f51e18b2332ec201bbbca19f4fc1d3a584b52bb979937366c9f11719b05ce07fba43aade40137df270530e60935f56cc99b9b36d052f
data/README.md CHANGED
@@ -17,10 +17,10 @@ to victordavidsantos@gmail.com.
17
17
  ## Made with MiniGL
18
18
 
19
19
  Below are two full games built with MiniGL, both available for free download and also open source.
20
- * [Super Bombinhas](https://victords.itch.io/super-bombinhas) ([source](https://github.com/victords/super-bombinhas))
21
- * [ConnecMan](https://victords.itch.io/connecman) ([source](https://github.com/victords/connecman))
20
+ * [Super Bombinhas](https://github.com/victords/super-bombinhas)
21
+ * [ConnecMan](https://github.com/victords/connecman)
22
22
 
23
- *Super Bombinhas* is also available on [Steam](https://store.steampowered.com/app/1553840).
23
+ If you create a project using MiniGL, feel free to open a PR to include it in this list.
24
24
 
25
25
  ## Installing
26
26
 
@@ -37,10 +37,9 @@ After installing the Gosu dependencies, you can just `gem install minigl`.
37
37
  * The [wiki](https://github.com/victords/minigl/wiki) is a work in progress with tutorials and examples.
38
38
  * Test package and examples aren't complete!
39
39
 
40
- ## Version 2.3.7
40
+ ## Version 2.4.0
41
41
 
42
- * Exposed the `Panel#controls`, `TextField#focused` and `DropDownList#open` properties.
43
- * Fixed a bug when clicking overlapping buttons: only the click action of the button with highest z-index (or last updated if z-indexes are the same) will be triggered. **WARNING**: the click callback will only be executed if `Mouse.update` is called after the click happened. If you call `Mouse.update` every frame (which is recommended), there's nothing to worry about.
42
+ * Added the `Localization` class! Check out [the documentation](http://www.rubydoc.info/gems/minigl/MiniGL/Localization) to learn more.
44
43
 
45
44
  ## Contributing
46
45
 
data/lib/minigl/forms.rb CHANGED
@@ -317,12 +317,12 @@ module MiniGL
317
317
  super x, y, font, text, text_color, disabled_text_color
318
318
  @over_text_color = over_text_color
319
319
  @down_text_color = down_text_color
320
- if center_x; @text_x = x + @w / 2 if @w
321
- else; @text_x = x + margin_x * @scale_x; end
322
- if center_y; @text_y = y + @h / 2 if @h
323
- else; @text_y = y + margin_y * @scale_y; end
324
320
  @center_x = center_x
325
321
  @center_y = center_y
322
+ @margin_x = margin_x
323
+ @margin_y = margin_y
324
+ set_position(x, y)
325
+
326
326
  @action = action
327
327
  @params = params
328
328
 
@@ -393,10 +393,10 @@ module MiniGL
393
393
  # [x] The new x-coordinate for the button.
394
394
  # [y] The new y-coordinate for the button.
395
395
  def set_position(x, y)
396
- if @center_x; @text_x = x + @w / 2
397
- else; @text_x += x - @x; end
398
- if @center_y; @text_y = y + @h / 2
399
- else; @text_y += y - @y; end
396
+ @text_x = @center_x ? x + @w / 2 : x
397
+ @text_y = @center_y ? y + @h / 2 : y
398
+ @text_x += @margin_x
399
+ @text_y += @margin_y
400
400
  @x = x; @y = y
401
401
  end
402
402
 
@@ -445,7 +445,7 @@ module MiniGL
445
445
  private
446
446
 
447
447
  def perform_action
448
- @action.call @params if @action
448
+ @action.call(@params) if @action
449
449
  end
450
450
  end
451
451
 
@@ -514,8 +514,6 @@ module MiniGL
514
514
  else; height * @scale_y; end
515
515
  _, x, y = FormUtils.check_anchor(anchor, @anchor_offset_x, @anchor_offset_y, @w, @h)
516
516
  set_position(x, y)
517
- @text_x = x + @w / 2 if center_x
518
- @text_y = y + @h / 2 if center_y
519
517
  @checked = checked
520
518
  end
521
519
 
@@ -304,6 +304,14 @@ module MiniGL
304
304
  # This is +true+ when the effect's lifetime has already passed.
305
305
  attr_reader :dead
306
306
 
307
+ # The lifetime of the effect, in updates, i.e., how many calls to +update+
308
+ # must happen before the effect is marked as +dead+, since its creation.
309
+ attr_reader :lifetime
310
+
311
+ # The number of times +update+ has been called for this effect, while it
312
+ # was still active (not +dead+).
313
+ attr_reader :elapsed_time
314
+
307
315
  # Creates a new Effect.
308
316
  #
309
317
  # Parameters:
@@ -352,7 +360,7 @@ module MiniGL
352
360
  end
353
361
 
354
362
  super x, y, img, sprite_cols, sprite_rows
355
- @timer = 0
363
+ @elapsed_time = 0
356
364
  if indices
357
365
  @indices = indices
358
366
  else
@@ -369,15 +377,21 @@ module MiniGL
369
377
 
370
378
  # Updates the effect, animating and counting its remaining lifetime.
371
379
  def update
372
- unless @dead
373
- animate @indices, @interval
374
- @timer += 1
375
- @dead = true if @timer == @lifetime
376
- end
380
+ return if @dead
381
+
382
+ animate(@indices, @interval)
383
+ @elapsed_time += 1
384
+ @dead = true if @elapsed_time == @lifetime
377
385
  end
378
386
 
379
387
  def draw(map = nil, scale_x = 1, scale_y = 1, alpha = 0xff, color = 0xffffff, angle = nil, z_index = 0)
380
388
  super unless @dead
381
389
  end
390
+
391
+ # The remaining number of calls to +update+ until the effect is marked
392
+ # +dead+.
393
+ def time_left
394
+ @lifetime - @elapsed_time
395
+ end
382
396
  end
383
397
  end
data/lib/minigl/global.rb CHANGED
@@ -245,6 +245,16 @@ module MiniGL
245
245
  def toggle_fullscreen
246
246
  self.fullscreen = !fullscreen?
247
247
  end
248
+
249
+ def button_down(id)
250
+ super
251
+ Mouse.register_button_down(id)
252
+ end
253
+
254
+ def button_up(id)
255
+ super
256
+ Mouse.register_button_up(id)
257
+ end
248
258
  end
249
259
 
250
260
  # Exposes methods for controlling keyboard and gamepad events.
@@ -387,6 +397,7 @@ module MiniGL
387
397
  def initialize
388
398
  @down = {}
389
399
  @prev_down = {}
400
+ @next_down = {}
390
401
  @dbl_click = {}
391
402
  @dbl_click_timer = {}
392
403
  end
@@ -394,7 +405,8 @@ module MiniGL
394
405
  # Updates the mouse position and the state of all buttons.
395
406
  def update
396
407
  @prev_down = @down.clone
397
- @down.clear
408
+ @down = @next_down.clone
409
+ @next_down.delete_if { |_, v| v.zero? }
398
410
  @dbl_click.clear
399
411
 
400
412
  if @click
@@ -403,19 +415,19 @@ module MiniGL
403
415
  end
404
416
 
405
417
  @dbl_click_timer.each do |k, v|
406
- if v < G.double_click_delay; @dbl_click_timer[k] += 1
407
- else; @dbl_click_timer.delete k; end
418
+ if v < G.double_click_delay
419
+ @dbl_click_timer[k] += 1
420
+ else
421
+ @dbl_click_timer.delete(k)
422
+ end
408
423
  end
409
424
 
410
- k1 = [Gosu::MsLeft, Gosu::MsMiddle, Gosu::MsRight]
411
- k2 = [:left, :middle, :right]
412
- (0..2).each do |i|
413
- if G.window.button_down? k1[i]
414
- @down[k2[i]] = true
415
- @dbl_click[k2[i]] = true if @dbl_click_timer[k2[i]]
416
- @dbl_click_timer.delete k2[i]
417
- elsif @prev_down[k2[i]]
418
- @dbl_click_timer[k2[i]] = 0
425
+ %i[left middle right].each do |key|
426
+ if @down[key]
427
+ @dbl_click[key] = true if @dbl_click_timer[key]
428
+ @dbl_click_timer.delete(key)
429
+ elsif @prev_down[key]
430
+ @dbl_click_timer[key] = 0
419
431
  end
420
432
  end
421
433
 
@@ -486,6 +498,31 @@ module MiniGL
486
498
 
487
499
  @click = { z_index: z_index, action: action }
488
500
  end
501
+
502
+ # :nodoc:
503
+ def register_button_down(id)
504
+ key = key_from_id(id)
505
+ @next_down[key] = 1 if key
506
+ end
507
+
508
+ # :nodoc:
509
+ def register_button_up(id)
510
+ key = key_from_id(id)
511
+ @next_down[key] = 0 if key && @next_down[key]
512
+ end
513
+
514
+ private
515
+
516
+ def key_from_id(id)
517
+ case id
518
+ when Gosu::MS_LEFT
519
+ :left
520
+ when Gosu::MS_RIGHT
521
+ :right
522
+ when Gosu::MS_MIDDLE
523
+ :middle
524
+ end
525
+ end
489
526
  end
490
527
  end
491
528
 
@@ -0,0 +1,79 @@
1
+ module MiniGL
2
+ # This class provides methods to easily retrieve string translations from
3
+ # text files.
4
+ class Localization
5
+ class << self
6
+ # The list of available languages. These are symbols corresponding to the
7
+ # names of the files in data/text, without the '.txt' extension.
8
+ attr_reader :languages
9
+
10
+ # The current language. It's a symbol corresponding to the name of the
11
+ # file in data/text for that language, without the '.txt' extension.
12
+ attr_reader :language
13
+
14
+ # Initializes the localization system. If you're using a custom
15
+ # +Res.prefix+, call this _after_ setting it.
16
+ #
17
+ # The localization system will look for files with extension '.txt' in
18
+ # the <code>[Res.prefix]/data/text</code> folder. In each file,
19
+ # each string should be specified in one line, with the following format:
20
+ #
21
+ # <code>identifier content content content...</code>
22
+ #
23
+ # Use tab characters between the identifier and the text, not white
24
+ # spaces. This makes it easier to make all the texts aligned and is
25
+ # required for the localization system to work. The identifiers will be
26
+ # used as symbols when retrieving strings.
27
+ #
28
+ # The text contents support placeholders, i.e., markers that can be
29
+ # replaced by arguments you pass to +Localization.text+. To specify a
30
+ # placeholder, simply use the '$' character. For example, if your string
31
+ # is:
32
+ #
33
+ # <code>my_string Values: $ and $</code>
34
+ #
35
+ # the call <code>Localization.text(:my_string, 'test', 10)</code> will
36
+ # result in "Values: test and 10."
37
+ #
38
+ # To include a literal '$'
39
+ # in the text, use '\\$' (without the quotes). Similarly, use '\\\\' to
40
+ # represent a literal backslash, and just '\\' to represent a line break
41
+ # (i.e. a "\\n" in the resulting string).
42
+ def initialize
43
+ @languages = []
44
+ @texts = {}
45
+ files = Dir["#{Res.prefix}text/*.txt"].sort
46
+ files.each do |f|
47
+ lang = f.split('/')[-1].chomp('.txt').to_sym
48
+ @languages << lang
49
+ @texts[lang] = {}
50
+ File.open(f).each do |l|
51
+ parts = l.split("\t")
52
+ @texts[lang][parts[0].to_sym] = parts[-1].chomp
53
+ end
54
+ end
55
+
56
+ @language = @languages[0]
57
+ end
58
+
59
+ # Sets the current language. +value+ must be a symbol corresponding to
60
+ # the name of a file in data/text, without the '.txt' extension.
61
+ def language=(value)
62
+ raise "Can't set to invalid language #{value}" unless @languages.include?(value)
63
+
64
+ @language = value
65
+ end
66
+
67
+ # Retrieves the string identified by +id+ in the current language.
68
+ #
69
+ # See +Localization.initialize+ for details on how to use +args+.
70
+ def text(id, *args)
71
+ value = @texts[@language][id] || '<MISSING STRING>'
72
+ args.each do |arg|
73
+ value = value.sub(/(^|[^\\])\$/, "\\1#{arg}")
74
+ end
75
+ value.gsub('\\$', '$').gsub(/\\(.|$)/) { |m| m[1] == '\\' ? '\\' : "\n#{m[1]}" }
76
+ end
77
+ end
78
+ end
79
+ end
data/lib/minigl/text.rb CHANGED
@@ -11,9 +11,18 @@ module MiniGL
11
11
  # if a character fits in the current line it must not be placed in the next
12
12
  # one. In the last line there can be any amount of free space at the end.
13
13
  class ImageFont
14
+ # A string containing the characters supported by this font.
15
+ attr_reader :chars
16
+
14
17
  # The height of this font in pixels.
15
18
  attr_reader :height
16
19
 
20
+ # The width of the white space character in this font, in pixels.
21
+ attr_reader :space_width
22
+
23
+ # The spacing between characters, in pixels (can be a decimal number).
24
+ attr_reader :char_spacing
25
+
17
26
  # Creates an +ImageFont+.
18
27
  #
19
28
  # Parameters:
@@ -26,16 +35,19 @@ module MiniGL
26
35
  # as they appear in the +chars+ string.
27
36
  # [height] The height of the lines in the image (see description above).
28
37
  # [space_width] The width of the white space character in this font.
38
+ # [char_spacing] The spacing between non-white-space characters when writing text with
39
+ # this font. It can be a decimal number, useful when scaling the text up.
29
40
  # [global] Parameter that will be passed to +Res.img+ when loading the image.
30
41
  # [ext] Parameter that will be passed to +Res.img+ when loading the image.
31
42
  # [retro] Parameter that will be passed to +Res.img+ when loading the image.
32
- def initialize(img_path, chars, widths, height, space_width, global = true, ext = '.png', retro = nil)
43
+ def initialize(img_path, chars, widths, height, space_width, char_spacing = 0, global = true, ext = '.png', retro = nil)
33
44
  retro = Res.retro_images if retro.nil?
34
45
  img = Res.img(img_path, global, false, ext, retro)
35
46
  @chars = chars
36
47
  @images = []
37
48
  @height = height
38
49
  @space_width = space_width
50
+ @char_spacing = char_spacing
39
51
  wa = widths.is_a?(Array)
40
52
  if wa && widths.length != chars.length
41
53
  raise 'Wrong widths array size!'
@@ -60,7 +72,17 @@ module MiniGL
60
72
  # Parameters:
61
73
  # [text] The string to be measured
62
74
  def markup_width(text)
63
- text.chars.reduce(0) { |w, c| if c == ' '; w += @space_width; else; i = @chars.index(c); w += i ? @images[i].width : 0; end }
75
+ w = 0
76
+ text.chars.each_with_index do |c, i|
77
+ if c == ' '
78
+ w += @space_width
79
+ else
80
+ idx = @chars.index(c)
81
+ w += idx ? @images[idx].width : 0
82
+ w += @char_spacing if i < text.chars.size - 1
83
+ end
84
+ end
85
+ w
64
86
  end
65
87
 
66
88
  # See <code>Gosu::Font#draw_markup_rel</code> for details.
@@ -82,7 +104,7 @@ module MiniGL
82
104
  i = @chars.index(c)
83
105
  next if i.nil?
84
106
  @images[i].draw(x, y, z, scale_x, scale_y, color)
85
- x += scale_x * @images[i].width
107
+ x += (scale_x * (@images[i].width + @char_spacing)).round
86
108
  end
87
109
  end
88
110
 
data/lib/minigl.rb CHANGED
@@ -2,3 +2,4 @@ require_relative 'minigl/game_object'
2
2
  require_relative 'minigl/map'
3
3
  require_relative 'minigl/text'
4
4
  require_relative 'minigl/forms'
5
+ require_relative 'minigl/localization'
@@ -0,0 +1,6 @@
1
+ str1 Common string.
2
+ str2 String with \$ dollar sign.
3
+ str3 $ should be replaced.
4
+ str4 Should replace both $ and $.
5
+ str5 String with \\ backslash.
6
+ str6 String with\line breaks.\
@@ -0,0 +1,6 @@
1
+ str1 String comum.
2
+ str2 String com \$ cifrão.
3
+ str3 $ deve ser substituído.
4
+ str4 Deve substituir $ e $.
5
+ str5 String com \\ barra invertida.
6
+ str6 String com\quebras de linha.\
data/test/game.rb CHANGED
@@ -19,7 +19,7 @@ class MyGame < GameWindow
19
19
  @font2 = Res.font :font1, 50
20
20
  @writer1 = TextHelper.new @font1, 5
21
21
  @writer2 = TextHelper.new @font2, 5
22
- @btn = Button.new(10, 560, @font1, 'Test', :btn, 0x008000, 0x808080, 0xffffff, 0xff9980, true, true, 0, 4, 0, 0, 'friends', nil, 2, 2) { |x| puts "hello #{x}" }
22
+ @btn = Button.new(10, 560, @font1, 'Test', :btn, 0x008000, 0x808080, 0xffffff, 0xff9980, true, false, -10, 4, 0, 0, 'friends', nil, 2, 2) { |x| puts "hello #{x}" }
23
23
  @btn.enabled = false
24
24
  @chk =
25
25
  ToggleButton.new(x: 0, y: 30, font: @font1, text: 'Click me', img: :check, center_x: false, margin_x: 36, params: 'friends', anchor: :south) { |c, x|
@@ -0,0 +1,41 @@
1
+ require 'test/unit'
2
+ require_relative '../lib/minigl'
3
+ include MiniGL
4
+
5
+ class LocalizationTest < Test::Unit::TestCase
6
+ def setup
7
+ Res.prefix = File.expand_path(File.dirname(__FILE__)) + '/data'
8
+ Localization.initialize
9
+ end
10
+
11
+ def test_languages
12
+ assert_equal([:english, :portuguese], Localization.languages)
13
+ end
14
+
15
+ def test_language
16
+ assert_equal(:english, Localization.language)
17
+ Localization.language = :portuguese
18
+ assert_equal(:portuguese, Localization.language)
19
+ assert_raise { Localization.language = :invalid }
20
+ assert_equal(:portuguese, Localization.language)
21
+ end
22
+
23
+ def test_strings
24
+ assert_equal('Common string.', Localization.text(:str1))
25
+ assert_equal('String with $ dollar sign.', Localization.text(:str2))
26
+ assert_equal('something should be replaced.', Localization.text(:str3, 'something'))
27
+ assert_equal('Should replace both 5 and true.', Localization.text(:str4, 5, true))
28
+ assert_equal('String with \\ backslash.', Localization.text(:str5))
29
+ assert_equal("String with\nline breaks.\n", Localization.text(:str6))
30
+ assert_equal('<MISSING STRING>', Localization.text(:str7))
31
+
32
+ Localization.language = :portuguese
33
+ assert_equal('String comum.', Localization.text(:str1))
34
+ assert_equal('String com $ cifrão.', Localization.text(:str2))
35
+ assert_equal('algo deve ser substituído.', Localization.text(:str3, 'algo'))
36
+ assert_equal('Deve substituir 5 e true.', Localization.text(:str4, 5, true))
37
+ assert_equal('String com \\ barra invertida.', Localization.text(:str5))
38
+ assert_equal("String com\nquebras de linha.\n", Localization.text(:str6))
39
+ assert_equal('<MISSING STRING>', Localization.text(:str7))
40
+ end
41
+ end
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: 2.3.7
4
+ version: 2.4.0
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: 2021-12-28 00:00:00.000000000 Z
11
+ date: 2022-03-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: gosu
@@ -43,6 +43,7 @@ files:
43
43
  - lib/minigl/forms.rb
44
44
  - lib/minigl/game_object.rb
45
45
  - lib/minigl/global.rb
46
+ - lib/minigl/localization.rb
46
47
  - lib/minigl/map.rb
47
48
  - lib/minigl/movement.rb
48
49
  - lib/minigl/text.rb
@@ -70,10 +71,13 @@ files:
70
71
  - test/data/img/tile2.svg
71
72
  - test/data/img/tile2b.png
72
73
  - test/data/sound/1.wav
74
+ - test/data/text/english.txt
75
+ - test/data/text/portuguese.txt
73
76
  - test/data/tileset/tileset1.png
74
77
  - test/game.rb
75
78
  - test/game_object_tests.rb
76
79
  - test/iso_game.rb
80
+ - test/localization_tests.rb
77
81
  - test/map_tests.rb
78
82
  - test/mov_game.rb
79
83
  - test/movement_tests.rb
@@ -107,6 +111,7 @@ test_files:
107
111
  - test/game.rb
108
112
  - test/game_object_tests.rb
109
113
  - test/iso_game.rb
114
+ - test/localization_tests.rb
110
115
  - test/map_tests.rb
111
116
  - test/mov_game.rb
112
117
  - test/movement_tests.rb
@@ -136,5 +141,7 @@ test_files:
136
141
  - test/data/img/tile2.svg
137
142
  - test/data/img/tile2b.png
138
143
  - test/data/sound/1.wav
144
+ - test/data/text/english.txt
145
+ - test/data/text/portuguese.txt
139
146
  - test/data/tileset/tileset1.png
140
147
  - test/data/img/sub/image.png