ruby2d 0.3.1 → 0.4.0

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