ruby2d 0.3.1 → 0.4.0

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