cyberarm_engine 0.1.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 (39) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile +6 -0
  5. data/LICENSE.txt +21 -0
  6. data/README.md +43 -0
  7. data/Rakefile +10 -0
  8. data/bin/console +14 -0
  9. data/bin/setup +8 -0
  10. data/cyberarm_engine.gemspec +36 -0
  11. data/lib/cyberarm_engine.rb +36 -0
  12. data/lib/cyberarm_engine/background.rb +166 -0
  13. data/lib/cyberarm_engine/common.rb +85 -0
  14. data/lib/cyberarm_engine/engine.rb +95 -0
  15. data/lib/cyberarm_engine/game_object.rb +256 -0
  16. data/lib/cyberarm_engine/game_state.rb +90 -0
  17. data/lib/cyberarm_engine/lib/bounding_box.rb +124 -0
  18. data/lib/cyberarm_engine/lib/vector.rb +97 -0
  19. data/lib/cyberarm_engine/objects/multi_line_text.rb +67 -0
  20. data/lib/cyberarm_engine/objects/text.rb +96 -0
  21. data/lib/cyberarm_engine/objects/timer.rb +23 -0
  22. data/lib/cyberarm_engine/ui/border_canvas.rb +101 -0
  23. data/lib/cyberarm_engine/ui/button.rb +53 -0
  24. data/lib/cyberarm_engine/ui/check_box.rb +52 -0
  25. data/lib/cyberarm_engine/ui/container.rb +154 -0
  26. data/lib/cyberarm_engine/ui/dsl.rb +82 -0
  27. data/lib/cyberarm_engine/ui/edit_line.rb +88 -0
  28. data/lib/cyberarm_engine/ui/element.rb +197 -0
  29. data/lib/cyberarm_engine/ui/event.rb +46 -0
  30. data/lib/cyberarm_engine/ui/flow.rb +15 -0
  31. data/lib/cyberarm_engine/ui/gui_state.rb +119 -0
  32. data/lib/cyberarm_engine/ui/image.rb +42 -0
  33. data/lib/cyberarm_engine/ui/label.rb +34 -0
  34. data/lib/cyberarm_engine/ui/stack.rb +11 -0
  35. data/lib/cyberarm_engine/ui/style.rb +15 -0
  36. data/lib/cyberarm_engine/ui/theme.rb +91 -0
  37. data/lib/cyberarm_engine/ui/toggle_button.rb +49 -0
  38. data/lib/cyberarm_engine/version.rb +4 -0
  39. metadata +137 -0
