cyberarm_engine 0.12.1 → 0.16.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.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +8 -0
  3. data/Gemfile +1 -1
  4. data/README.md +33 -3
  5. data/Rakefile +1 -1
  6. data/assets/textures/default.png +0 -0
  7. data/cyberarm_engine.gemspec +11 -8
  8. data/lib/cyberarm_engine.rb +25 -7
  9. data/lib/cyberarm_engine/animator.rb +56 -0
  10. data/lib/cyberarm_engine/background.rb +19 -15
  11. data/lib/cyberarm_engine/background_nine_slice.rb +125 -0
  12. data/lib/cyberarm_engine/bounding_box.rb +18 -18
  13. data/lib/cyberarm_engine/cache.rb +4 -0
  14. data/lib/cyberarm_engine/cache/download_manager.rb +121 -0
  15. data/lib/cyberarm_engine/common.rb +16 -16
  16. data/lib/cyberarm_engine/config_file.rb +46 -0
  17. data/lib/cyberarm_engine/game_object.rb +63 -72
  18. data/lib/cyberarm_engine/game_state.rb +7 -4
  19. data/lib/cyberarm_engine/model.rb +207 -0
  20. data/lib/cyberarm_engine/model/material.rb +21 -0
  21. data/lib/cyberarm_engine/model/model_object.rb +131 -0
  22. data/lib/cyberarm_engine/model/parser.rb +74 -0
  23. data/lib/cyberarm_engine/model/parsers/collada_parser.rb +138 -0
  24. data/lib/cyberarm_engine/model/parsers/wavefront_parser.rb +154 -0
  25. data/lib/cyberarm_engine/model_cache.rb +31 -0
  26. data/lib/cyberarm_engine/opengl.rb +28 -0
  27. data/lib/cyberarm_engine/opengl/light.rb +50 -0
  28. data/lib/cyberarm_engine/opengl/orthographic_camera.rb +46 -0
  29. data/lib/cyberarm_engine/opengl/perspective_camera.rb +38 -0
  30. data/lib/cyberarm_engine/opengl/renderer/bounding_box_renderer.rb +249 -0
  31. data/lib/cyberarm_engine/opengl/renderer/g_buffer.rb +164 -0
  32. data/lib/cyberarm_engine/opengl/renderer/opengl_renderer.rb +289 -0
  33. data/lib/cyberarm_engine/opengl/renderer/renderer.rb +22 -0
  34. data/lib/cyberarm_engine/opengl/shader.rb +406 -0
  35. data/lib/cyberarm_engine/opengl/texture.rb +69 -0
  36. data/lib/cyberarm_engine/ray.rb +5 -5
  37. data/lib/cyberarm_engine/stats.rb +21 -0
  38. data/lib/cyberarm_engine/text.rb +45 -31
  39. data/lib/cyberarm_engine/timer.rb +1 -1
  40. data/lib/cyberarm_engine/transform.rb +221 -9
  41. data/lib/cyberarm_engine/ui/border_canvas.rb +4 -3
  42. data/lib/cyberarm_engine/ui/dsl.rb +86 -50
  43. data/lib/cyberarm_engine/ui/element.rb +60 -21
  44. data/lib/cyberarm_engine/ui/elements/button.rb +121 -28
  45. data/lib/cyberarm_engine/ui/elements/check_box.rb +25 -33
  46. data/lib/cyberarm_engine/ui/elements/container.rb +88 -24
  47. data/lib/cyberarm_engine/ui/elements/edit_box.rb +179 -0
  48. data/lib/cyberarm_engine/ui/elements/edit_line.rb +180 -27
  49. data/lib/cyberarm_engine/ui/elements/flow.rb +1 -3
  50. data/lib/cyberarm_engine/ui/elements/image.rb +32 -12
  51. data/lib/cyberarm_engine/ui/elements/label.rb +122 -16
  52. data/lib/cyberarm_engine/ui/elements/list_box.rb +82 -0
  53. data/lib/cyberarm_engine/ui/elements/progress.rb +6 -5
  54. data/lib/cyberarm_engine/ui/elements/radio.rb +6 -0
  55. data/lib/cyberarm_engine/ui/elements/slider.rb +104 -0
  56. data/lib/cyberarm_engine/ui/elements/stack.rb +1 -3
  57. data/lib/cyberarm_engine/ui/elements/text_block.rb +156 -0
  58. data/lib/cyberarm_engine/ui/elements/toggle_button.rb +40 -31
  59. data/lib/cyberarm_engine/ui/event.rb +8 -7
  60. data/lib/cyberarm_engine/ui/gui_state.rb +94 -6
  61. data/lib/cyberarm_engine/ui/style.rb +10 -9
  62. data/lib/cyberarm_engine/ui/theme.rb +85 -22
  63. data/lib/cyberarm_engine/vector.rb +132 -38
  64. data/lib/cyberarm_engine/version.rb +2 -2
  65. data/lib/cyberarm_engine/{engine.rb → window.rb} +32 -19
  66. metadata +88 -17
  67. data/lib/cyberarm_engine/gosu_ext/circle.rb +0 -9
  68. data/lib/cyberarm_engine/shader.rb +0 -205
