minigl 2.3.7 → 2.4.0

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
  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