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.
data/lib/ruby2d/sprite.rb CHANGED
@@ -2,16 +2,17 @@
2
2
 
3
3
  module Ruby2D
4
4
  class Sprite
5
-
5
+
6
6
  attr_accessor :x, :y, :clip_x, :clip_y, :clip_w, :clip_h, :data
7
-
8
- def initialize(x, y, path)
9
-
7
+ attr_reader :z
8
+
9
+ def initialize(x, y, path, z=0)
10
+
10
11
  # unless File.exists? path
11
12
  # raise Error, "Cannot find image file `#{path}`"
12
13
  # end
13
-
14
- @type_id = 4
14
+
15
+ @type_id = 5
15
16
  @x, @y, @path = x, y, path
16
17
  @clip_x, @clip_y, @clip_w, @clip_h = 0, 0, 0, 0
17
18
  @default = nil
@@ -19,22 +20,23 @@ module Ruby2D
19
20
  @current_animation = nil
20
21
  @current_frame = 0
21
22
  @current_frame_time = 0
22
-
23
- init(path)
23
+ @z = z
24
+
25
+ ext_sprite_init(path)
24
26
  if Module.const_defined? :DSL
25
27
  Application.add(self)
26
28
  end
27
29
  end
28
-
30
+
29
31
  def start(x, y, w, h)
30
32
  @default = [x, y, w, h]
31
33
  clip(x, y, w, h)
32
34
  end
33
-
35
+
34
36
  def add(animations)
35
37
  @animations.merge!(animations)
36
38
  end
37
-
39
+
38
40
  def animate(animation)
39
41
  if @current_animation != animation
40
42
  @current_frame = 0
@@ -43,31 +45,31 @@ module Ruby2D
43
45
  end
44
46
  animate_frames(@animations[animation])
45
47
  end
46
-
48
+
47
49
  def reset
48
50
  clip(@default[0], @default[1], @default[2], @default[3])
49
51
  @current_animation = nil
50
52
  end
51
-
53
+
52
54
  # TODO: Sprite already has an `add` method, have to reconsile
53
55
  # def add
54
56
  # if Module.const_defined? :DSL
55
57
  # Application.add(self)
56
58
  # end
57
59
  # end
58
-
60
+
59
61
  def remove
60
62
  if Module.const_defined? :DSL
61
63
  Application.remove(self)
62
64
  end
63
65
  end
64
-
66
+
65
67
  private
66
-
68
+
67
69
  def clip(x, y, w, h)
68
70
  @clip_x, @clip_y, @clip_w, @clip_h = x, y, w, h
69
71
  end
70
-
72
+
71
73
  def animate_frames(frames)
72
74
  if @current_frame_time < frames[@current_frame][4]
73
75
  clip_with_current_frame(frames)
@@ -81,11 +83,11 @@ module Ruby2D
81
83
  @current_frame_time = 0
82
84
  end
83
85
  end
84
-
86
+
85
87
  def clip_with_current_frame(frames)
86
88
  clip(frames[@current_frame][0], frames[@current_frame][1],
87
89
  frames[@current_frame][2], frames[@current_frame][3])
88
90
  end
89
-
91
+
90
92
  end
91
93
  end
data/lib/ruby2d/square.rb CHANGED
@@ -2,22 +2,27 @@
2
2
 
3
3
  module Ruby2D
4
4
  class Square < Rectangle
5
-
5
+
6
6
  attr_reader :size
7
-
8
- def initialize(x=0, y=0, s=100, c='white')
7
+
8
+ def initialize(opts = {})
9
9
  @type_id = 2
10
- @x, @y, @color = x, y, c
11
- @width = @height = @size = s
12
- update_coords(x, y, s, s)
13
- update_color(c)
10
+ @x = opts[:x] || 0
11
+ @y = opts[:y] || 0
12
+ @z = opts[:z] || 0
13
+ @width = @height = @size = opts[:size] || 100
14
+
15
+ self.color = opts[:color] || 'white'
16
+
17
+ update_coords(@x, @y, @size, @size)
18
+
14
19
  add
15
20
  end
16
-
21
+
17
22
  def size=(s)
18
23
  self.width = self.height = @size = s
19
24
  end
20
-
25
+
21
26
  private :width=, :height=
22
27
  end
23
28
  end
data/lib/ruby2d/text.rb CHANGED
@@ -2,44 +2,48 @@
2
2
 