@@ -15,19 +15,18 @@ module CyberarmEngine
15
15
 
16
16
  return unless enabled?
17
17
 
18
- if respond_to?(event)
19
- return :handled if send(event, self, *args) == :handled
20
- end
18
+ return :handled if respond_to?(event) && (send(event, self, *args) == :handled)
21
19
 
22
20
  @event_handler[event].reverse_each do |handler|
23
21
  return :handled if handler.call(self, *args) == :handled
24
22
  end
25
23
 
26
- return nil
24
+ parent.publish(event, *args) if parent
25
+ nil
27
26
  end
28
27
 
29
28
  def event(event)
30
- @event_handler ||= Hash.new
29
+ @event_handler ||= {}
31
30
  @event_handler[event] ||= []
32
31
  end
33
32
  end
@@ -36,11 +35,13 @@ module CyberarmEngine
36
35
  attr_reader :publisher, :event, :handler
37
36
 
38
37
  def initialize(publisher, event, handler)
39
- @publisher, @event, @handler = publisher, event, handler
38
+ @publisher = publisher
39
+ @event = event
40
+ @handler = handler
40
41
  end
41
42
 
42
43
  def unsubscribe
43
44
  @publisher.unsubscribe(self)
44
45
  end
45
46
  end
46
- end
47
+ end
@@ -12,22 +12,30 @@ module CyberarmEngine
12
12
 
13
13
  @root_container = Element::Stack.new(gui_state: self)
14
14
  @game_objects << @root_container
15
- @containers = [@root_container]
15
+ $__current_container__ = @root_container
16
16
 
17
17
  @active_width = window.width
18
18
  @active_height = window.height
19
19
 
20
+ @menu = nil
20
21
  @focus = nil
21
22
  @mouse_over = nil
22
23
  @mouse_down_on = {}
23
24
  @mouse_down_position = {}
25
+ @last_mouse_pos = nil
26
+ @dragging_element = nil
24
27
  @pending_recalculate_request = false
28
+
29
+ @tip = Element::ToolTip.new("", parent: @root_container, z: Float::INFINITY)
30
+ @menu = nil
31
+ @min_drag_distance = 0
32
+ @mouse_pos = Vector.new
25
33
  end
26
34
 
27
35
  # throws :blur event to focused element and sets GuiState focused element
28
36
  # Does NOT throw :focus event at element or set element as focused
29
37
  def focus=(element)
30
- @focus.publish(:blur) if @focus and element && @focus != element
38
+ @focus.publish(:blur) if @focus && element && @focus != element
31
39
  @focus = element
32
40
  end
33
41
 
@@ -35,15 +43,35 @@ module CyberarmEngine
35
43
  @focus
36
44
  end
37
45
 
46
+ def draw
47
+ super
48
+
49
+ if @menu
50
+ Gosu.flush
51
+ @menu.draw
52
+ end
53
+
54
+ if @tip.value.length.positive?
55
+ Gosu.flush
56
+ @tip.draw
57
+ end
58
+ end
59
+
38
60
  def update
39
61
  if @pending_recalculate_request
40
62
  @root_container.recalculate
63
+ @root_container.recalculate
64
+ @root_container.recalculate
65
+
41
66
  @pending_recalculate_request = false
