ruby2d 0.3.1 → 0.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.
@@ -3,47 +3,43 @@
3
3
  module Ruby2D::Application
4
4
  class << self
5
5
  @@window = Ruby2D::Window.new
6
-
6
+
7
7
  def get(sym)
8
8
  @@window.get(sym)
9
9
  end
10
-
10
+
11
11
  def set(opts)
12
12
  @@window.set(opts)
13
13
  end
14
-
15
- def on(args = {}, &proc)
16
- @@window.on(args, &proc)
17
- end
18
-
19
- def on_key(&proc)
20
- @@window.on_key(&proc)
14
+
15
+ def on(event, &proc)
16
+ @@window.on(event, &proc)
21
17
  end
22
-
23
- def on_controller(&proc)
24
- @@window.on_controller(&proc)
18
+
19
+ def off(event_descriptor)
20
+ @@window.off(event_descriptor)
25
21
  end
26
-
22
+
27
23
  def add(o)
28
24
  @@window.add(o)
29
25
  end
30
-
26
+
31
27
  def remove(o)
32
28
  @@window.remove(o)
33
29
  end
34
-
30
+
35
31
  def clear
36
32
  @@window.clear
37
33
  end
38
-
34
+
39
35
  def update(&proc)
40
36
  @@window.update(&proc)
41
37
  end
42
-
38
+
43
39
  def show
44
40
  @@window.show
45
41
  end
46
-
42
+
47
43
  def close
48
44
  @@window.close
49
45
  end
data/lib/ruby2d/color.rb CHANGED
@@ -2,9 +2,31 @@
2
2
 
3
3
  module Ruby2D
4
4
  class Color
5
-
5
+ # Color::Set represents an array of colors
6
+ class Set
7
+ def initialize(colors)
8
+ @colors = colors.map{|c| Color.new(c)}
9
+ end
10
+
11
+ def [](i)
12
+ @colors[i]
13
+ end
14
+
15
+ def length
16
+ @colors.length
17
+ end
18
+
19
+ def opacity; @colors[0].opacity end
20
+
21
+ def opacity=(opacity)
22
+ @colors.each do |color|
23
+ color.opacity = opacity
24
+ end
25
+ end
26
+ end
27
+
6
28
  attr_reader :r, :g, :b, :a
7
-
29
+
8
30
  # Based on clrs.cc
9
31
  @@colors = {
10
32
  'navy' => '#001F3F',
@@ -27,7 +49,7 @@ module Ruby2D
27
49
  'black' => '#111111',
28
50
  'random' => ''
29
51
  }
30
-
52
+
31
53
  def initialize(c)
32
54
  if !self.class.is_valid? c
33
55
  raise Error, "`#{c}` is not a valid color"
@@ -46,28 +68,44 @@ module Ruby2D
46
68
  end
47
69
  end
48
70
  end
49
-
71
+
50
72
  # Check if string is a proper hex value
51
73
  def self.is_hex?(s)
52
74
  # MRuby doesn't support regex, otherwise we'd do:
53
75
  # !(/^#[0-9A-F]{6}$/i.match(a).nil?)
54
76
  s.class == String && s[0] == '#' && s.length == 7
55
77
  end
56
-
78
+
57
79
  # Check if the color is valid
58
80
  def self.is_valid?(c)
59
81
  @@colors.key?(c) || # keyword
60
82
  self.is_hex?(c) || # hexadecimal value
61
-
83
+
62
84
  # Array of Floats from 0.0..1.0
63
85
  c.class == Array && c.length == 4 &&
64
86
  c.all? { |el|
65
87
  el.is_a?(Numeric) && (0.0..1.0).include?(el)
66
88
  }
67
89
  end
68
-
90
+
91
+ def self.from(input)
92
+ # If a valid array of colors, return a Color::Set with those colors
93
+ # Else return single color
94
+ if input.is_a? Array and input.all? { |el| Color.is_valid? el }
95
+ Color::Set.new(input)
96
+ else
97
+ Color.new(input)
98
+ end
99
+ end
100
+
101
+ def opacity; @a end
102
+
103
+ def opacity=(opacity)
104
+ @a = opacity
105
+ end
106
+
69
107
  private