3
3
  module Ruby2D
4
4
  class Text
5
-
5
+ include Renderable
6
+
6
7
  attr_accessor :x, :y, :data
7
- attr_reader :text, :size, :font, :color
8
-
9
- def initialize(x=0, y=0, text="Hello World!", size=20, font=nil, c="white")
10
-
11
- # if File.exists? font
12
- @font = font
13
- # else
14
- # @font = resolve_path(font)
15
- # end
16
-
17
- @type_id = 5
18
- @x, @y, @size = x, y, size
19
- @text = text
20
- @color = Color.new(c)
21
- init
8
+ attr_reader :text, :size, :width, :height, :font, :color
9
+
10
+ def initialize(opts = {})
11
+ @type_id = 6
12
+
13
+ @x = opts[:x] || 0
14
+ @y = opts[:y] || 0
15
+ @z = opts[:z] || 0
16
+ @text = (opts[:text] || "Hello World!").to_s
17
+ @size = opts[:size] || 20
18
+
19
+ @font = opts[:font]
20
+
21
+ unless RUBY_ENGINE == 'opal'
22
+ unless File.exists? @font
23
+ raise Error, "Cannot find font file `#{@font}`"
24
+ end
25
+ end
26
+
27
+ self.color = opts[:color] || 'white'
28
+ ext_text_init
22
29
  add
23
30
  end
24
-
31
+
32
+ def text=(msg)
33
+ @text = msg.to_s
34
+ ext_text_set(@text)
35
+ end
36
+
25
37
  def color=(c)
26
38
  @color = Color.new(c)
27
39
  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
40
+
41
+ def contains?(x, y)
42
+ @x < x and @x + @width > x and @y < y and @y + @height > y
39
43
  end
40
-
44
+
41
45
  private
42
-
46
+
43
47
  def resolve_path(font)
44
48
  if RUBY_PLATFORM =~ /darwin/
45
49
  font_path = "/Library/Fonts/#{font}.ttf"
@@ -47,13 +51,13 @@ module Ruby2D
47
51
  # Linux
48
52
  font_path = "/usr/share/fonts/truetype/#{font}.ttf"
49
53
  end
50
-
54
+
51
55
  unless File.exists? font_path
52
56
  raise Error, "Cannot find system font"
53
57
  else
54
58
  font_path
55
59
  end
56
60
  end
57
-
61
+
58
62
  end
59
63
  end
@@ -2,64 +2,66 @@
2
2
 
3
3
  module Ruby2D
4
4
  class Triangle
5
-
5
+ include Renderable
6
+
6
7
  attr_accessor :x1, :y1, :c1,
7
8
  :x2, :y2, :c2,
8
9
  :x3, :y3, :c3
9
10
  attr_reader :color, :type_id
10
-
11
- def initialize(x1=50, y1=0, x2=100, y2=100, x3=0, y3=100, c='white')
11
+
12
+ def initialize(opts= {})
12
13
  @type_id = 1
13
- @x1, @y1 = x1, y1
14
- @x2, @y2 = x2, y2
15
- @x3, @y3 = x3, y3
16
- @color = c
17
- update_color(c)
14
+
15
+ @x1 = opts[:x1] || 50
16
+ @y1 = opts[:y1] || 0
17
+ @x2 = opts[:x2] || 100
18
+ @y2 = opts[:y2] || 100
19
+ @x3 = opts[:x3] || 0
20
+ @y3 = opts[:y3] || 100
21
+ @z = opts[:z] || 0
22
+
23
+ self.color = opts[:color] || 'white'
18
24
  add
19
25
  end
20
-
26
+
21
27
  def color=(c)
22
- update_color(c)
23
- @color = c
24
- end
25
-
26
- def add
27
- if Module.const_defined? :DSL
28
- Application.add(self)
29
- end
28
+ @color = Color.from(c)
29
+ update_color(@color)
30
30
  end
31
-
32
- def remove
33
- if Module.const_defined? :DSL
34
- Application.remove(self)
35
- end
31
+
32
+ # Point is inside a triangle if
33
+ # the area of 3 triangles, constructed from triangle sides and that point
34
+ # is equal to the area of triangle.
35
+ def contains?(x, y)
36
+ self_area = triangle_area(@x1, @y1, @x2, @y2, @x3, @y3)
37
+ questioned_area =
38
+ triangle_area(@x1, @y1, @x2, @y2, x, y) +
39
+ triangle_area(@x2, @y2, @x3, @y3, x, y) +
40
+ triangle_area(@x3, @y3, @x1, @y1, x, y)
41
+
42
+ questioned_area <= self_area
36
43
  end