42
67
  end
43
68
 
69
+ @menu&.update
44
70
  super
45
71
 
46
- new_mouse_over = @root_container.hit_element?(window.mouse_x, window.mouse_y)
72
+ new_mouse_over = @menu.hit_element?(window.mouse_x, window.mouse_y) if @menu
73
+ new_mouse_over ||= @root_container.hit_element?(window.mouse_x, window.mouse_y)
74
+
47
75
  if new_mouse_over
48
76
  new_mouse_over.publish(:enter) if new_mouse_over != @mouse_over
49
77
  new_mouse_over.publish(:hover)
@@ -56,12 +84,37 @@ module CyberarmEngine
56
84
  redirect_holding_mouse_button(:middle) if @mouse_over && Gosu.button_down?(Gosu::MsMiddle)
57
85
  redirect_holding_mouse_button(:right) if @mouse_over && Gosu.button_down?(Gosu::MsRight)
58
86
 
87
+ if Vector.new(window.mouse_x, window.mouse_y) == @last_mouse_pos
88
+ if @mouse_over && (Gosu.milliseconds - @mouse_moved_at) > tool_tip_delay
89
+ @tip.value = @mouse_over.tip if @mouse_over
90
+ @tip.x = window.mouse_x - @tip.width / 2
91
+ @tip.x = 0 if @tip.x < 0
92
+ @tip.x = window.width - @tip.width if @tip.x + @tip.width > window.width
93
+ @tip.y = window.mouse_y - @tip.height
94
+ @tip.y = 0 if @tip.y < 0
95
+ @tip.y = window.height - @tip.height if @tip.y + @tip.height > window.height
96
+ @tip.update
97
+ @tip.recalculate
98
+ else
99
+ @tip.value = ""
100
+ end
101
+ else
102
+ @mouse_moved_at = Gosu.milliseconds
103
+ end
104
+
105
+ @last_mouse_pos = Vector.new(window.mouse_x, window.mouse_y)
106
+ @mouse_pos = @last_mouse_pos.clone
107
+
59
108
  request_recalculate if @active_width != window.width || @active_height != window.height
60
109
 
61
110
  @active_width = window.width
62
111
  @active_height = window.height
63
112
  end
64
113
 
114
+ def tool_tip_delay
115
+ 250 # ms
116
+ end
117
+
65
118
  def button_down(id)
66
119
  super
67
120
 
@@ -72,7 +125,11 @@ module CyberarmEngine
72
125
  redirect_mouse_button(:middle)
73
126
  when Gosu::MsRight
74
127
  redirect_mouse_button(:right)
128
+ when Gosu::KbF5
129
+ request_recalculate
75
130
  end
131
+
132
+ @focus.button_down(id) if @focus.respond_to?(:button_down)
76
133
  end
77
134
 
78
135
  def button_up(id)
@@ -90,9 +147,13 @@ module CyberarmEngine
90
147
  when Gosu::MsWheelDown
91
148
  redirect_mouse_wheel(:down)
92
149
  end
150
+
151
+ @focus.button_up(id) if @focus.respond_to?(:button_up)
93
152
  end
94
153
 
95
154
  def redirect_mouse_button(button)
155
+ hide_menu unless @menu && (@menu == @mouse_over) || (@mouse_over&.parent == @menu)
156
+
96
157
  if @focus && @mouse_over != @focus
97
158
  @focus.publish(:blur)
98
159
  @focus = nil
@@ -110,9 +171,19 @@ module CyberarmEngine
110
171
  end
111
172
 
112
173
  def redirect_released_mouse_button(button)
174
+ hide_menu if @menu && (@menu == @mouse_over) || (@mouse_over&.parent == @menu)
175
+
113
176
  if @mouse_over
114
177
  @mouse_over.publish(:"released_#{button}_mouse_button", window.mouse_x, window.mouse_y)
115
- @mouse_over.publish(:"clicked_#{button}_mouse_button", window.mouse_x, window.mouse_y) if @mouse_over == @mouse_down_on[button]
178
+ if @mouse_over == @mouse_down_on[button]
179
+ @mouse_over.publish(:"clicked_#{button}_mouse_button", window.mouse_x,
180
+ window.mouse_y)
181
+ end
182
+ end
183
+
184
+ if @dragging_element
185
+ @dragging_element.publish(:end_drag, window.mouse_x, window.mouse_y, button)
186
+ @dragging_element = nil
116
187
  end