70
-
108
+
71
109
  # TODO: Only `Number` supported in JS
72
110
  # Convert from Fixnum (0..255) to Float (0.0..1.0)
73
111
  def to_f(a)
@@ -77,19 +115,19 @@ module Ruby2D
77
115
  end
78
116
  return b
79
117
  end
80
-
118
+
81
119
  # Convert from hex value (e.g. #FFF000) to Float (0.0..1.0)
82
120
  def hex_to_f(h)
83
121
  h = (h[1..-1]).chars.each_slice(2).map(&:join)
84
122
  a = []
85
-
123
+
86
124
  h.each do |el|
87
125
  a.push(el.to_i(16))
88
126
  end
89
-
127
+
90
128
  a.push(255)
91
129
  return to_f(a)
92
130
  end
93
-
131
+
94
132
  end
95
133
  end
data/lib/ruby2d/dsl.rb CHANGED
@@ -4,37 +4,33 @@ module Ruby2D::DSL
4
4
  def get(sym)
5
5
  Application.get(sym)
6
6
  end
7
-
7
+
8
8
  def set(opts)
9
9
  Application.set(opts)
10
10
  end
11
-
12
- def on(args = {}, &proc)
13
- Application.on(args, &proc)
14
- end
15
-
16
- def on_key(&proc)
17
- Application.on_key(&proc)
11
+
12
+ def on(event, &proc)
13
+ Application.on(event, &proc)
18
14
  end
19
-
20
- def on_controller(&proc)
21
- Application.on_controller(&proc)
15
+
16
+ def off(event_descriptor)
17
+ Application.off(event_descriptor)
22
18
  end
23
-
19
+
24
20
  def update(&proc)
25
21
  Application.update(&proc)
26
22
  end
27
-
23
+
28
24
  def clear
29
25
  Application.clear
30
26
  end
31
-
27
+
32
28
  def show
33
29
  Application.show
34
30
  end
35
-
31
+
36
32
  def close
37
33
  Application.close
38
34
  end
39
-
35
+
40
36
  end
@@ -2,14 +2,5 @@
2
2
 
3
3
  module Ruby2D
4
4
  class Error < StandardError
5
- def colorize(msg, c); "\e[#{c}m#{msg}\e[0m" end
6
- def error(msg); colorize(msg, '4;31') end
7
- def bold(msg); colorize(msg, '1') end
8
-
9
- def initialize(msg)
10
- super(msg)
11
- puts error("\nRuby 2D Error:") << " #{msg}" <<
12
- bold("\nOccurred in:\n #{caller.last}\n")
13
- end
14
5
  end
15
6
  end
data/lib/ruby2d/image.rb CHANGED
@@ -2,41 +2,38 @@
2
2
 
3
3
  module Ruby2D
4
4
  class Image
5
-
5
+ include Renderable
6
+
6
7
  attr_accessor :x, :y, :width, :height, :data
7
8
  attr_reader :path, :color
8
-
9
- def initialize(x, y, path)
10
-
11
- # TODO: Check if file exists
12
- # `File.exists?` is not available in MRuby
13
- # Ideally would do:
14
- # unless File.exists? path
15
- # raise Error, "Cannot find image file `#{path}`"
16
- # end
17
-
18
- @type_id = 3
19
- @x, @y, @path = x, y, path
20
- @color = Color.new([1, 1, 1, 1])
21
- init(path)
9
+
10
+ def initialize(opts = {})
11
+ @path = opts[:path]
12
+
13
+ unless RUBY_ENGINE == 'opal'
14
+ unless File.exists? @path
15
+ raise Error, "Cannot find image file `#{@path}`"
16
+ end
17
+ end
18
+
19
+ @x = opts[:x] || 0
20
+ @y = opts[:y] || 0
21
+ @z = opts[:x] || 0
22
+
23
+ @type_id = 4
24
+
25
+ self.color = opts[:color] || 'white'
26
+
27
+ ext_image_init(@path)
22
28
  add