37
-
44
+
38
45
  private
39
-
46
+
47
+ def triangle_area(x1, y1, x2, y2, x3, y3)
48
+ (x1*y2 + x2*y3 + x3*y1 - x3*y2 - x1*y3 - x2*y1).abs / 2
49
+ end
50
+
40
51
  def update_color(c)
41
-
42
- # If a valid color, use it for each vertex
43
- if Color.is_valid? c
44
- @c1 = Color.new(c)
45
- @c2 = Color.new(c)
46
- @c3 = Color.new(c)
47
-
48
- elsif c.class == Array && c.length < 3
49
- raise Error, "Triangles require 3 colors, one for each vertex. Only " <<
50
- "#{c.length} were given."
51
-
52
- # If a valid array of colors, assign them to each vertex, respectively
53
- elsif c.all? { |el| Color.is_valid? el }
54
- @c1 = Color.new(c[0])
55
- @c2 = Color.new(c[1])
56
- @c3 = Color.new(c[2])
57
-
52
+ if c.is_a? Color::Set
53
+ if c.length == 3
54
+ @c1 = c[0]
55
+ @c2 = c[1]
56
+ @c3 = c[2]
57
+ else
58
+ raise ArgumentError, "Triangles require 3 colors, one for each vertex. #{c.length} were given."
59
+ end
58
60
  else
59
- raise Error, "Not a valid color for #{self.class}"
61
+ @c1 = c
62
+ @c2 = c
63
+ @c3 = c
60
64
  end
61
-
62
65
  end
63
-
64
66
  end
65
67
  end
@@ -1,5 +1,5 @@
1
1
  # version.rb
2
2
 
3
3
  module Ruby2D
4
- VERSION = '0.3.1'
4
+ VERSION = '0.4.0'
5
5
  end
data/lib/ruby2d/window.rb CHANGED
@@ -2,10 +2,15 @@
2
2
 
3
3
  module Ruby2D
4
4
  class Window
5
-
5
+
6
6
  attr_reader :objects
7
7
  attr_accessor :mouse_x, :mouse_y, :frames, :fps
8
-
8
+
9
+ MouseEvent = Struct.new(:type, :button, :direction, :x, :y, :delta_x, :delta_y)
10
+ KeyEvent = Struct.new(:type, :key)
11
+ ControllerEvent = Struct.new(:which, :type, :axis, :value, :button)
12
+ EventDescriptor = Struct.new(:type, :id)
13
+
9
14
  def initialize(args = {})
10
15
  @title = args[:title] || "Ruby 2D"
11
16
  @background = Color.new([0.0, 0.0, 0.0, 1.0])
@@ -17,18 +22,35 @@ module Ruby2D
17
22
  @fullscreen = false
18
23
  @highdpi = false
19
24
  @frames = 0
20
- @fps_cap = args[:fps] || 60
25
+ @fps_cap = args[:fps] || 60
21
26
  @fps = @fps_cap
22
- @vsync = args[:vsync] || true
23
- @mouse_x = 0; @mouse_y = 0
27
+ @vsync = args[:vsync] || true
28
+ @mouse_x, @mouse_y = 0, 0
24
29
  @objects = []
25
- @keys_down, @keys, @keys_up, @mouse, @controller = {}, {}, {}, {}, {}
26
- @on_key_proc = Proc.new {}
27
- @on_controller_proc = Proc.new {}
28
- @update_proc = Proc.new {}
29
- @diagnostics = false
30
+ @event_key = 0
31
+ @events = {
32
+ key: {},
33
+ key_down: {},
34
+ key_held: {},
35
+ key_up: {},
36
+ mouse: {},
37
+ mouse_up: {},
38
+ mouse_down: {},
39
+ mouse_scroll: {},
40
+ mouse_move: {},
41
+ controller: {},
42
+ controller_axis: {},
43
+ controller_button_down: {},
44
+ controller_button_up: {}
45
+ }
46
+ @update_proc = Proc.new {}
47
+ @diagnostics = false
30
48
  end
31
-
49
+
50
+ def new_event_key
51
+ @event_key = @event_key.next
52
+ end
53
+
32
54
  def get(sym)