117
188
 
118
189
  @mouse_down_position[button] = nil
@@ -120,7 +191,16 @@ module CyberarmEngine
120
191
  end
121
192
 
122
193
  def redirect_holding_mouse_button(button)
123
- @mouse_over.publish(:"holding_#{button}_mouse_button", window.mouse_x, window.mouse_y) if @mouse_over
194
+ if !@dragging_element && @mouse_down_on[button] && @mouse_down_on[button].draggable?(button) && @mouse_pos.distance(@mouse_down_position[button]) > @min_drag_distance
195
+ @dragging_element = @mouse_down_on[button]
196
+ @dragging_element.publish(:begin_drag, window.mouse_x, window.mouse_y, button)
197
+ end
198
+
199
+ if @dragging_element
200
+ @dragging_element.publish(:drag_update, window.mouse_x, window.mouse_y, button) if @dragging_element
201
+ elsif @mouse_over
202
+ @mouse_over.publish(:"holding_#{button}_mouse_button", window.mouse_x, window.mouse_y)
203
+ end
124
204
  end
125
205
 
126
206
  def redirect_mouse_wheel(button)
@@ -131,5 +211,13 @@ module CyberarmEngine
131
211
  def request_recalculate
132
212
  @pending_recalculate_request = true
133
213
  end
214
+
215
+ def show_menu(list_box)
216
+ @menu = list_box
217
+ end
218
+
219
+ def hide_menu
220
+ @menu = nil
221
+ end
134
222
  end
135
- end
223
+ end
@@ -1,11 +1,11 @@
1
1
  module Gosu
2
2
  class Color
3
- def _dump(level)
3
+ def _dump(_level)
4
4
  [
5
- "%02X" % self.alpha,
6
- "%02X" % self.red,
7
- "%02X" % self.green,
8
- "%02X" % self.blue
5
+ "%02X" % alpha,
6
+ "%02X" % red,
7
+ "%02X" % green,
8
+ "%02X" % blue
9
9
  ].join
10
10
  end
11
11
 
@@ -21,17 +21,18 @@ module CyberarmEngine
21
21
  @hash = Marshal.load(Marshal.dump(hash))
22
22
  end
23
23
 
24
- def method_missing(method, *args, &block)
24
+ def method_missing(method, *args)
25
25
  if method.to_s.end_with?("=")
26
26
  raise "Did not expect more than 1 argument" if args.size > 1
27
- return @hash[method.to_s.sub("=", "").to_sym] = args.first
27
+
28
+ @hash[method.to_s.sub("=", "").to_sym] = args.first
28
29
 
29
30
  elsif args.size == 0
30
- return @hash[method]
31
+ @hash[method]
31
32
 
32
33
  else
33
34
  raise ArgumentError, "Did not expect arguments"
34
35
  end
35
36
  end
36
37
  end
37
- end
38
+ end
@@ -11,17 +11,21 @@ module CyberarmEngine
11
11
 
12
12
  def theme_defaults(options)
13
13
  raise "Error" unless self.class.ancestors.include?(CyberarmEngine::Element)
14
+
14
15
  _theme = THEME
15
- _theme = _theme.merge(options[:theme]) if options[:theme]
16
+ _theme = deep_merge(_theme, options[:theme]) if options[:theme]
16
17
  _theme.delete(:theme) if options[:theme]
17
18
 
18
19
  hash = {}
19
20
  class_names = self.class.ancestors
20
- class_names = class_names[0..class_names.index(CyberarmEngine::Element)].map! {|c| c.to_s.split("::").last.to_sym}.reverse!
21
+ class_names = class_names[0..class_names.index(CyberarmEngine::Element)].map! do |c|
22
+ c.to_s.split("::").last.to_sym
23
+ end.reverse!
21
24
 
22
25
  class_names.each do |klass|
23
26
  next unless data = _theme.dig(klass)
24
- data.each do |key, value|
27
+
28
+ data.each do |_key, _value|
25
29
  hash.merge!(data)
26
30
  end
27
31
  end
