cyberarm_engine 0.17.1 → 0.18.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fa05052d75e7e9660d600f07d014eba3a118584eaea601540efe3e8d0681494a
4
- data.tar.gz: 6695ea5a245aa63518ffd8070859de10a70e04e25f7da154f9186540aa1e8d41
3
+ metadata.gz: f24458d4ec27a35ff7877afa6e4acdc06d153b8cd161c53063a26282dc14802b
4
+ data.tar.gz: baf54b9e08f2f78a75e6db02dfdc6e7ad749f73afb9dfad6260f666f75447fe8
5
5
  SHA512:
6
- metadata.gz: cdeb1da5ae89e67cf2ee02cea28313da1c657509c0b41fd517f4dd112aafd28d41f8987b5c8a47a95d8c92cd20d132461f87c1764dc74e7c54d560749c38f205
7
- data.tar.gz: 4a26c1468e381323bfd2daa503c686f98b30b2918c0d5795aea43bf9209388a2fa13e9f6d9786e454692a2834f676528645647a1f723c417ed2dc7cf1a1f59fb
6
+ metadata.gz: 6296128b5384912865a96a0e80e176cdc92d853838874507c7eebe5ad86089062ea14fd5a12f0e848fa176047064f4ecf2f68aa1ddddfcc35830e01e688fa164
7
+ data.tar.gz: '07386961b8796e2e4d73155c8e44c6c2df6906888609f8424a3cb94f947328356851dc6e72dc2cf26ba3952415c6696cca3c8524963359c6f2b5463c81d5cc18'
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # CyberarmEngine
1
+ ![CyberarmEngine](https://raw.githubusercontent.com/cyberarm/cyberarm_engine/master/assets/textures/logo.png)
2
2
 
3
3
  Yet Another Game Engine On Top Of Gosu
4
4
 
@@ -32,6 +32,8 @@ require "cyberarm_engine"
32
32
 
33
33
  class Hello < CyberarmEngine::GuiState
34
34
  def setup
35
+ background Gosu::Color::GRAY
36
+
35
37
  stack do
36
38
  label "Hello World!"
37
39
 
@@ -43,15 +45,14 @@ class Hello < CyberarmEngine::GuiState
43
45
  end
44
46
 
45
47
  class Window < CyberarmEngine::Window
46
- def initialize
47
- super
48
+ def setup
48
49
  self.show_cursor = true
49
50
 
50
51
  push_state(Hello)
51
52
  end
52
53
  end
53
54
 
54
- Window.new.show
55
+ Window.new(width: 800, height: 600, fullscreen: false, resizable: true).show
55
56
  ```
56
57
 
57
58
  ## Development
Binary file
@@ -1,9 +1,8 @@
1
1
  CYBERARM_ENGINE_ROOT_PATH = File.expand_path("..", __dir__)
2
2
 
3
- begin
4
- require File.expand_path("../../ffi-gosu/lib/gosu", File.dirname(__FILE__))
5
- rescue LoadError => e
6
- pp e
3
+ if ARGV.join.include?("--ffi-gosu")
4
+ require File.expand_path("../../ffi-gosu/lib/gosu", __dir__)
5
+ else
7
6
  require "gosu"
8
7
  end
9
8
  require "json"
@@ -62,3 +61,5 @@ require_relative "cyberarm_engine/model/model_object"
62
61
  require_relative "cyberarm_engine/model/parser"
63
62
  require_relative "cyberarm_engine/model/parsers/wavefront_parser"
64
63
  require_relative "cyberarm_engine/model/parsers/collada_parser" if defined?(Nokogiri)
64
+
65
+ require_relative "cyberarm_engine/builtin/intro_state"
@@ -1,11 +1,11 @@
1
1
  module CyberarmEngine
2
2
  class Animator
3
- DEFAULT_TWEEN = :linear
4
- def initialize(start_time:, duration:, from:, to:, &block)
3
+ def initialize(start_time:, duration:, from:, to:, tween: :linear, &block)
5
4
  @start_time = start_time
6
5
  @duration = duration
7
6
  @from = from.dup
8
7
  @to = to.dup
8
+ @tween = tween
9
9
  @block = block
10
10
  end
11
11
 
@@ -14,18 +14,18 @@ module CyberarmEngine
14
14
  end
15
15
 
16
16
  def progress
17
- (@start_time.to_f + (Gosu.milliseconds - @start_time)) / (@start_time + @duration.to_f)
17
+ ((Gosu.milliseconds - @start_time) / @duration.to_f).clamp(0.0, 1.0)
18
18
  end
19
19
 
20
20
  def complete?
21
21
  progress >= 1.0
22
22
  end
23
23
 
24
- def transition(from, to, tween = DEFAULT_TWEEN)
24
+ def transition(from = @from, to = @to, tween = @tween)
25
25
  from + (to - from) * send("tween_#{tween}", progress)
26
26
  end
27
27
 
28
- def color_transition(from, to, _tween = DEFAULT_TWEEN)
28
+ def color_transition(from = @from, to = @to, _tween = @tween)
29
29
  r = transition(from.red, to.red)
30
30
  g = transition(from.green, to.green)
31
31
  b = transition(from.blue, to.blue)
@@ -34,7 +34,7 @@ module CyberarmEngine
34
34
  Gosu::Color.rgba(r, g, b, a)
35
35
  end
36
36
 
37
- def color_hsv_transition(from, to, tween = DEFAULT_TWEEN)
37
+ def color_hsv_transition(from = @from, to = @to, tween = @tween)
38
38
  hue = transition(from.hue, to.hue, tween)
39
39
  saturation = transition(from.saturation, to.saturation, tween)
40
40
  value = transition(from.value, to.value, tween)
@@ -49,8 +49,8 @@ module CyberarmEngine
49
49
  t
50
50
  end
51
51
 
52
- def tween_sine(t)
53
- Math.sin(t) * t
52
+ def tween_ease_in_out(t)
53
+ (-0.5 * (Math.cos(Math::PI * t) - 1))
54
54
  end
55
55
  end
56
56
  end
@@ -0,0 +1,128 @@
1
+ module CyberarmEngine
2
+ class IntroState < CyberarmEngine::GameState
3
+ def setup
4
+ @display_width = 800
5
+ @display_height = 600
6
+
7
+ @title_size = 56
8
+ @caption_size = 24
9
+
10
+ @title = CyberarmEngine::Text.new("", size: @title_size, shadow_color: 0xaa_222222)
11
+ @caption = CyberarmEngine::Text.new("", size: @caption_size, shadow_color: 0xaa_222222)
12
+
13
+ @spacer_width = 256
14
+ @spacer_height = 6
15
+ @padding = 6
16
+
17
+ @cyberarm_engine_logo = get_image "#{CYBERARM_ENGINE_ROOT_PATH}/assets/textures/logo.png"
18
+
19
+ @gosu_logo = generate_proxy("Gosu", "Game Library", 0xff_111111)
20
+ @ruby_logo = generate_proxy("Ruby", "Programming Language", 0xff_880000)
21
+ @opengl_logo = generate_proxy("OpenGL", "Graphics API", 0xff_5586a4) if defined?(OpenGL)
22
+
23
+ base_time = Gosu.milliseconds
24
+
25
+ @animators = [
26
+ Animator.new(start_time: base_time += 1000, duration: 100, from: 0.0, to: 1.0, tween: :ease_in_out),
27
+ Animator.new(start_time: base_time += -500, duration: 1_000, from: 0.0, to: 1.0, tween: :ease_in_out),
28
+ Animator.new(start_time: base_time += 500, duration: 1_000, from: 0.0, to: 1.0, tween: :ease_in_out),
29
+ Animator.new(start_time: base_time += 500, duration: 1_000, from: 0.0, to: 1.0, tween: :ease_in_out),
30
+ Animator.new(start_time: base_time + 500, duration: 1_000, from: 0.0, to: 1.0, tween: :ease_in_out),
31
+
32
+ Animator.new(start_time: Gosu.milliseconds + 250, duration: 500, from: 0.0, to: 1.0, tween: :ease_in_out) # CyberarmEngine LOGO
33
+ ]
34
+
35
+ @born_time = Gosu.milliseconds
36
+ @continue_after = 5_000
37
+ end
38
+
39
+ def draw
40
+ Gosu.draw_rect(0, 0, window.width, window.height, 0xff_222222)
41
+
42
+ scale = (@display_width - @padding * 2).to_f / @cyberarm_engine_logo.width * @animators.last.transition
43
+
44
+ @cyberarm_engine_logo.draw_rot(
45
+ window.width / 2,
46
+ (window.height) / 2 - @cyberarm_engine_logo.height / 2 - @padding * 2,
47
+ 2,
48
+ 0,
49
+ 0.5,
50
+ 0.5,
51
+ scale,
52
+ scale
53
+ )
54
+
55
+ Gosu.draw_rect(
56
+ window.width / 2 - (@display_width / 2 + @padding),
57
+ window.height / 2 - @spacer_height / 2,
58
+ @display_width + @padding,
59
+ @spacer_height * @animators[0].transition,
60
+ Gosu::Color::WHITE
61
+ )
62
+
63
+ @title.x = window.width / 2 - @title.width / 2
64
+ @title.y = (window.height / 2 + (@spacer_height / 2) + @padding) * @animators[1].transition
65
+ @title.text = "Powered By"
66
+
67
+ Gosu.clip_to(0, window.height / 2 + (@spacer_height / 2), window.width, @title.height) do
68
+ @title.draw
69
+ end
70
+
71
+ y = @title.y + @title.height * 2
72
+
73
+ Gosu.clip_to(0, y, window.width, @gosu_logo.height) do
74
+ Gosu.translate(@opengl_logo.nil? ? @ruby_logo.width / 2 : 0, 0) do
75
+ @gosu_logo.draw(
76
+ window.width.to_f / 2 - @ruby_logo.width / 2 - (@ruby_logo.width - @padding),
77
+ y * @animators[2].transition,
78
+ 2
79
+ )
80
+ @ruby_logo.draw(
81
+ window.width.to_f / 2 - @ruby_logo.width / 2,
82
+ y * @animators[3].transition,
83
+ 2
84
+ )
85
+ @opengl_logo&.draw(
86
+ window.width.to_f / 2 - @ruby_logo.width / 2 + (@ruby_logo.width - @padding),
87
+ y * @animators[4].transition,
88
+ 2
89
+ )
90
+ end
91
+ end
92
+ end
93
+
94
+ def update
95
+ @animators.each(&:update)
96
+
97
+ return unless Gosu.milliseconds - @born_time >= @continue_after
98
+
99
+ pop_state
100
+ push_state(@options[:forward], @options[:forward_options] || {}) if @options[:forward]
101
+ end
102
+
103
+ def button_down(_id)
104
+ @continue_after = 0
105
+ end
106
+
107
+ def generate_proxy(title, caption, color_hint)
108
+ @title.text = title
109
+ @caption.text = caption
110
+
111
+ width = @spacer_width + 2 * @padding
112
+ height = @title_size + @caption_size + @spacer_height + 2 * @padding + @spacer_height
113
+
114
+ Gosu.record(width.ceil, height.ceil) do
115
+ @title.x = (width - @padding * 2) / 2 - @title.width / 2
116
+ @title.y = @padding
117
+ @title.draw
118
+
119
+ Gosu.draw_rect(0, @padding + @title_size + @padding, @spacer_width, @spacer_height, Gosu::Color::WHITE)
120
+ Gosu.draw_rect(1, @padding + @title_size + @padding + 1, @spacer_width - 2, @spacer_height - 2, color_hint)
121
+
122
+ @caption.x = (width - @padding * 2) / 2 - @caption.width / 2
123
+ @caption.y = @padding + @title_size + @padding + @spacer_height + @padding
124
+ @caption.draw
125
+ end
126
+ end
127
+ end
128
+ end
@@ -16,6 +16,10 @@ module CyberarmEngine
16
16
  window.pop_state
17
17
  end
18
18
 
19
+ def shift_state
20
+ window.shift_state
21
+ end
22
+
19
23
  def show_cursor
20
24
  window.show_cursor
21
25
  end
@@ -70,6 +74,7 @@ module CyberarmEngine
70
74
  else
71
75
  klass.new(path)
72
76
  end
77
+
73
78
  hash[path] = instance
74
79
  asset = instance
75
80
  end
@@ -17,6 +17,11 @@ module CyberarmEngine
17
17
  def setup
18
18
  end
19
19
 
20
+ # Called immediately after setup returns.
21
+ # GuiState uses this to set current_theme for ToolTip
22
+ def post_setup
23
+ end
24
+
20
25
  def draw
21
26
  @game_objects.each(&:draw)
22
27
  end
@@ -54,7 +54,7 @@ module CyberarmEngine
54
54
  texture_id = tex_names_buf.unpack1("L2")
55
55
 
56
56
  glBindTexture(GL_TEXTURE_2D, texture_id)
57
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, array_of_pixels)
57
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_SRGB_ALPHA, image.width, image.height, 0, GL_RGBA, GL_UNSIGNED_BYTE, array_of_pixels)
58
58
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
59
59
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
60
60
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST) if @retro
@@ -65,6 +65,15 @@ module CyberarmEngine
65
65
  font
66
66
  end
67
67
 
68
+ def swap_font(size, font_name = @font)
69
+ if @size != size || @font != font_name
70
+ @size = size
71
+ @font = font_name
72
+
73
+ @textobject = check_cache(size, font_name)
74
+ end
75
+ end
76
+
68
77
  def text=(string)
69
78
  @rendered_shadow = nil
70
79
  @text = string
@@ -140,6 +149,7 @@ module CyberarmEngine
140
149
  @textobject.send(method, @text, _x + @shadow_size, _y, @z, @factor_x, @factor_y, white, :add)
141
150
  @textobject.send(method, @text, _x + @shadow_size, _y + @shadow_size, @z, @factor_x, @factor_y, white, :add)
142
151
  end
152
+
143
153
  @rendered_shadow.draw(@x - @shadow_size, @y - @shadow_size, @z, @factor_x, @factor_y, shadow_color)
144
154
  end
145
155
 
@@ -23,7 +23,8 @@ module CyberarmEngine
23
23
  "Tagline",
24
24
  "Caption",
25
25
  "Para",
26
- "Inscription"
26
+ "Inscription",
27
+ "Link"
27
28
  ].each do |const|
28
29
  define_method(:"#{const.downcase}") do |text, options = {}, &block|
29
30
  options[:parent] = element_parent
@@ -97,7 +98,7 @@ module CyberarmEngine
97
98
  end
98
99
 
99
100
  def background(color = Gosu::Color::NONE)
100
- element_parent.style.background = color
101
+ element_parent.style.default[:background] = color
101
102
  end
102
103
 
103
104
  def theme(theme)
@@ -18,6 +18,8 @@ module CyberarmEngine
18
18
  @visible = @options[:visible].nil? ? true : @options[:visible]
19
19
  @tip = @options[:tip] || ""
20
20
 
21
+ @debug_color = @options[:debug_color].nil? ? Gosu::Color::RED : @options[:debug_color]
22
+
21
23
  @style = Style.new(options)
22
24
 
23
25
  @root ||= nil
@@ -36,6 +38,8 @@ module CyberarmEngine
36
38
  @style.background_canvas = Background.new
37
39
  @style.border_canvas = BorderCanvas.new(element: self)
38
40
 
41
+ @style_event = :default
42
+
39
43
  stylize
40
44
 
41
45
  default_events
@@ -45,14 +49,18 @@ module CyberarmEngine
45
49
 
46
50
  def stylize
47
51
  set_static_position
48
- set_border_thickness(@style.border_thickness)
49
52
 
50
- set_padding(@style.padding)
53
+ set_padding
54
+ set_margin
51
55
 
52
- set_margin(@style.margin)
56
+ set_background
57
+
58
+ set_border_thickness
59
+ set_border_color
60
+ end
53
61
 
54
- set_background(@style.background)
55
- set_border_color(@style.border_color)
62
+ def safe_style_fetch(*args)
63
+ @style.hash.dig(@style_event, *args) || @style.hash.dig(:default, *args) || default(*args)
56
64
  end
57
65
 
58
66
  def set_static_position
@@ -60,47 +68,65 @@ module CyberarmEngine
60
68
  @y = @style.y if @style.y != 0
61
69
  end
62
70
 
63
- def set_background(background)
64
- @style.background = background
65
- @style.background_canvas.background = background
71
+ def set_background
72
+ @style.background = safe_style_fetch(:background)
73
+
74
+ @style.background_canvas.background = @style.background
66
75
  end
67
76
 
68
- def set_border_thickness(border_thickness)
69
- @style.border_thickness = border_thickness
77
+ def set_border_thickness
78
+ @style.border_thickness = safe_style_fetch(:border_thickness)
70
79
 
71
- @style.border_thickness_left = default(:border_thickness_left) || @style.border_thickness
72
- @style.border_thickness_right = default(:border_thickness_right) || @style.border_thickness
73
- @style.border_thickness_top = default(:border_thickness_top) || @style.border_thickness
74
- @style.border_thickness_bottom = default(:border_thickness_bottom) || @style.border_thickness
80
+ @style.border_thickness_left = safe_style_fetch(:border_thickness_left) || @style.border_thickness
81
+ @style.border_thickness_right = safe_style_fetch(:border_thickness_right) || @style.border_thickness
82
+ @style.border_thickness_top = safe_style_fetch(:border_thickness_top) || @style.border_thickness
83
+ @style.border_thickness_bottom = safe_style_fetch(:border_thickness_bottom) || @style.border_thickness
75
84
  end
76
85
 
77
- def set_border_color(color)
78
- @style.border_color = color
86
+ def set_border_color
87
+ @style.border_color = safe_style_fetch(:border_color)
79
88
 
80
- @style.border_color_left = default(:border_color_left) || @style.border_color
81
- @style.border_color_right = default(:border_color_right) || @style.border_color
82
- @style.border_color_top = default(:border_color_top) || @style.border_color
83
- @style.border_color_bottom = default(:border_color_bottom) || @style.border_color
89
+ @style.border_color_left = safe_style_fetch(:border_color_left) || @style.border_color
90
+ @style.border_color_right = safe_style_fetch(:border_color_right) || @style.border_color
91
+ @style.border_color_top = safe_style_fetch(:border_color_top) || @style.border_color
92
+ @style.border_color_bottom = safe_style_fetch(:border_color_bottom) || @style.border_color
84
93
 
85
- @style.border_canvas.color = color
94
+ @style.border_canvas.color = [
95
+ @style.border_color_top,
96
+ @style.border_color_right,
97
+ @style.border_color_bottom,
98
+ @style.border_color_left
99
+ ]
86
100
  end
87
101
 
88
- def set_padding(padding)
89
- @style.padding = padding
102
+ def set_padding
103
+ @style.padding = safe_style_fetch(:padding)
90
104
 
91
- @style.padding_left = default(:padding_left) || @style.padding
92
- @style.padding_right = default(:padding_right) || @style.padding
93
- @style.padding_top = default(:padding_top) || @style.padding
94
- @style.padding_bottom = default(:padding_bottom) || @style.padding
105
+ @style.padding_left = safe_style_fetch(:padding_left) || @style.padding
106
+ @style.padding_right = safe_style_fetch(:padding_right) || @style.padding
107
+ @style.padding_top = safe_style_fetch(:padding_top) || @style.padding
108
+ @style.padding_bottom = safe_style_fetch(:padding_bottom) || @style.padding
95
109
  end
96
110
 
97
- def set_margin(margin)
98
- @style.margin = margin
111
+ def set_margin
112
+ @style.margin = safe_style_fetch(:margin)
99
113
 
100
- @style.margin_left = default(:margin_left) || @style.margin
101
- @style.margin_right = default(:margin_right) || @style.margin
102
- @style.margin_top = default(:margin_top) || @style.margin
103
- @style.margin_bottom = default(:margin_bottom) || @style.margin
114
+ @style.margin_left = safe_style_fetch(:margin_left) || @style.margin
115
+ @style.margin_right = safe_style_fetch(:margin_right) || @style.margin
116
+ @style.margin_top = safe_style_fetch(:margin_top) || @style.margin
117
+ @style.margin_bottom = safe_style_fetch(:margin_bottom) || @style.margin
118
+ end
119
+
120
+ def update_styles(event = :default)
121
+ _style = @style.send(event)
122
+ @style_event = event
123
+
124
+ if @text.is_a?(CyberarmEngine::Text)
125
+ @text.color = _style&.dig(:color) || @style.default[:color]
126
+ @text.swap_font(_style&.dig(:text_size) || @style.default[:text_size], _style&.dig(:font) || @style.default[:font])
127
+ end
128
+
129
+ (root&.gui_state || @gui_state).request_recalculate
104
130
  end
105
131
 
106
132
  def default_events
@@ -124,6 +150,68 @@ module CyberarmEngine
124
150
  event(:changed)
125
151
  end
126
152
 
153
+ def enter(_sender)
154
+ @focus = false unless window.button_down?(Gosu::MsLeft)
155
+
156
+ if !@enabled
157
+ update_styles(:disabled)
158
+ elsif @focus
159
+ update_styles(:active)
160
+ else
161
+ update_styles(:hover)
162
+ end
163
+
164
+ :handled
165
+ end
166
+
167
+ def left_mouse_button(_sender, _x, _y)
168
+ @focus = true
169
+
170
+ unless @enabled
171
+ update_styles(:disabled)
172
+ else
173
+ update_styles(:active)
174
+ end
175
+
176
+ window.current_state.focus = self
177
+
178
+ :handled
179
+ end
180
+
181
+ def released_left_mouse_button(sender, _x, _y)
182
+ enter(sender)
183
+
184
+ :handled
185
+ end
186
+
187
+ def clicked_left_mouse_button(_sender, _x, _y)
188
+ @block&.call(self) if @enabled && !self.is_a?(Container)
189
+
190
+ :handled
191
+ end
192
+
193
+ def leave(_sender)
194
+ if @enabled
195
+ update_styles
196
+ else
197
+ update_styles(:disabled)
198
+ end
199
+
200
+ :handled
201
+ end
202
+
203
+ def blur(_sender)
204
+ @focus = false
205
+
206
+ if @enabled
207
+ update_styles
208
+ else
209
+ update_styles(:disabled)
210
+ end
211
+
212
+ :handled
213
+ end
214
+
127
215
  def enabled?
128
216
  @enabled
129
217
  end
@@ -160,6 +248,31 @@ module CyberarmEngine
160
248
  end
161
249
  end
162
250
 
251
+ def debug_draw
252
+ return if defined?(GUI_DEBUG_ONLY_ELEMENT) && self.class == GUI_DEBUG_ONLY_ELEMENT
253
+
254
+ Gosu.draw_line(
255
+ x, y, @debug_color,
256
+ x + outer_width, y, @debug_color,
257
+ Float::INFINITY
258
+ )
259
+ Gosu.draw_line(
260
+ x + outer_width, y, @debug_color,
261
+ x + outer_width, y + outer_height, @debug_color,
262
+ Float::INFINITY
263
+ )
264
+ Gosu.draw_line(
265
+ x + outer_width, y + outer_height, @debug_color,
266
+ x, y + outer_height, @debug_color,
267
+ Float::INFINITY
268
+ )
269
+ Gosu.draw_line(
270
+ x, outer_height, @debug_color,
271
+ x, y, @debug_color,
272
+ Float::INFINITY
273
+ )
274
+ end
275
+
163
276
  def update
164
277
  end
165
278
 
@@ -258,7 +371,7 @@ module CyberarmEngine
258
371
  end
259
372
 
260
373
  def background=(_background)
261
- @style.background_canvas.background = (_background)
374
+ @style.background_canvas.background = _background
262
375
  update_background
263
376
  end
264
377
 
@@ -281,11 +394,9 @@ module CyberarmEngine
281
394
  @root = parent
282
395
 
283
396
  loop do
284
- if @root.parent.nil?
285
- break
286
- else
287
- @root = @root.parent
288
- end
397
+ break unless @root&.parent
398
+
399
+ @root = @root.parent
289
400
  end
290
401
  end
291
402
 
@@ -34,69 +34,6 @@ module CyberarmEngine
34
34
  @text.draw
35
35
  end
36
36
 
37
- def enter(_sender)
38
- @focus = false unless window.button_down?(Gosu::MsLeft)
39
-
40
- if !@enabled
41
- @style.background_canvas.background = @style.disabled[:background]
42
- @text.color = @style.disabled[:color]
43
- elsif @focus
44
- @style.background_canvas.background = @style.active[:background]
45
- @text.color = @style.active[:color]
46
- else
47
- @style.background_canvas.background = @style.hover[:background]
48
- @text.color = @style.hover[:color]
49
- end
50
-
51
- :handled
52
- end
53
-
54
- def left_mouse_button(_sender, _x, _y)
55
- @focus = true
56
-
57
- unless @enabled
58
- @style.background_canvas.background = @style.disabled[:background]
59
- @text.color = @style.disabled[:color]
60
- else
61
- @style.background_canvas.background = @style.active[:background]
62
- @text.color = @style.active[:color]
63
- end
64
-
65
- window.current_state.focus = self
66
-
67
- :handled
68
- end
69
-
70
- def released_left_mouse_button(sender, _x, _y)
71
- enter(sender)
72
-
73
- :handled
74
- end
75
-
76
- def clicked_left_mouse_button(_sender, _x, _y)
77
- @block.call(self) if @enabled && @block
78
-
79
- :handled
80
- end
81
-
82
- def leave(_sender)
83
- unless @enabled
84
- @style.background_canvas.background = @style.disabled[:background]
85
- @text.color = @style.disabled[:color]
86
- else
87
- @style.background_canvas.background = @style.background
88
- @text.color = @style.color
89
- end
90
-
91
- :handled
92
- end
93
-
94
- def blur(_sender)
95
- @focus = false
96
-
97
- :handled
98
- end
99
-
100
37
  def recalculate
101
38
  unless @enabled
102
39
  @style.background_canvas.background = @style.disabled[:background]
@@ -5,8 +5,11 @@ module CyberarmEngine
5
5
  super(options, block)
6
6
  options[:toggled] = options[:checked]
7
7
 
8
+ options[:parent] = self
8
9
  @toggle_button = ToggleButton.new(options)
9
- @label = TextBlock.new(text, options)
10
+
11
+ options[:parent] = self
12
+ @label = TextBlock.new(text, options)
10
13
 
11
14
  @label.subscribe(:holding_left_mouse_button) do |sender, x, y|
12
15
  @toggle_button.left_mouse_button(sender, x, y)
@@ -60,30 +60,13 @@ module CyberarmEngine
60
60
  Gosu.clip_to(@x, @y, width, height) do
61
61
  @children.each(&:draw)
62
62
  end
63
+ end
64
+
65
+ def debug_draw
66
+ super
63
67
 
64
- if false # DEBUG
65
- Gosu.flush
66
-
67
- Gosu.draw_line(
68
- x, y, Gosu::Color::RED,
69
- x + outer_width, y, Gosu::Color::RED,
70
- Float::INFINITY
71
- )
72
- Gosu.draw_line(
73
- x + outer_width, y, Gosu::Color::RED,
74
- x + outer_width, y + outer_height, Gosu::Color::RED,
75
- Float::INFINITY
76
- )
77
- Gosu.draw_line(
78
- x + outer_width, y + outer_height, Gosu::Color::RED,
79
- x, y + outer_height, Gosu::Color::RED,
80
- Float::INFINITY
81
- )
82
- Gosu.draw_line(
83
- x, outer_height, Gosu::Color::RED,
84
- x, y, Gosu::Color::RED,
85
- Float::INFINITY
86
- )
68
+ @children.each do |child|
69
+ child.debug_draw
87
70
  end
88
71
  end
89
72
 
@@ -205,7 +188,6 @@ module CyberarmEngine
205
188
 
206
189
  def mouse_wheel_up(sender, x, y)
207
190
  return unless @style.scroll
208
- return if height < max_scroll_height
209
191
 
210
192
  if @scroll_position.y < 0
211
193
  @scroll_position.y += @scroll_speed
@@ -218,7 +200,8 @@ module CyberarmEngine
218
200
 
219
201
  def mouse_wheel_down(sender, x, y)
220
202
  return unless @style.scroll
221
- return if height < max_scroll_height
203
+
204
+ return unless height < scroll_height
222
205
 
223
206
  if @scroll_position.y.abs < max_scroll_height
224
207
  @scroll_position.y -= @scroll_speed
@@ -229,6 +212,21 @@ module CyberarmEngine
229
212
  end
230
213
  end
231
214
 
215
+ def scroll_top
216
+ @scroll_position.y
217
+ end
218
+
219
+ def scroll_top=(n)
220
+ n = 0 if n <= 0
221
+ @scroll_position.y = -n
222
+
223
+ if max_scroll_height.positive?
224
+ @scroll_position.y = -max_scroll_height if @scroll_position.y.abs > max_scroll_height
225
+ else
226
+ @scroll_position.y = 0
227
+ end
228
+ end
229
+
232
230
  def value
233
231
  @children.map { |c| c.class }.join(", ")
234
232
  end
@@ -59,6 +59,8 @@ module CyberarmEngine
59
59
  end
60
60
 
61
61
  def update
62
+ @style_event = :active if @focus
63
+
62
64
  @text.text = if @type == :password
63
65
  default(:password_character) * @text_input.text.length
64
66
  else
@@ -194,38 +196,27 @@ module CyberarmEngine
194
196
  :handled
195
197
  end
196
198
 
197
- def enter(_sender)
198
- if @focus
199
- @style.background_canvas.background = default(:active, :background)
200
- @text.color = default(:active, :color)
201
- else
202
- @style.background_canvas.background = default(:hover, :background)
203
- @text.color = default(:hover, :color)
204
- end
199
+ def focus(sender)
200
+ super
201
+
202
+ window.text_input = @text_input
203
+ @text_input.caret_pos = @text_input.selection_start = @text_input.text.length
205
204
 
206
205
  :handled
207
206
  end
208
207
 
209
- def leave(sender)
210
- super unless @focus
208
+ def enter(sender)
209
+ _has_focus = @focus
211
210
 
212
- :handled
213
- end
211
+ super
214
212
 
215
- def focus(sender)
216
- @focus = true
217
- @style.background_canvas.background = default(:active, :background)
218
- @text.color = default(:active, :color)
219
- window.text_input = @text_input
220
- @text_input.caret_pos = @text_input.selection_start = @text_input.text.length
213
+ @focus = _has_focus
221
214
 
222
215
  :handled
223
216
  end
224
217
 
225
218
  def blur(_sender)
226
- @focus = false
227
- @style.background_canvas.background = default(:background)
228
- @text.color = default(:color)
219
+ super
229
220
  window.text_input = nil
230
221
 
231
222
  :handled
@@ -18,12 +18,6 @@ module CyberarmEngine
18
18
  @text.draw
19
19
  end
20
20
 
21
- def clicked_left_mouse_button(_sender, _x, _y)
22
- @block&.call(self) if @enabled
23
-
24
- # return :handled
25
- end
26
-
27
21
  def recalculate
28
22
  @width = 0
29
23
  @height = 0
@@ -152,5 +146,8 @@ module CyberarmEngine
152
146
 
153
147
  class ToolTip < TextBlock
154
148
  end
149
+
150
+ class Link < TextBlock
151
+ end
155
152
  end
156
153
  end
@@ -26,12 +26,15 @@ module CyberarmEngine
26
26
  @dragging_element = nil
27
27
  @pending_recalculate_request = false
28
28
 
29
- @tip = Element::ToolTip.new("", parent: @root_container, z: Float::INFINITY)
30
29
  @menu = nil
31
30
  @min_drag_distance = 0
32
31
  @mouse_pos = Vector.new
33
32
  end
34
33
 
34
+ def post_setup
35
+ @tip = Element::ToolTip.new("", parent: @root_container, z: Float::INFINITY, theme: current_theme)
36
+ end
37
+
35
38
  # throws :blur event to focused element and sets GuiState focused element
36
39
  # Does NOT throw :focus event at element or set element as focused
37
40
  def focus=(element)
@@ -55,6 +58,12 @@ module CyberarmEngine
55
58
  Gosu.flush
56
59
  @tip.draw
57
60
  end
61
+
62
+ if defined?(GUI_DEBUG)
63
+ Gosu.flush
64
+
65
+ @root_container.debug_draw
66
+ end
58
67
  end
59
68
 
60
69
  def update
@@ -97,7 +106,7 @@ module CyberarmEngine
97
106
  @tip.x = window.mouse_x - @tip.width / 2
98
107
  @tip.x = 0 if @tip.x < 0
99
108
  @tip.x = window.width - @tip.width if @tip.x + @tip.width > window.width
100
- @tip.y = window.mouse_y - @tip.height
109
+ @tip.y = window.mouse_y - (@tip.height + 5)
101
110
  @tip.y = 0 if @tip.y < 0
102
111
  @tip.y = window.height - @tip.height if @tip.y + @tip.height > window.height
103
112
  @tip.update
@@ -17,8 +17,20 @@ end
17
17
 
18
18
  module CyberarmEngine
19
19
  class Style
20
+ attr_reader :hash
21
+
20
22
  def initialize(hash = {})
21
- @hash = Marshal.load(Marshal.dump(hash))
23
+ h = Marshal.load(Marshal.dump(hash))
24
+
25
+ h[:default] = {}
26
+
27
+ h.each do |key, value|
28
+ next if value.is_a?(Hash)
29
+
30
+ h[:default][key] = value
31
+ end
32
+
33
+ @hash = h
22
34
  end
23
35
 
24
36
  def method_missing(method, *args)
@@ -27,9 +39,8 @@ module CyberarmEngine
27
39
 
28
40
  @hash[method.to_s.sub("=", "").to_sym] = args.first
29
41
 
30
- elsif args.size == 0
42
+ elsif args.empty?
31
43
  @hash[method]
32
-
33
44
  else
34
45
  raise ArgumentError, "Did not expect arguments"
35
46
  end
@@ -64,6 +64,10 @@ module CyberarmEngine
64
64
  border_radius: 0
65
65
  },
66
66
 
67
+ Container: { # < Element (Base class for Stack and Flow)
68
+ debug_color: Gosu::Color::YELLOW
69
+ },
70
+
67
71
  Button: { # < Label
68
72
  margin: 1,
69
73
  padding: 4,
@@ -155,11 +159,28 @@ module CyberarmEngine
155
159
  border_color: 0xffaaaaaa,
156
160
  background: 0xff404040
157
161
  },
162
+ Link: { # < TextBlock
163
+ color: Gosu::Color::BLUE,
164
+ border_thickness: 1,
165
+ border_bottom_color: Gosu::Color::BLUE,
166
+ hover: {
167
+ color: 0xff_ff00ff,
168
+ border_bottom_color: 0xff_ff00ff
169
+ },
170
+ active: {
171
+ color: 0xff_ff0000,
172
+ border_bottom_color: 0xff_ff0000
173
+ }
174
+ },
158
175
 
159
176
  ToggleButton: { # < Button
160
177
  checkmark: "√"
161
178
  },
162
179
 
180
+ CheckBox: { # < Flow
181
+ text_wrap: :none
182
+ },
183
+
163
184
  Progress: { # < Element
164
185
  width: 250,
165
186
  height: 36,
@@ -1,4 +1,4 @@
1
1
  module CyberarmEngine
2
2
  NAME = "InDev".freeze
3
- VERSION = "0.17.1".freeze
3
+ VERSION = "0.18.0".freeze
4
4
  end
@@ -77,10 +77,12 @@ module CyberarmEngine
77
77
  if klass.instance_of?(klass.class) && defined?(klass.options)
78
78
  @states << klass
79
79
  klass.setup if options[:setup]
80
+ klass.post_setup if options[:setup]
80
81
  else
81
82
  @states << klass.new(options) if child_of?(klass, GameState)
82
83
  @states << klass.new if child_of?(klass, Element::Container)
83
84
  current_state.setup if current_state.instance_of?(klass) && options[:setup]
85
+ current_state.post_setup if current_state.instance_of?(klass) && options[:setup]
84
86
  end
85
87
  end
86
88
 
@@ -93,7 +95,7 @@ module CyberarmEngine
93
95
  end
94
96
 
95
97
  def previous_state
96
- if @states.size > 1 && state = @states[@states.size - 2]
98
+ if @states.size > 1 && (state = @states[@states.size - 2])
97
99
  state
98
100
  end
99
101
  end
@@ -102,6 +104,10 @@ module CyberarmEngine
102
104
  @states.pop
103
105
  end
104
106
 
107
+ def shift_state
108
+ @states.shift
109
+ end
110
+
105
111
  # Sourced from https://gist.github.com/ippa/662583
106
112
  def draw_circle(cx, cy, r, z = 9999, color = Gosu::Color::GREEN, step = 10)
107
113
  0.step(360, step) do |a1|
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cyberarm_engine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.1
4
+ version: 0.18.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cyberarm
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-02-11 00:00:00.000000000 Z
11
+ date: 2021-04-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: clipboard
@@ -123,6 +123,7 @@ files:
123
123
  - README.md
124
124
  - Rakefile
125
125
  - assets/textures/default.png
126
+ - assets/textures/logo.png
126
127
  - bin/console
127
128
  - bin/setup
128
129
  - cyberarm_engine.gemspec
@@ -131,6 +132,7 @@ files:
131
132
  - lib/cyberarm_engine/background.rb
132
133
  - lib/cyberarm_engine/background_nine_slice.rb
133
134
  - lib/cyberarm_engine/bounding_box.rb
135
+ - lib/cyberarm_engine/builtin/intro_state.rb
134
136
  - lib/cyberarm_engine/cache.rb
135
137
  - lib/cyberarm_engine/cache/download_manager.rb
136
138
  - lib/cyberarm_engine/common.rb
@@ -169,7 +171,6 @@ files:
169
171
  - lib/cyberarm_engine/ui/elements/edit_line.rb
170
172
  - lib/cyberarm_engine/ui/elements/flow.rb
171
173
  - lib/cyberarm_engine/ui/elements/image.rb
172
- - lib/cyberarm_engine/ui/elements/label.rb
173
174
  - lib/cyberarm_engine/ui/elements/list_box.rb
174
175
  - lib/cyberarm_engine/ui/elements/progress.rb
175
176
  - lib/cyberarm_engine/ui/elements/radio.rb
@@ -1,156 +0,0 @@
1
- module CyberarmEngine
2
- class Element
3
- class TextBlock < Element
4
- def initialize(text, options = {}, block = nil)
5
- super(options, block)
6
-
7
- @text = Text.new(
8
- text, font: @options[:font], z: @z, color: @options[:color],
9
- size: @options[:text_size], shadow: @options[:text_shadow],
10
- shadow_size: @options[:text_shadow_size],
11
- shadow_color: @options[:text_shadow_color]
12
- )
13
-
14
- @raw_text = text
15
- end
16
-
17
- def render
18
- @text.draw
19
- end
20
-
21
- def clicked_left_mouse_button(_sender, _x, _y)
22
- @block&.call(self) if @enabled
23
-
24
- # return :handled
25
- end
26
-
27
- def recalculate
28
- @width = 0
29
- @height = 0
30
-
31
- _width = dimensional_size(@style.width, :width)
32
- _height = dimensional_size(@style.height, :height)
33
-
34
- handle_text_wrapping(_width)
35
-
36
- @width = _width || @text.width.round
37
- @height = _height || @text.height.round
38
-
39
- @text.y = @style.border_thickness_top + @style.padding_top + @y
40
- @text.z = @z + 3
41
-
42
- if (text_alignment = @options[:text_align])
43
- case text_alignment
44
- when :left
45
- @text.x = @style.border_thickness_left + @style.padding_left + @x
46
- when :center
47
- @text.x = if @text.width <= outer_width
48
- @x + outer_width / 2 - @text.width / 2
49
- else # Act as left aligned
50
- @style.border_thickness_left + @style.padding_left + @x
51
- end
52
- when :right
53
- @text.x = @x + outer_width - (@text.width + @style.border_thickness_right + @style.padding_right)
54
- end
55
- end
56
-
57
- update_background
58
- end
59
-
60
- def handle_text_wrapping(max_width)
61
- max_width ||= @parent&.width
62
- max_width ||= @x - (window.width + noncontent_width)
63
- wrap_behavior = style.text_wrap
64
- copy = @raw_text.to_s.dup
65
-
66
- if max_width >= line_width(copy[0]) && line_width(copy) > max_width && wrap_behavior != :none
67
- breaks = []
68
- line_start = 0
69
- line_end = copy.length
70
-
71
- while line_start != copy.length
72
- if line_width(copy[line_start...line_end]) > max_width
73
- line_end = ((line_end - line_start) / 2.0)
74
- elsif line_end < copy.length && line_width(copy[line_start...line_end + 1]) < max_width
75
- # To small, grow!
76
- # TODO: find a more efficient way
77
- line_end += 1
78
-
79
- else # FOUND IT!
80
- entering_line_end = line_end.floor
81
- max_reach = line_end.floor - line_start < 63 ? line_end.floor - line_start : 63
82
- reach = 0
83
-
84
- if wrap_behavior == :word_wrap
85
- max_reach.times do |i|
86
- reach = i
87
- break if copy[line_end.floor - i].to_s.match(/[[:punct:]]| /)
88
- end
89
-
90
- puts "Max width: #{max_width}/#{line_width(@raw_text)} Reach: {#{reach}/#{max_reach}} Line Start: #{line_start}/#{line_end.floor} (#{copy.length}|#{@raw_text.length}) [#{entering_line_end}] '#{copy}' {#{copy[line_start...line_end]}}"
91
- line_end = line_end.floor - reach + 1 if reach != max_reach # Add +1 to walk in front of punctuation
92
- end
93
-
94
- breaks << line_end.floor
95
- line_start = line_end.floor
96
- line_end = copy.length
97
-
98
- break if entering_line_end == copy.length || reach == max_reach
99
- end
100
- end
101
-
102
- breaks.each_with_index do |pos, index|
103
- copy.insert(pos + index, "\n") if pos + index >= 0 && pos + index < copy.length
104
- end
105
- end
106
-
107
- @text.text = copy
108
- end
109
-
110
- def line_width(text)
111
- (@x + @text.textobject.markup_width(text) + noncontent_width)
112
- end
113
-
114
- def value
115
- @raw_text
116
- end
117
-
118
- def value=(value)
119
- @raw_text = value.to_s.chomp
120
-
121
- old_width = width
122
- old_height = height
123
- recalculate
124
-
125
- root.gui_state.request_recalculate if old_width != width || old_height != height
126
-
127
- publish(:changed, self.value)
128
- end
129
- end
130
-
131
- class Banner < TextBlock
132
- end
133
-
134
- class Title < TextBlock
135
- end
136
-
137
- class Subtitle < TextBlock
138
- end
139
-
140
- class Tagline < TextBlock
141
- end
142
-
143
- class Caption < TextBlock
144
- end
145
-
146
- class Para < TextBlock
147
- end
148
-
149
- class Inscription < TextBlock
150
- end
151
-
152
- # TODO: Remove in version 0.16.0+
153
- class Label < TextBlock
154
- end
155
- end
156
- end