33
55
  case sym
34
56
  when :window; self
@@ -49,7 +71,7 @@ module Ruby2D
49
71
  when :diagnostics; @diagnostics
50
72
  end
51
73
  end
52
-
74
+
53
75
  def set(opts)
54
76
  # Store new window attributes, or ignore if nil
55
77
  @title = opts[:title] || @title
@@ -66,7 +88,7 @@ module Ruby2D
66
88
  @highdpi = opts[:highdpi] || @highdpi
67
89
  @diagnostics = opts[:diagnostics] || @diagnostics
68
90
  end
69
-
91
+
70
92
  def add(o)
71
93
  case o
72
94
  when nil
@@ -77,153 +99,159 @@ module Ruby2D
77
99
  add_object(o)
78
100
  end
79
101
  end
80
-
102
+
81
103
  def remove(o)
82
104
  if o == nil
83
105
  raise Error, "Cannot remove '#{o.class}' from window!"
84
106
  end
85
-
107
+
86
108
  if i = @objects.index(o)
87
- @objects.slice!(i)
109
+ @objects.delete_at(i)
88
110
  true
89
111
  else
90
112
  false
91
113
  end
92
114
  end
93
-
115
+
94
116
  def clear
95
117
  @objects.clear
96
118
  end
97
-
119
+
98
120
  def update(&proc)
99
121
  @update_proc = proc
100
122
  true
101
123
  end
102
-
103
- # def on(mouse: nil, key: nil, key_up: nil, key_down: nil, controller: nil, &proc)
104
- def on(args = {}, &proc)
105
- mouse = args[:mouse]
106
- key = args[:key]
107
- key_up = args[:key_up]
108
- key_down = args[:key_down]
109
- controller = args[:controller]
110
-
111
- unless mouse.nil?
112
- reg_mouse(mouse, &proc)
113
- end
114
-
115
- unless key_down.nil?
116
- reg_key_down(key_down, &proc)
117
- end
118
-
119
- unless key.nil?
120
- reg_key(key, &proc)
121
- end
122
-
123
- unless key_up.nil?
124
- reg_key_up(key_up, &proc)
125
- end
126
-
127
- unless controller.nil?
128
- reg_controller(controller, &proc)
129
- end
130
- end
131
-
132
- def mouse_callback(btn, x, y)
133
- if @mouse.has_key? 'any'
134
- @mouse[btn].call(x, y)
124
+
125
+ def on(event, &proc)
126
+ unless @events.has_key? event
127
+ raise Error, "`#{event}` is not a valid event type"
135
128
  end
129
+ event_id = new_event_key
130
+ @events[event][event_id] = proc
131
+ EventDescriptor.new(event, event_id)
136
132
  end
137
-
138
- def on_key(&proc)
139
- @on_key_proc = proc
140
- true
133
+
134
+ def off(event_descriptor)
135
+ @events[event_descriptor.type].delete(event_descriptor.id)
141
136
  end
142
-
143
- def key_down_callback(key)
137
+
138
+ def key_callback(type, key)
139
+ # puts "===", "type: #{type}", "key: #{key}"
140
+
144
141
  key = key.downcase
145
- if @keys_down.has_key? 'any'
146
- @keys_down['any'].call
142
+
143
+ # All key events
144
+ @events[:key].each do |id, e|
145
+ e.call(KeyEvent.new(type, key))
147
146
  end
148
- if @keys_down.has_key? key
149
- @keys_down[key].call
147
+
148
+ case type
149
+ # When key is pressed, fired once
150
+ when :down
151
+ @events[:key_down].each do |id, e|
152
+ e.call(KeyEvent.new(type, key))
153
+ end
154
+ # When key is being held down, fired every frame
155
+ when :held
156
+ @events[:key_held].each do |id, e|
157
+ e.call(KeyEvent.new(type, key))
158
+ end
159
+ # When key released, fired once
160
+ when :up
161
+ @events[:key_up].each do |id, e|
162
+ e.call(KeyEvent.new(type, key))
163
+ end
150
164
  end
151
165
  end