@@ -32,7 +36,7 @@ module CyberarmEngine
32
36
  # Derived from Rails Hash#deep_merge!
33
37
  # Enables passing partial themes through Element options without issue
34
38
  def deep_merge(original, intergrate, &block)
35
- hash = original.merge(intergrate) do |key, this_val, other_val|
39
+ original.merge(intergrate) do |key, this_val, other_val|
36
40
  if this_val.is_a?(Hash) && other_val.is_a?(Hash)
37
41
  deep_merge(this_val, other_val, &block)
38
42
  elsif block_given?
@@ -41,8 +45,6 @@ module CyberarmEngine
41
45
  other_val
42
46
  end
43
47
  end
44
-
45
- return hash
46
48
  end
47
49
 
48
50
  THEME = {
@@ -51,33 +53,40 @@ module CyberarmEngine
51
53
  y: 0,
52
54
  z: 30,
53
55
 
54
- width: nil,
56
+ width: nil,
55
57
  height: nil,
56
- color: Gosu::Color::WHITE,
58
+ color: Gosu::Color::WHITE,
57
59
  background: Gosu::Color::NONE,
58
- margin: 0,
59
- padding: 0,
60
+ margin: 0,
61
+ padding: 0,
60
62
  border_thickness: 0,
61
63
  border_color: Gosu::Color::NONE,
62
- border_radius: 0,
64
+ border_radius: 0
63
65
  },
64
66
 
65
67
  Button: { # < Label
66
- margin: 1,
67
- padding: 4,
68
+ margin: 1,
69
+ padding: 4,
68
70
  border_thickness: 1,
69
71
  border_color: ["ffd59674".hex, "ffff8746".hex],
70
72
  border_radius: 0,
71
73
  background: ["ffc75e61".to_i(16), "ffe26623".to_i(16)],
74
+ text_align: :center,
75
+ text_wrap: :none,
72
76
 
73
77
  hover: {
74
- color: Gosu::Color.rgb(200,200,200),
75
- background: ["ffB23E41".to_i(16), "ffFF7C00".to_i(16)],
78
+ color: Gosu::Color.rgb(200, 200, 200),
79
+ background: ["ffB23E41".to_i(16), "ffFF7C00".to_i(16)]
76
80
  },
77
81
 
78
82
  active: {
79
83
  color: Gosu::Color::BLACK,
80
84
  background: ["ffB23E41".to_i(16)]
85
+ },
86
+
87
+ disabled: {
88
+ color: Gosu::Color::GRAY,
89
+ background: 0xff303030
81
90
  }
82
91
  },
83
92
 
@@ -88,18 +97,63 @@ module CyberarmEngine
88
97
  caret_width: 2,
89
98
  caret_color: Gosu::Color::WHITE,
90
99
  caret_interval: 500,
100
+ selection_color: Gosu::Color.rgba(255, 128, 50, 200),
101
+ text_align: :left
91
102
  },
92
103
 
93
104
  Image: { # < Element
105
+ color: Gosu::Color::WHITE,
106
+ tileable: false,
94
107
  retro: false
95
108
  },
96
109
 