23
29
  end
24
-
30
+
25
31
  def color=(c)
26
32
  @color = Color.new(c)
27
33
  end
28
-
29
- def add
30
- if Module.const_defined? :DSL
31
- Application.add(self)
32
- end
33
- end
34
-
35
- def remove
36
- if Module.const_defined? :DSL
37
- Application.remove(self)
38
- end
34
+
35
+ def contains?(x, y)
36
+ @x < x and @x + @width > x and @y < y and @y + @height > y
39
37
  end
40
-
41
38
  end
42
39
  end
@@ -0,0 +1,64 @@
1
+ # line.rb
2
+
3
+ module Ruby2D
4
+ class Line
5
+ include Renderable
6
+ attr_accessor :x1, :x2, :y1, :y2, :color, :width
7
+
8
+ def initialize(opts = {})
9
+ @type_id = 3
10
+
11
+ @x1 = opts[:x1] || 0
12
+ @y1 = opts[:y1] || 0
13
+ @x2 = opts[:x2] || 100
14
+ @y2 = opts[:y2] || 100
15
+ @width = opts[:width] || 2
16
+ @z = opts[:z] || 0
17
+ self.color = opts[:color] || 'white'
18
+
19
+ add
20
+ end
21
+
22
+ def color=(c)
23
+ @color = Color.from(c)
24
+ update_color(@color)
25
+ end
26
+
27
+ def length
28
+ points_distance(@x1, @y1, @x2, @y2)
29
+ end
30
+
31
+ # Line contains a point if the point is closer than the length of line from both ends
32
+ # and if the distance from point to line is smaller than half of the width.
33
+ # Check https://en.wikipedia.org/wiki/Distance_from_a_point_to_a_line for reference
34
+ def contains?(x, y)
35
+ points_distance(x1, y1, x, y) < length and
36
+ points_distance(x2, y2, x, y) < length and
37
+ (((@y2 - @y1) * x - (@x2 - @x1) * y + @x2 * @y1 - @y2 * @x1).abs / length) < 0.5 * @width
38
+ end
39
+
40
+ private
41
+
42
+ def points_distance(x1, y1, x2, y2)
43
+ Math.sqrt((x1 - x2) ** 2 + (y1 - y2) ** 2)
44
+ end
45
+
46
+ def update_color(c)
47
+ if c.is_a? Color::Set
48
+ if c.length == 4
49
+ @c1 = c[0]
50
+ @c2 = c[1]
51
+ @c3 = c[2]
52
+ @c4 = c[3]
53
+ else
54
+ raise ArgumentError, "Lines require 4 colors, one for each vertex. #{c.length} were given."
55
+ end
56
+ else
57
+ @c1 = c
58
+ @c2 = c
59
+ @c3 = c
60
+ @c4 = c
61
+ end
62
+ end
63
+ end
64
+ end
data/lib/ruby2d/music.rb CHANGED
@@ -2,16 +2,41 @@
2
2
 
3
3
  module Ruby2D
4
4
  class Music
5
-
5
+
6
6
  attr_accessor :data, :loop
7
7
  attr_reader :path
8
-
8
+
9
9
  def initialize(path)
10
- # TODO: Check if file exists
11
- init(path)
10
+
11
+ unless RUBY_ENGINE == 'opal'
12
+ unless File.exists? path
13
+ raise Error, "Cannot find audio file `#{path}`"
14
+ end
15
+ end
16
+
12
17
  @path = path
13
18
  @loop = false
19
+ ext_music_init(path)
20
+ end
21
+
22
+ def play
23
+ ext_music_play
24
+ end
25
+
26
+ def pause
27
+ ext_music_pause
28
+ end
29
+
30
+ def resume
31
+ ext_music_resume
32
+ end
33
+
34
+ def stop
35
+ ext_music_stop
36
+ end
37
+
38
+ def fadeout(ms)
39
+ ext_music_fadeout(ms)
14
40
  end
15
-
16
41
  end