152
-
153
- def key_callback(key)
154
- key = key.downcase
155
- @on_key_proc.call(key)
156
- if @keys.has_key? 'any'
157
- @keys['any'].call
166
+
167
+ def mouse_callback(type, button, direction, x, y, delta_x, delta_y)
168
+ # Convert to symbols (see MRuby bug in native extension)
169
+ button = button.to_sym unless button == nil
170
+ direction = direction.to_sym unless direction == nil
171
+
172
+ # All mouse events
173
+ @events[:mouse].each do |id, e|
174
+ e.call(MouseEvent.new(type, button, direction, x, y, delta_x, delta_y))
158
175
  end
159
- if @keys.has_key? key
160
- @keys[key].call
176
+
177
+ case type
178
+ # When mouse button pressed
179
+ when :down
180
+ @events[:mouse_down].each do |id, e|
181
+ e.call(MouseEvent.new(type, button, nil, x, y, nil, nil))
182
+ end
183
+ # When mouse button released
184
+ when :up
185
+ @events[:mouse_up].each do |id, e|
186
+ e.call(MouseEvent.new(type, button, nil, x, y, nil, nil))
187
+ end
188
+ # When mouse motion / movement
189
+ when :scroll
190
+ @events[:mouse_scroll].each do |id, e|
191
+ e.call(MouseEvent.new(type, nil, direction, nil, nil, delta_x, delta_y))
192
+ end
193
+ # When mouse scrolling, wheel or trackpad
194
+ when :move
195
+ @events[:mouse_move].each do |id, e|
196
+ e.call(MouseEvent.new(type, nil, nil, x, y, delta_x, delta_y))
197
+ end
161
198
  end
162
199
  end
163
-
164
- def key_up_callback(key)
165
- key = key.downcase
166
- if @keys_up.has_key? 'any'
167
- @keys_up['any'].call
200
+
201
+ def controller_callback(which, type, axis, value, button)
202
+ # All controller events
203
+ @events[:controller].each do |id, e|
204
+ e.call(ControllerEvent.new(which, type, axis, value, button))
168
205
  end
169
- if @keys_up.has_key? key
170
- @keys_up[key].call
206
+
207
+ case type
208
+ # When controller axis motion, like analog sticks
209
+ when :axis
210
+ @events[:controller_axis].each do |id, e|
211
+ e.call(ControllerEvent.new(which, type, axis, value, nil))
212
+ end
213
+ # When controller button is pressed
214
+ when :button_down
215
+ @events[:controller_button_down].each do |id, e|
216
+ e.call(ControllerEvent.new(which, type, nil, nil, button))
217
+ end
218
+ # When controller button is released
219
+ when :button_up
220
+ @events[:controller_button_up].each do |id, e|
221
+ e.call(ControllerEvent.new(which, type, nil, nil, button))
222
+ end
171
223
  end
172
224
  end
173
-
174
- def on_controller(&proc)
175
- @on_controller_proc = proc
176
- true
177
- end
178
-
179
- def controller_callback(which, is_axis, axis, val, is_btn, btn, pressed)
180
- @on_controller_proc.call(which, is_axis, axis, val, is_btn, btn, pressed)
181
- end
182
-
225
+
183
226
  def update_callback
184
227
  @update_proc.call
185
228
  end
186
-
229
+
230
+ def show
231
+ ext_window_show
232
+ end
233
+
234
+ def close
235
+ ext_window_close
236
+ end
237
+
187
238
  private
188
-
239
+
189
240
  def add_object(o)
190
241
  if !@objects.include?(o)
191
- @objects.push(o)
242
+ index = @objects.index do |object|
243
+ object.z > o.z
244
+ end
245
+ if index
246
+ @objects.insert(index, o)
247
+ else
248
+ @objects.push(o)
249
+ end
192
250
  true
193
251
  else
194
252
  false
195
253
  end
196
254
  end
197
-
198
- # Register key string with proc
199
- def reg_key_down(key, &proc)
200
- @keys_down[key] = proc
201
- true
202
- end
203
-
204
- # Register key string with proc
205
- def reg_key(key, &proc)
206
- @keys[key] = proc
207
- true
208
- end
209
-
210
- # Register key string with proc
211
- def reg_key_up(key, &proc)
212
- @keys_up[key] = proc
213
- true
214
- end
215
-
216
- # Register mouse button string with proc
217
- def reg_mouse(btn, &proc)
218
- @mouse[btn] = proc
219
- true
220
- end
221
-
222
- # Register controller string with proc
223
- def reg_controller(event, &proc)
224
- @controller[event] = proc
225
- true
226
- end
227
-
255
+
228
256
  end
229
257
  end