97
- Label: { # < Element
98
- text_size: 28,
99
- text_shadow: false,
100
- font: "Arial",
101
- margin: 0,
102
- padding: 2
110
+ TextBlock: { # < Element
111
+ text_size: 28,
112
+ text_wrap: :word_wrap, # :word_wrap, :break_word, :none
113
+ text_shadow: false,
114
+ text_align: :left,
115
+ font: "Arial",
116
+ margin: 0,
117
+ padding: 2
118
+ },
119
+
120
+ Banner: { # < TextBlock
121
+ text_size: 48
122
+ },
123
+
124
+ Title: { # < TextBlock
125
+ text_size: 34
126
+ },
127
+
128
+ Subtitle: { # < TextBlock
129
+ text_size: 26
130
+ },
131
+
132
+ Tagline: { # < TextBlock
133
+ text_size: 24
134
+ },
135
+
136
+ Caption: { # < TextBlock
137
+ text_size: 22
138
+ },
139
+
140
+ Para: { # < TextBlock
141
+ text_size: 18
142
+ },
143
+
144
+ Inscription: { # < TextBlock
145
+ text_size: 16
146
+ },
147
+
148
+ ToolTip: { # < TextBlock
149
+ color: Gosu::Color::WHITE,
150
+ padding_top: 4,
151
+ padding_bottom: 4,
152
+ padding_left: 8,
153
+ padding_right: 8,
154
+ border_thickness: 1,
155
+ border_color: 0xffaaaaaa,
156
+ background: 0xff404040
103
157
  },
104
158
 
105
159
  ToggleButton: { # < Button
@@ -111,7 +165,16 @@ module CyberarmEngine
111
165
  height: 36,
112
166
  background: 0xff111111,
113
167
  fraction_background: [0xffc75e61, 0xffe26623],
114
- border_thickness: 4,
168
+ border_thickness: 1,
169
+ border_color: [0xffd59674, 0xffff8746]
170
+ },
171
+
172
+ Slider: { # < Element
173
+ width: 250,
174
+ height: 36,
175
+ background: 0xff111111,
176
+ fraction_background: [0xffc75e61, 0xffe26623],
177
+ border_thickness: 1,
115
178
  border_color: [0xffd59674, 0xffff8746]
116
179
  }
117
180
  }.freeze
@@ -1,63 +1,101 @@
1
1
  module CyberarmEngine
2
2
  class Vector
3
+ ##
4
+ # Creates a up vector
5
+ #
6
+ # Vector.new(0, 1, 0)
7
+ #
8
+ # @return [CyberarmEngine::Vector]
3
9
  def self.up
4
10
  Vector.new(0, 1, 0)
5
11
  end
6
12
 
13
+ ##
14
+ # Creates a down vector
15
+ #
16
+ # Vector.new(0, -1, 0)
17
+ #
18
+ # @return [CyberarmEngine::Vector]
7
19
  def self.down
8
20
  Vector.new(0, -1, 0)
9
21
  end
10
22
 
23
+ ##
24
+ # Creates a left vector
25
+ #
26
+ # Vector.new(-1, 0, 0)
27
+ #
28
+ # @return [CyberarmEngine::Vector]
11
29
  def self.left
12
30
  Vector.new(-1, 0, 0)
13
31
  end
14
32
 
33
+ ##
34
+ # Creates a right vector
35
+ #
36
+ # Vector.new(1, 0, 0)
37
+ #
38
+ # @return [CyberarmEngine::Vector]
15
39
  def self.right
16
40
  Vector.new(1, 0, 0)
17
41
  end
18
42
 
43
+ ##
44
+ # Creates a forward vector
45
+ #
46
+ # Vector.new(0, 0, 1)
47
+ #
48
+ # @return [CyberarmEngine::Vector]
19
49
  def self.forward
20
50
  Vector.new(0, 0, 1)
21
51
  end
22
52
 
53
+ ##
54
+ # Creates a backward vector
55
+ #
56
+ # Vector.new(0, 0, -1)
57
+ #
58
+ # @return [CyberarmEngine::Vector]
23
59
  def self.backward
24
60
  Vector.new(0, 0, -1)
25
61
  end
26
62
 
63
+ attr_accessor :x, :y, :z, :weight
64
+
27
65
  def initialize(x = 0, y = 0, z = 0, weight = 0)
28
- @x, @y, @z, @weight = x, y, z, weight
66
+ @x = x
67
+ @y = y
68
+ @z = z
69
+ @weight = weight
29
70
  end
30
71
 
31
- def x; @x; end
32
- def x=(n); @x = n; end
33
-
34
- def y; @y; end
35
- def y=(n); @y = n; end
36
-
37
- def z; @z; end
38
- def z=(n); @z = n; end
39
-
40
- def weight; @weight; end
41
- def weight=(n); @weight = n; end
42
-
43
72
  alias w weight
44
73
  alias w= weight=
45
74
 
75
+ # @return [Boolean]
46
76
  def ==(other)
47
77
  if other.is_a?(Numeric)
48
78
  @x == other &&
49
- @y == other &&
50
- @z == other &&
51
- @weight == other
52
- else
79
+ @y == other &&
80
+ @z == other &&
81
+ @weight == other
82
+ elsif other.is_a?(Vector)
53
83
  @x == other.x &&