@@ -0,0 +1,154 @@
1
+ module CyberarmEngine
2
+ class Container < Element
3
+ include Common
4
+
5
+ attr_accessor :stroke_color, :fill_color
6
+ attr_reader :children
7
+ attr_reader :scroll_x, :scroll_y
8
+
9
+ def initialize(options = {}, block = nil)
10
+ super
11
+
12
+ @scroll_x, @scroll_y = 0, 0
13
+ @scroll_speed = 10
14
+
15
+ @text_color = options[:color]
16
+
17
+ @children = []
18
+
19
+ @theme = {}
20
+ end
21
+
22
+ def build
23
+ @theme.merge(@parent.theme) if @parent
24
+ @block.call(self) if @block
25
+
26
+ recalculate
27
+ end
28
+
29
+ def add(element)
30
+ @children << element
31
+
32
+ recalculate
33
+ end
34
+
35
+ def render
36
+ @children.each(&:draw)
37
+ end
38
+
39
+ def update
40
+ @children.each(&:update)
41
+ end
42
+
43
+ def theme
44
+ @theme
45
+ end
46
+
47
+ def color(color)
48
+ @theme[:color] = color
49
+ end
50
+
51
+ def hit_element?(x, y)
52
+ @children.reverse_each do |child|
53
+ case child
54
+ when Container
55
+ if element = child.hit_element?(x, y)
56
+ return element
57
+ end
58
+ else
59
+ return child if child.hit?(x, y)
60
+ end
61
+ end
62
+
63
+ self if hit?(x, y)
64
+ end
65
+
66
+ def recalculate
67
+ @current_position = Vector.new(@margin_left, @margin_top)
68
+
69
+ layout
70
+
71
+ @width = @max_width ? @max_width : (@children.map {|c| c.x + c.width + c.margin_right }.max || 0).round
72
+ @height = @max_height ? @max_height : (@children.map {|c| c.y + c.height + c.margin_bottom}.max || 0).round
73
+
74
+ # Move child to parent after positioning
75
+ @children.each do |child|
76
+ child.x += @x
77
+ child.y += @y
78
+
79
+ # Fix child being displaced
80
+ child.recalculate
81
+ end
82
+
83
+ update_background
84
+ end
85
+
86
+ def layout
87
+ raise "Not overridden"
88
+ end
89
+
90
+ def max_width
91
+ @max_width ? @max_width : window.width - (@parent ? @parent.margin_right + @margin_right : @margin_right)
92
+ end
93
+
94
+ def fits_on_line?(element) # Flow
95
+ @current_position.x + element.outer_width <= max_width &&
96
+ @current_position.x + element.outer_width <= window.width
97
+ end
98
+
99
+ def position_on_current_line(element) # Flow
100
+ element.x = element.margin_left + @current_position.x
101
+ element.y = element.margin_top + @current_position.y
102
+
103
+ element.recalculate
104
+
105
+ @current_position.x += element.outer_width
106
+ @current_position.x = @margin_left if @current_position.x >= max_width
107
+ end
108
+
109
+ def tallest_neighbor(querier, y_position) # Flow
110
+ response = querier
111
+ @children.each do |child|
112
+ response = child if child.outer_height > response.outer_height
113
+ break if child == querier
114
+ end
115
+
116
+ return response
117
+ end
118
+
119
+ def position_on_next_line(child) # Flow
120
+ @current_position.x = @margin_left
121
+ @current_position.y += tallest_neighbor(child, @current_position.y).outer_height
122
+
123
+ child.x = child.margin_left + @current_position.x
124
+ child.y = child.margin_top + @current_position.y
125
+
126
+ child.recalculate
127
+
128
+ @current_position.x += child.outer_width
129
+ end
130
+
131
+ def move_to_next_line(element) # Stack
132
+ element.x = element.margin_left + @current_position.x
133
+ element.y = element.margin_top + @current_position.y
134
+
135
+ element.recalculate
136
+
137
+ @current_position.y += element.outer_height
138
+ end
139
+
140
+ # def mouse_wheel_up(sender, x, y)
141
+ # @children.each {|c| c.y -= @scroll_speed}
142
+ # @children.each {|c| c.recalculate}
143
+ # end
144
+
145
+ # def mouse_wheel_down(sender, x, y)
146
+ # @children.each {|c| c.y += @scroll_speed}
147
+ # @children.each {|c| c.recalculate}
148
+ # end
149
+
150
+ def value
151
+ @children.map {|c| c.class}.join(", ")
152
+ end
153
+ end
154
+ end
@@ -0,0 +1,82 @@
1
+ module CyberarmEngine
2
+ module DSL
3
+ def flow(options = {}, &block)
4
+ options[:parent] = @containers.last
5
+ _container = Flow.new(options, block)
6
+ @containers << _container
7
+ _container.build
8
+ options[:parent].add(_container)
9
+ @containers.pop
10
+
11
+ return _container
12
+ end
13
+
14
+ def stack(options = {}, &block)
15
+ options[:parent] = @containers.last
16
+ _container = Stack.new(options, block)
17
+ @containers << _container
18
+ _container.build
19
+ options[:parent].add(_container)
20
+ @containers.pop
21
+
22
+ return _container
23
+ end
24
+
25
+ def label(text, options = {}, &block)
26
+ options[:parent] = @containers.last
27
+ _element = Label.new(text, options, block)
28
+ @containers.last.add(_element)
29
+
30
+ return _element
31
+ end
32
+
33
+ def button(text, options = {}, &block)
34
+ options[:parent] = @containers.last
35
+ _element = Button.new(text, options, block) { if block.is_a?(Proc); block.call; end }
36
+ @containers.last.add(_element)
37
+
38
+ return _element
39
+ end
40
+
41
+ def edit_line(text, options = {}, &block)
42
+ options[:parent] = @containers.last
43
+ _element = EditLine.new(text, options, block)
44
+ @containers.last.add(_element)
45
+
46
+ return _element
47
+ end
48
+
49
+ def toggle_button(options = {}, &block)
50
+ options[:parent] = @containers.last
51
+ _element = ToggleButton.new(options, block)
52
+ @containers.last.add(_element)
53
+
54
+ return _element
55
+ end
56
+
57
+ def check_box(text, options = {}, &block)
58
+ options[:parent] = @containers.last
59
+ _element = CheckBox.new(text, options, block)
60
+ @containers.last.add(_element)
61
+
62
+ return _element
63
+ end
64
+
65
+ def image(path, options = {}, &block)
66
+ options[:parent] = @containers.last
67
+ _element = Image.new(path, options, block)
68
+ @containers.last.add(_element)
69
+
70
+ return _element
71
+ end
72
+
73
+ def background(color = Gosu::Color::NONE)
74
+ @containers.last.background = color
75
+ end
76
+
77
+ # Foreground color, e.g. Text
78
+ def color(color)
79
+ @containers.last.color(color)
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,88 @@
1
+ module CyberarmEngine
2
+ class EditLine < Button
3
+ def initialize(text, options = {}, block = nil)
4
+ super(text, options, block)
5
+
6
+ @type = default(:type)
7
+
8
+
9
+ @caret_width = default(:caret_width)
10
+ @caret_height= @text.height
11
+ @caret_color = default(:caret_color)
12
+ @caret_interval = default(:caret_interval)
13
+ @caret_last_interval = Gosu.milliseconds
14
+ @show_caret = true
15
+
16
+ @text_input = Gosu::TextInput.new
17
+ @text_input.text = text
18
+
19
+ return self
20
+ end
21
+
22
+ def render
23
+ Gosu.clip_to(@text.x, @text.y, @width, @text.height) do
24
+ draw_text
25
+ Gosu.draw_rect(caret_position, @text.y, @caret_width, @caret_height, @caret_color, @z + 40) if @focus && @show_caret
26
+ end
27
+ end
28
+
29
+ def update
30
+ if @type == :password
31
+ @text.text = default(:password_character) * @text_input.text.length
32
+ else
33
+ @text.text = @text_input.text
34
+ end
35
+
36
+ if Gosu.milliseconds >= @caret_last_interval + @caret_interval
37
+ @caret_last_interval = Gosu.milliseconds
38
+
39
+ @show_caret = !@show_caret
40
+ end
41
+ end
42
+
43
+ def left_mouse_button(sender, x, y)
44
+ super
45
+ window.text_input = @text_input
46
+ end
47
+
48
+ def enter(sender)
49
+ if @focus
50
+ @background_canvas.background = default(:active, :background)
51
+ @text.color = default(:active, :color)
52
+ else
53
+ @background_canvas.background = default(:hover, :background)
54
+ @text.color = default(:hover, :color)
55
+ end
56
+ end
57
+
58
+ def leave(sender)
59
+ end
60
+
61
+ def blur(sender)
62
+ @focus = false
63
+ @background_canvas.background = default(:background)
64
+ @text.color = default(:color)
65
+ window.text_input = nil
66
+ end
67
+
68
+ # TODO: Fix caret rendering in wrong position unless caret_pos is at end of text
69
+ def caret_position
70
+ if @type == :password
71
+ @text.x + @text.textobject.text_width(default(:password_character) * @text_input.text[0..@text_input.caret_pos-1].length)
72
+ else
73
+ @text.x + @text.textobject.text_width(@text_input.text[0..@text_input.caret_pos-1])
74
+ end
75
+ end
76
+
77
+ def recalculate
78
+ super
79
+
80
+ @width = default(:width)
81
+ update_background
82
+ end
83
+
84
+ def value
85
+ @text_input.text
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,197 @@
1
+ module CyberarmEngine
2
+ class Element
3
+ include Theme
4
+ include Event
5
+ include Common
6
+
7
+ attr_accessor :x, :y, :z, :enabled
8
+ attr_reader :width, :height, :parent, :options, :event_handler, :background_canvas, :border_canvas
9
+
10
+ attr_reader :border_thickness, :border_thickness_left, :border_thickness_right, :border_thickness_top, :border_thickness_bottom
11
+ attr_reader :border_color, :border_color_left, :border_color_right, :border_color_top, :border_color_bottom
12
+
13
+ attr_reader :padding, :padding_left, :padding_right, :padding_top, :padding_bottom
14
+ attr_reader :margin, :margin_left, :margin_right, :margin_top, :margin_bottom
15
+
16
+ def initialize(options = {}, block = nil)
17
+ @parent = options[:parent] # parent Container (i.e. flow/stack)
18
+ options = theme_defaults.merge(options)
19
+ @options = options
20
+ @block = block
21
+
22
+ @style = Style.new(options)
23
+ @focus = false
24
+ @background_canvas = Background.new
25
+ @border_canvas = BorderCanvas.new(element: self)
26
+
27
+ @x = default(:x)
28
+ @y = default(:y)
29
+ @z = default(:z)
30
+
31
+ @fixed_x = @x if @x != 0
32
+ @fixed_y = @y if @y != 0
33
+
34
+ @width = default(:width) || $window.width
35
+ @height = default(:height) || $window.height
36
+
37
+ set_border_thickness(default(:border_thickness))
38
+
39
+ set_padding(default(:padding))
40
+
41
+ set_margin(default(:margin))
42
+
43
+ set_background(default(:background))
44
+ set_border_color(default(:border_color))
45
+
46
+ raise "#{self.class} 'x' must be a number" unless @x.is_a?(Numeric)
47
+ raise "#{self.class} 'y' must be a number" unless @y.is_a?(Numeric)
48
+ raise "#{self.class} 'z' must be a number" unless @z.is_a?(Numeric)
49
+ raise "#{self.class} 'width' must be a number" unless @width.is_a?(Numeric) || @width.nil?
50
+ raise "#{self.class} 'height' must be a number" unless @height.is_a?(Numeric) || @height.nil?
51
+ raise "#{self.class} 'options' must be a Hash" unless @options.is_a?(Hash)
52
+
53
+ # raise "#{self.class} 'padding' must be a number" unless @padding.is_a?(Numeric)
54
+
55
+ @enabled = true
56
+
57
+ default_events
58
+ end
59
+
60
+ def set_background(background)
61
+ @background = background
62
+ @background_canvas.background = background
63
+ end
64
+
65
+ def set_border_thickness(border_thickness)
66
+ @border_thickness = border_thickness
67
+
68
+ @border_thickness_left = default(:border_thickness_left) || @border_thickness
69
+ @border_thickness_right = default(:border_thickness_right) || @border_thickness
70
+ @border_thickness_top = default(:border_thickness_top) || @border_thickness
71
+ @border_thickness_bottom = default(:border_thickness_bottom) || @border_thickness
72
+ end
73
+
74
+ def set_border_color(color)
75
+ @border_color = color
76
+
77
+ @border_color_left = default(:border_color_left) || @border_color
78
+ @border_color_right = default(:border_color_right) || @border_color
79
+ @border_color_top = default(:border_color_top) || @border_color
80
+ @border_color_bottom = default(:border_color_bottom) || @border_color
81
+
82
+ @border_canvas.color = color
83
+ end
84
+
85
+ def set_padding(padding)
86
+ @padding = padding
87
+
88
+ @padding_left = default(:padding_left) || @padding
89
+ @padding_right = default(:padding_right) || @padding
90
+ @padding_top = default(:padding_top) || @padding
91
+ @padding_bottom = default(:padding_bottom) || @padding
92
+ end
93
+
94
+ def set_margin(margin)
95
+ @margin = margin
96
+
97
+ @margin_left = default(:margin_left) || @margin
98
+ @margin_right = default(:margin_right) || @margin
99
+ @margin_top = default(:margin_top) || @margin
100
+ @margin_bottom = default(:margin_bottom) || @margin
101
+ end
102
+
103
+ def default_events
104
+ [:left, :middle, :right].each do |button|
105
+ event(:"#{button}_mouse_button")
106
+ event(:"released_#{button}_mouse_button")
107
+ event(:"clicked_#{button}_mouse_button")
108
+ event(:"holding_#{button}_mouse_button")
109
+ end
110
+
111
+ event(:mouse_wheel_up)
112
+ event(:mouse_wheel_down)
113
+
114
+ event(:enter)
115
+ event(:hover)
116
+ event(:leave)
117
+
118
+ event(:blur)
119
+ end
120
+
121
+ def enabled?
122
+ @enabled
123
+ end
124
+
125
+ def draw
126
+ @background_canvas.draw
127
+ @border_canvas.draw
128
+ render
129
+ end
130
+
131
+ def update
132
+ end
133
+
134
+ def button_down(id)
135
+ end
136
+
137
+ def button_up(id)
138
+ end
139
+
140
+ def render
141
+ end
142
+
143
+ def hit?(x, y)
144
+ x.between?(@x, @x + width) &&
145
+ y.between?(@y, @y + height)
146
+ end
147
+
148
+ def width
149
+ (@border_thickness_left + @padding_left) + @width + (@padding_right + @border_thickness_right)
150
+ end
151
+
152
+ def outer_width
153
+ @margin_left + width + @margin_right
154
+ end
155
+
156
+ def height
157
+ (@border_thickness_top + @padding_top) + @height + (@padding_bottom + @border_thickness_bottom)
158
+ end
159
+
160
+ def outer_height
161
+ @margin_top + height + @margin_bottom
162
+ end
163
+
164
+ def style(hash)
165
+ if hash
166
+ @style.set(hash)
167
+ else
168
+ @style.hash
169
+ end
170
+ end
171
+
172
+ def background=(_background)
173
+ @background_canvas.background=(_background)
174
+ update_background
175
+ end
176
+
177
+ def update_background
178
+ @background_canvas.x = @x
179
+ @background_canvas.y = @y
180
+ @background_canvas.z = @z
181
+ @background_canvas.width = width
182
+ @background_canvas.height = height
183
+
184
+ @background_canvas.update
185
+
186
+ @border_canvas.update
187
+ end
188
+
189
+ def recalculate
190
+ raise "#{self.class}#recalculate was not overridden!"
191
+ end
192
+
193
+ def value
194
+ raise "#{self.class}#value was not overridden!"
195
+ end
196
+ end
197
+ end