17
42
  end
data/lib/ruby2d/quad.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  module Ruby2D
4
4
  class Quad
5
+ include Renderable
5
6
  # Coordinates in clockwise order, starting at top left:
6
7
  # x1,y1 == top left
7
8
  # x2,y2 == top right
@@ -11,61 +12,68 @@ module Ruby2D
11
12
  :x2, :y2, :c2,
12
13
  :x3, :y3, :c3,
13
14
  :x4, :y4, :c4
14
-
15
+
15
16
  attr_reader :color
16
-
17
- def initialize(x1=0, y1=0, x2=100, y2=0, x3=100, y3=100, x4=100, y4=100, c='white')
17
+
18
+ def initialize(opts = {})
18
19
  @type_id = 2
19
- @x1, @y1, @x2, @y2, @x3, @y3, @x4, @y4 = x1, y1, x2, y2, x3, y3, x4, y4
20
- @color = c
21
- update_color(c)
20
+
21
+ @x1 = opts[:x1] || 0
22
+ @y1 = opts[:y1] || 0
23
+ @x2 = opts[:x2] || 100
24
+ @y2 = opts[:y2] || 0
25
+ @x3 = opts[:x3] || 100
26
+ @y3 = opts[:y3] || 100
27
+ @x4 = opts[:x4] || 0
28
+ @y4 = opts[:y4] || 100
29
+
30
+ @z = opts[:z] || 0
31
+
32
+ self.color = opts[:color] || 'white'
22
33
  add
23
34
  end
24
-
35
+
25
36
  def color=(c)
26
- @color = c
27
- update_color(c)
28
- end
29
-
30
- def add
31
- if Module.const_defined? :DSL
32
- Application.add(self)
33
- end
37
+ @color = Color.from(c)
38
+ update_color(@color)
34
39
  end
35
-
36
- def remove
37
- if Module.const_defined? :DSL
38
- Application.remove(self)
39
- end
40
+
41
+ # The logic is the same as for a triangle
42
+ # See triangle.rb for reference
43
+ def contains?(x, y)
44
+ self_area = triangle_area(@x1, @y1, @x2, @y2, @x3, @y3) +
45
+ triangle_area(@x1, @y1, @x3, @y3, @x4, @y4)
46
+
47
+ questioned_area = triangle_area(@x1, @y1, @x2, @y2, x, y) +
48
+ triangle_area(@x2, @y2, @x3, @y3, x, y) +
49
+ triangle_area(@x3, @y3, @x4, @y4, x, y) +
50
+ triangle_area(@x4, @y4, @x1, @y1, x, y)
51
+
52
+ questioned_area <= self_area
40
53
  end
41
-
54
+
42
55
  private
43
-
56
+
57
+ def triangle_area(x1, y1, x2, y2, x3, y3)
58
+ (x1*y2 + x2*y3 + x3*y1 - x3*y2 - x1*y3 - x2*y1).abs / 2
59
+ end
60
+
44
61
  def update_color(c)
45
-
46
- # If a valid color, use it for each vertex
47
- if Color.is_valid? c
48
- @c1 = Color.new(c)
49
- @c2 = Color.new(c)
50
- @c3 = Color.new(c)
51
- @c4 = Color.new(c)
52
-
53
- elsif c.class == Array && c.length < 4
54
- raise Error, "Quads require 4 colors, one for each vertex. Only " <<
55
- "#{c.length} were given."
56
-
57
- # If a valid array of colors, assign them to each vertex, respectively
58
- elsif c.all? { |el| Color.is_valid? el }
59
- @c1 = Color.new(c[0])
60
- @c2 = Color.new(c[1])
61
- @c3 = Color.new(c[2])
62
- @c4 = Color.new(c[3])
63
-
62
+ if c.is_a? Color::Set
63
+ if c.length == 4
64
+ @c1 = c[0]
65
+ @c2 = c[1]
66
+ @c3 = c[2]
67
+ @c4 = c[3]
68
+ else
69
+ raise ArgumentError, "Quads require 4 colors, one for each vertex. #{c.length} were given."
70
+ end
64
71
  else