54
- @y == other.y &&
55
- @z == other.z &&
56
- @weight == other.weight
84
+ @y == other.y &&
85
+ @z == other.z &&
86
+ @weight == other.weight
87
+ else
88
+ other == self
57
89
  end
58
90
  end
59
91
 
60
- # Performs math operation, excluding @weight
92
+ # Create a new vector using {x} and {y} values
93
+ # @return [CyberarmEngine::Vector]
94
+ def xy
95
+ Vector.new(@x, @y)
96
+ end
97
+
98
+ # Performs math operation, excluding {weight}
61
99
  private def operator(function, other)
62
100
  if other.is_a?(Numeric)
63
101
  Vector.new(
@@ -74,22 +112,37 @@ module CyberarmEngine
74
112
  end
75
113
  end
76
114
 
77
- # Adds Vector and Numberic or Vector and Vector, excluding @weight
115
+ # Adds Vector and Numeric or Vector and Vector, excluding {weight}
116
+ # @return [CyberarmEngine::Vector]
78
117
  def +(other)
79
118
  operator("+", other)
80
119
  end
81
120
 
82
- # Subtracts Vector and Numberic or Vector and Vector, excluding @weight
121
+ # Subtracts Vector and Numeric or Vector and Vector, excluding {weight}
122
+ # @return [CyberarmEngine::Vector]
83
123
  def -(other)
84
124
  operator("-", other)
85
125
  end
86
126
 
87
- # Multiplies Vector and Numberic or Vector and Vector, excluding @weight
127
+ # Multiplies Vector and Numeric or Vector and Vector, excluding {weight}
128
+ # @return [CyberarmEngine::Vector]
88
129
  def *(other)
89
130
  operator("*", other)
90
131
  end
91
132
 
92
- # Divides Vector and Numberic or Vector and Vector, excluding @weight
133
+ def multiply_transform(transform)
134
+ e = transform.elements
135
+
136
+ x = @x * e[0] + @y * e[1] + @z * e[2] + 1 * e[3]
137
+ y = @x * e[4] + @y * e[5] + @z * e[6] + 1 * e[7]
138
+ z = @x * e[8] + @y * e[9] + @z * e[10] + 1 * e[11]
139
+ w = @x * e[12] + @y * e[13] + @z * e[14] + 1 * e[15]
140
+
141
+ Vector.new(x / 1, y / 1, z / 1, w / 1)
142
+ end
143
+
144
+ # Divides Vector and Numeric or Vector and Vector, excluding {weight}
145
+ # @return [CyberarmEngine::Vector]
93
146
  def /(other)
94
147
  # Duplicated to protect from DivideByZero
95
148
  if other.is_a?(Numeric)
@@ -107,21 +160,25 @@ module CyberarmEngine
107
160
  end
108
161
  end
109
162
 
163
+ # dot product of {Vector}
164
+ # @return [Integer|Float]
110
165
  def dot(other)
111
166
  product = 0
112
167
 
113
- a = self.to_a
168
+ a = to_a
114
169
  b = other.to_a
115
170
 
116
171
  3.times do |i|
117
- product = product + (a[i] * b[i])
172
+ product += (a[i] * b[i])
118
173
  end
119
174
 
120
- return product
175
+ product
121
176
  end
122
177
 
178
+ # cross product of {Vector}
179
+ # @return [CyberarmEngine::Vector]
123
180
  def cross(other)
124
- a = self.to_a
181
+ a = to_a
125
182
  b = other.to_a
126
183
 
127
184
  Vector.new(
@@ -132,24 +189,39 @@ module CyberarmEngine
132
189
  end
133
190
 
134
191
  # returns degrees
192
+ # @return [Float]
135
193
  def angle(other)
136
- Math.acos( self.normalized.dot(other.normalized) ) * 180 / Math::PI
194
+ Math.acos(normalized.dot(other.normalized)) * 180 / Math::PI
137
195
  end
138
196
 
139
197
  # returns magnitude of Vector, ignoring #weight
198
+ # @return [Float]
140
199
  def magnitude
141
200
  Math.sqrt((@x * @x) + (@y * @y) + (@z * @z))
142
201
  end
143
202
 
203
+ ##
204
+ # returns normalized {Vector}
205
+ #
206
+ # @example
207
+ # CyberarmEngine::Vector.new(50, 21.2, 45).normalized
208
+ # # => <CyberarmEngine::Vector:0x001 @x=0.7089... @y=0.3005... @z=0.6380... @weight=0>
209
+ #
210
+ # @return [CyberarmEngine::Vector]
144
211
  def normalized
145
212
  mag = magnitude
146
213
  self / Vector.new(mag, mag, mag)
147
214
  end
148
215
 
216
+ # returns a direction {Vector}
217
+ #
218
+ # z is pitch
219
+ #
220
+ # y is yaw
221
+ #
222
+ # x is roll
223
+ # @return [CyberarmEngine::Vector]
149
224
  def direction
150
- # z is pitch
151
- # y is yaw
152
- # x is roll
153
225
  _x = -Math.sin(@y.degrees_to_radians) * Math.cos(@z.degrees_to_radians)
154
226
  _y = Math.sin(@z.degrees_to_radians)
155
227
  _z = Math.cos(@y.degrees_to_radians) * Math.cos(@z.degrees_to_radians)
@@ -157,43 +229,65 @@ module CyberarmEngine
157
229
  Vector.new(_x, _y, _z)
158
230
  end
159
231
 
232
+ # returns an inverse {Vector}
233
+ # @return [CyberarmEngine::Vector]
160
234
  def inverse
161
235
  Vector.new(1.0 / @x, 1.0 / @y, 1.0 / @z)
162
236
  end
163
237
 
238
+ # Adds up values of {x}, {y}, and {z}
239
+ # @return [Integer|Float]
164
240
  def sum
165
241
  @x + @y + @z
166
242
  end
167
243
 
244
+ ##
245
+ # Linear interpolation: smoothly transition between two {Vector}
246
+ #
247
+ # CyberarmEngine::Vector.new(100, 100, 100).lerp( CyberarmEngine::Vector.new(0, 0, 0), 0.75 )
248
+ # # => <CyberarmEngine::Vector:0x0001 @x=75.0, @y=75.0, @z=75.0, @weight=0>
249
+ #
250
+ # @param other [CyberarmEngine::Vector | Integer | Float] value to subtract from
251
+ # @param factor [Float] how complete transition to _other_ is, in range [0.0..1.0]
252
+ # @return [CyberarmEngine::Vector]
168
253
  def lerp(other, factor)
169
254
  (self - other) * factor.clamp(0.0, 1.0)
170
255
  end
171
256
 
172
257
  # 2D distance using X and Y
258
+ # @return [Float]
173
259
  def distance(other)
174
- Math.sqrt((@x-other.x)**2 + (@y-other.y)**2)
260
+ Math.sqrt((@x - other.x)**2 + (@y - other.y)**2)
175
261
  end
176
262
 
177
263
  # 2D distance using X and Z
264
+ # @return [Float]
178
265
  def gl_distance2d(other)
179
- Math.sqrt((@x-other.x)**2 + (@z-other.z)**2)
266
+ Math.sqrt((@x - other.x)**2 + (@z - other.z)**2)
180
267
  end
181
268
 
182
269
  # 3D distance using X, Y, and Z
270
+ # @return [Float]
183
271
  def distance3d(other)
184
- Math.sqrt((@x-other.x)**2 + (@y-other.y)**2 + (@z-other.z)**2)
272
+ Math.sqrt((@x - other.x)**2 + (@y - other.y)**2 + (@z - other.z)**2)
185
273
  end
186
274
 
275
+ # Converts {Vector} to Array
276
+ # @return [Array]
187
277
  def to_a
188
278
  [@x, @y, @z, @weight]
189
279
  end
190
280
 
281
+ # Converts {Vector} to String
282
+ # @return [String]
191
283
  def to_s
192
284
  "X: #{@x}, Y: #{@y}, Z: #{@z}, Weight: #{@weight}"
193
285
  end
194
286
 
287
+ # Converts {Vector} to Hash
288
+ # @return [Hash]
195
289
  def to_h
196
- {x: @x, y: @y, z: @z, weight: @weight}
290
+ { x: @x, y: @y, z: @z, weight: @weight }
197
291
  end
198
292
  end
199
- end
293
+ end