65
- raise Error, "Not a valid color for #{self.class}"
72
+ @c1 = c
73
+ @c2 = c
74
+ @c3 = c
75
+ @c4 = c
66
76
  end
67
-
68
77
  end
69
-
70
78
  end
71
79
  end
@@ -2,43 +2,54 @@
2
2
 
3
3
  module Ruby2D
4
4
  class Rectangle < Quad
5
-
5
+
6
6
  attr_reader :x, :y, :width, :height
7
-
8
- def initialize(x=0, y=0, w=200, h=100, c='white')
7
+
8
+ def initialize(opts = {})
9
9
  @type_id = 2
10
- @x, @y, @width, @height, @color = x, y, w, h, c
11
- update_coords(x, y, w, h)
12
- update_color(c)
10
+
11
+ @x = opts[:x] || 0
12
+ @y = opts[:y] || 0
13
+ @z = opts[:z] || 0
14
+ @width = opts[:width] || 200
15
+ @height = opts[:height] || 100
16
+
17
+ update_coords(@x, @y, @width, @height)
18
+
19
+ self.color = opts[:color] || 'white'
13
20
  add
14
21
  end
15
-
22
+
16
23
  def x=(x)
17
24
  @x = @x1 = x
18
25
  @x2 = x + @width
19
26
  @x3 = x + @width
20
27
  @x4 = x
21
28
  end
22
-
29
+
23
30
  def y=(y)
24
31
  @y = @y1 = y
25
32
  @y2 = y
26
33
  @y3 = y + @height
27
34
  @y4 = y + @height
28
35
  end
29
-
36
+
30
37
  def width=(w)
31
38
  @width = w
32
39
  update_coords(@x, @y, w, @height)
33
40
  end
34
-
41
+
35
42
  def height=(h)
36
43
  @height = h
37
44
  update_coords(@x, @y, @width, h)
38
45
  end
39
-
46
+
47
+ def contains?(x, y)
48
+ @x < x and @x + @width > x and @y < y and @y + @height > y
49
+ end
50
+
40
51
  private
41
-
52
+
42
53
  def update_coords(x, y, w, h)
43
54
  @x1 = x
44
55
  @y1 = y
@@ -49,6 +60,6 @@ module Ruby2D
49
60
  @x3 = x + w
50
61
  @y3 = y + h
51
62
  end
52
-
63
+
53
64
  end
54
65
  end
@@ -0,0 +1,35 @@
1
+ module Ruby2D
2
+ module Renderable
3
+ attr_reader :z
4
+
5
+ def z=(z)
6
+ remove
7
+ @z = z
8
+ add
9
+ end
10
+
11
+ def add
12
+ if Module.const_defined? :DSL
13
+ Application.add(self)
14
+ end
15
+ end
16
+
17
+ def remove
18
+ if Module.const_defined? :DSL
19
+ Application.remove(self)
20
+ end
21
+ end
22
+
23
+ def opacity
24
+ self.color.opacity
25
+ end
26
+
27
+ def opacity=(val)
28
+ self.color.opacity = val
29
+ end
30
+
31
+ def contains?(x, y)
32
+ raise "Not implemented yet"
33
+ end
34
+ end
35
+ end
data/lib/ruby2d/sound.rb CHANGED
@@ -2,15 +2,25 @@
2
2
 
3
3
  module Ruby2D
4
4
  class Sound
5
-
5
+
6
6
  attr_accessor :data
7
7
  attr_reader :path
8
-
8
+
9
9
  def initialize(path)
10
- # TODO: Check if file exists
11
- init(path)
10
+
11
+ unless RUBY_ENGINE == 'opal'
12
+ unless File.exists? path
13
+ raise Error, "Cannot find audio file `#{path}`"
14
+ end
15
+ end
16
+
12
17
  @path = path
18
+ ext_sound_init(path)
13
19
  end
14
-
20
+
21
+ def play
22
+ ext_sound_play
23
+ end
24
+
15
25
  end
16
26
  end