osb 1.0.3 → 1.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.
- checksums.yaml +4 -4
- data/lib/osb/animation.rb +1 -1
- data/lib/osb/assert.rb +15 -10
- data/lib/osb/background.rb +3 -1
- data/lib/osb/color.rb +52 -17
- data/lib/osb/commandable.rb +38 -15
- data/lib/osb/dsl/commands.rb +252 -0
- data/lib/osb/dsl/object.rb +141 -0
- data/lib/osb/integer.rb +2 -0
- data/lib/osb/numeric.rb +2 -0
- data/lib/osb/sample.rb +4 -1
- data/lib/osb/sprite.rb +1 -1
- data/lib/osb/storyboard.rb +5 -5
- data/lib/osb/vector2.rb +20 -10
- data/lib/osb/video.rb +4 -4
- data/lib/osb.rb +6 -1
- metadata +5 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bfa8c9fd46a2c0c25b5ae9b9d88d1043e2f16a74b01ff0ae1f8f7561d448f7f0
|
4
|
+
data.tar.gz: 44a5c46b92e37bdb8f8f5694e8da2b28dabecc77d27793d43b15238ddc97382c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 96064b59c3bbca5233109df31a39cf1867a1c598bfdb4f5583f992af578d43c9b4659c46f81ef8fcedd870e112aaa415bc27e88c290025700d8f7ea35a26e812
|
7
|
+
data.tar.gz: 601067ee4dd65cd6781b0a8719e988b5ba4f7888760a9dc4069b1d5369bfe497358314cf97ed01b3be9aee48a6cca0368e9bd6d0b31e59b930be818ba8be920b
|
data/lib/osb/animation.rb
CHANGED
data/lib/osb/assert.rb
CHANGED
@@ -1,20 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Osb
|
4
|
-
# @
|
4
|
+
# @private
|
5
5
|
class TypeError < StandardError
|
6
6
|
end
|
7
7
|
|
8
|
-
# @
|
8
|
+
# @private
|
9
9
|
class InvalidValueError < StandardError
|
10
10
|
end
|
11
11
|
|
12
|
-
# @
|
12
|
+
# @private
|
13
13
|
module Internal
|
14
|
-
# @
|
14
|
+
# @private
|
15
15
|
Boolean = [TrueClass, FalseClass]
|
16
16
|
|
17
|
-
# @
|
17
|
+
# @private
|
18
18
|
class TypedArray
|
19
19
|
# @param [Class] type
|
20
20
|
def initialize(type)
|
@@ -30,16 +30,21 @@ module Osb
|
|
30
30
|
end
|
31
31
|
end
|
32
32
|
|
33
|
-
# @
|
33
|
+
# @private
|
34
34
|
# @type [Hash{Class => Hash{Class => Object}}]
|
35
|
-
T = {
|
35
|
+
T = {
|
36
|
+
Array => {
|
37
|
+
Numeric => TypedArray.new(Numeric),
|
38
|
+
Integer => TypedArray.new(Integer)
|
39
|
+
}
|
40
|
+
}
|
36
41
|
|
37
42
|
# Check if supplied argument is correctly typed.
|
38
43
|
# @param [Object] arg
|
39
44
|
# @param [BasicObject, Array, TypedArray] possible_types
|
40
45
|
# @param [String] param_name
|
41
46
|
# @return [void]
|
42
|
-
# @
|
47
|
+
# @private
|
43
48
|
def self.assert_type!(arg, possible_types, param_name)
|
44
49
|
if possible_types.is_a?(Array)
|
45
50
|
valid =
|
@@ -75,7 +80,7 @@ module Osb
|
|
75
80
|
# @param [BasicObject, Array, Range] possible_values
|
76
81
|
# @param [String] param_name
|
77
82
|
# @return [void]
|
78
|
-
# @
|
83
|
+
# @private
|
79
84
|
def self.assert_value!(arg, possible_values, param_name)
|
80
85
|
val =
|
81
86
|
if arg.is_a?(String) && arg.empty?
|
@@ -113,7 +118,7 @@ module Osb
|
|
113
118
|
# Ensure the file name extenstion is correct.
|
114
119
|
# @param [String] file_name
|
115
120
|
# @param [String, Array<String>] exts
|
116
|
-
# @
|
121
|
+
# @private
|
117
122
|
def self.assert_file_name_ext!(file_name, exts)
|
118
123
|
if exts.is_a?(Array)
|
119
124
|
exts_ = exts.join("|")
|
data/lib/osb/background.rb
CHANGED
data/lib/osb/color.rb
CHANGED
@@ -11,36 +11,52 @@ module Osb
|
|
11
11
|
# @attribute [rw] b
|
12
12
|
# @return Blue value.
|
13
13
|
|
14
|
-
# @param [Integer] r red value
|
14
|
+
# @param [Integer, String, Array<Integer>] r red value, a hex +String+,
|
15
|
+
# or an +Array+ of 3 +{Integer}+s.
|
15
16
|
# @param [Integer] g green value
|
16
17
|
# @param [Integer] b blue value
|
17
|
-
def initialize(r, g, b)
|
18
|
-
Internal.assert_type!(
|
19
|
-
|
18
|
+
def initialize(r, g = nil, b = nil)
|
19
|
+
Internal.assert_type!(
|
20
|
+
r,
|
21
|
+
[Integer, String, Internal::T[Array][Integer]],
|
22
|
+
"r"
|
23
|
+
)
|
24
|
+
if r.is_a?(Array)
|
25
|
+
if r.size != 3
|
26
|
+
raise InvalidValueError, "Must be an Array of 3 Integers."
|
27
|
+
end
|
28
|
+
@r = r[0]
|
29
|
+
@g = r[1]
|
30
|
+
@b = r[2]
|
31
|
+
elsif r.is_a?(String)
|
32
|
+
Color.from_hex(r)
|
33
|
+
else
|
34
|
+
Internal.assert_value!(r, 0..255, "r")
|
20
35
|
|
21
|
-
|
22
|
-
|
36
|
+
Internal.assert_type!(g, Integer, "g")
|
37
|
+
Internal.assert_value!(g, 0..255, "g")
|
23
38
|
|
24
|
-
|
25
|
-
|
39
|
+
Internal.assert_type!(b, Integer, "b")
|
40
|
+
Internal.assert_value!(b, 0..255, "b")
|
26
41
|
|
27
|
-
|
28
|
-
|
29
|
-
|
42
|
+
@r = r
|
43
|
+
@g = g
|
44
|
+
@b = b
|
45
|
+
end
|
30
46
|
end
|
31
47
|
|
32
48
|
# Returns whether 2 colors are not equal.
|
33
49
|
# @param [Color] color
|
34
50
|
def !=(color)
|
35
51
|
Internal.assert_type!(color, Color, "color")
|
36
|
-
|
52
|
+
|
37
53
|
color.r != self.r && color.g != self.g && color.b != self.b
|
38
54
|
end
|
39
55
|
|
40
56
|
# Converts an HSL color value to RGB.
|
41
|
-
# @param [Integer]
|
42
|
-
# @param [Integer]
|
43
|
-
# @param [Integer]
|
57
|
+
# @param [Integer] hue
|
58
|
+
# @param [Integer] saturation
|
59
|
+
# @param [Integer] lightness
|
44
60
|
# @return [Color]
|
45
61
|
def self.from_hsl(h, s, l)
|
46
62
|
Internal.assert_type!(h, Integer, "h")
|
@@ -70,7 +86,7 @@ module Osb
|
|
70
86
|
Color.new((r * 255).round, (g * 255).round, (b * 255).round)
|
71
87
|
end
|
72
88
|
|
73
|
-
# @
|
89
|
+
# @private
|
74
90
|
# @param [Float] p
|
75
91
|
# @param [Float] q
|
76
92
|
# @param [Float] t_
|
@@ -84,7 +100,7 @@ module Osb
|
|
84
100
|
return p
|
85
101
|
end
|
86
102
|
|
87
|
-
# Create a Color object from hex string.
|
103
|
+
# Create a +{Color}+ object from hex string.
|
88
104
|
# @param [String] hex
|
89
105
|
# @return [Color]
|
90
106
|
def self.from_hex(hex)
|
@@ -95,4 +111,23 @@ module Osb
|
|
95
111
|
components.collect { |component| component.to_i(16) }
|
96
112
|
end
|
97
113
|
end
|
114
|
+
|
115
|
+
# Create a new rgb +{Color}+.
|
116
|
+
# @param [Integer, String, Array<Integer>] r red value, a hex +String+,
|
117
|
+
# or an +Array+ of 3 +{Integer}+s.
|
118
|
+
# @param [Integer] g green value
|
119
|
+
# @param [Integer] b blue value
|
120
|
+
# @return [Color]
|
121
|
+
def rgb(r, g = nil, b = nil)
|
122
|
+
Color.new(r, g, b)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Create a new hsl +{Color}+.
|
126
|
+
# @param [Integer] hue
|
127
|
+
# @param [Integer] saturation
|
128
|
+
# @param [Integer] lightness
|
129
|
+
# @return [Color]
|
130
|
+
def hsl(h, s, l)
|
131
|
+
Color.from_hsl(h, s, l)
|
132
|
+
end
|
98
133
|
end
|
data/lib/osb/commandable.rb
CHANGED
@@ -4,21 +4,21 @@ module Osb
|
|
4
4
|
module Internal
|
5
5
|
# @param [Integer] time
|
6
6
|
# @return [void]
|
7
|
-
# @
|
7
|
+
# @private
|
8
8
|
def self.raise_if_invalid_start_time!(time)
|
9
9
|
Internal.assert_type!(time, Integer, "start_time")
|
10
10
|
end
|
11
11
|
|
12
12
|
# @param [Integer] time
|
13
13
|
# @return [void]
|
14
|
-
# @
|
14
|
+
# @private
|
15
15
|
def self.raise_if_invalid_end_time!(time)
|
16
16
|
Internal.assert_type!(time, Integer, "end_time")
|
17
17
|
end
|
18
18
|
|
19
19
|
# @param [Integer] easing
|
20
20
|
# @return [void]
|
21
|
-
# @
|
21
|
+
# @private
|
22
22
|
def self.raise_if_invalid_easing!(easing)
|
23
23
|
Internal.assert_type!(easing, Integer, "easing")
|
24
24
|
Internal.assert_value!(easing, Easing::ALL, "easing")
|
@@ -26,10 +26,12 @@ module Osb
|
|
26
26
|
end
|
27
27
|
|
28
28
|
module Commandable
|
29
|
+
# @private
|
29
30
|
private def tab_level
|
30
31
|
@is_in_trigger ? 2 : 1
|
31
32
|
end
|
32
33
|
|
34
|
+
# @private
|
33
35
|
private def raise_if_trigger_called!
|
34
36
|
if @trigger_called
|
35
37
|
raise RuntimeError, "Do not add commands after #trigger is called."
|
@@ -42,6 +44,7 @@ module Osb
|
|
42
44
|
# @param [Integer] easing
|
43
45
|
# @param [Numeric] start_opacity
|
44
46
|
# @param [Numeric] end_opacity
|
47
|
+
# @return [void]
|
45
48
|
def fade(
|
46
49
|
start_time:,
|
47
50
|
end_time: start_time,
|
@@ -71,6 +74,7 @@ module Osb
|
|
71
74
|
# @param [Integer] easing
|
72
75
|
# @param [Osb::Vector2, Array<Numeric>] start_position
|
73
76
|
# @param [Osb::Vector2, Array<Numeric>] end_position
|
77
|
+
# @return [void]
|
74
78
|
def move(
|
75
79
|
start_time:,
|
76
80
|
end_time: start_time,
|
@@ -84,12 +88,12 @@ module Osb
|
|
84
88
|
Internal.raise_if_invalid_easing!(easing)
|
85
89
|
Internal.assert_type!(
|
86
90
|
start_position,
|
87
|
-
[Osb::Vector2, T[Array][Numeric]],
|
91
|
+
[Osb::Vector2, Internal::T[Array][Numeric]],
|
88
92
|
"start_position"
|
89
93
|
)
|
90
94
|
Internal.assert_type!(
|
91
95
|
end_position,
|
92
|
-
[Osb::Vector2, T[Array][Numeric]],
|
96
|
+
[Osb::Vector2, Internal::T[Array][Numeric]],
|
93
97
|
"end_position"
|
94
98
|
)
|
95
99
|
if start_position.is_a?(Array)
|
@@ -100,8 +104,9 @@ module Osb
|
|
100
104
|
tabs = " " * self.tab_level
|
101
105
|
command =
|
102
106
|
"#{tabs}M,#{start_time},#{end_time},#{start_position.x},#{start_position.y}"
|
103
|
-
|
104
|
-
|
107
|
+
if end_position != start_position
|
108
|
+
command += ",#{end_position.x},#{end_position.y}"
|
109
|
+
end
|
105
110
|
@commands << command
|
106
111
|
end
|
107
112
|
|
@@ -111,6 +116,7 @@ module Osb
|
|
111
116
|
# @param [Integer] easing
|
112
117
|
# @param [Numeric] start_x
|
113
118
|
# @param [Numeric] end_x
|
119
|
+
# @return [void]
|
114
120
|
def move_x(
|
115
121
|
start_time:,
|
116
122
|
end_time: start_time,
|
@@ -138,6 +144,7 @@ module Osb
|
|
138
144
|
# @param [Integer] easing
|
139
145
|
# @param [Numeric] start_y
|
140
146
|
# @param [Numeric] end_y
|
147
|
+
# @return [void]
|
141
148
|
def move_y(
|
142
149
|
start_time:,
|
143
150
|
end_time: start_time,
|
@@ -167,6 +174,7 @@ module Osb
|
|
167
174
|
# @param [Integer] easing
|
168
175
|
# @param [Numeric, Osb::Vector2, Array<Numeric>] start_scale
|
169
176
|
# @param [Numeric, Osb::Vector2, Array<Numeric>] end_scale
|
177
|
+
# @return [void]
|
170
178
|
def scale(
|
171
179
|
start_time:,
|
172
180
|
end_time: start_time,
|
@@ -180,12 +188,12 @@ module Osb
|
|
180
188
|
Internal.raise_if_invalid_easing!(easing)
|
181
189
|
Internal.assert_type!(
|
182
190
|
start_scale,
|
183
|
-
[Numeric, T[Array][Numeric], Osb::Vector2],
|
191
|
+
[Numeric, Internal::T[Array][Numeric], Osb::Vector2],
|
184
192
|
"start_scale"
|
185
193
|
)
|
186
194
|
Internal.assert_type!(
|
187
195
|
end_scale,
|
188
|
-
[Numeric, T[Array][Numeric], Osb::Vector2],
|
196
|
+
[Numeric, Internal::T[Array][Numeric], Osb::Vector2],
|
189
197
|
"end_scale"
|
190
198
|
)
|
191
199
|
|
@@ -207,7 +215,6 @@ module Osb
|
|
207
215
|
end
|
208
216
|
|
209
217
|
start_scale = Osb::Vector2.new(start_scale) if start_scale.is_a?(Array)
|
210
|
-
|
211
218
|
end_scale = Osb::Vector2.new(end_scale) if end_scale.is_a?(Array)
|
212
219
|
|
213
220
|
command =
|
@@ -223,6 +230,7 @@ module Osb
|
|
223
230
|
# @param [Integer] easing
|
224
231
|
# @param [Float] start_angle start angle in radians.
|
225
232
|
# @param [Float] end_angle end angle in radians.
|
233
|
+
# @return [void]
|
226
234
|
def rotate(
|
227
235
|
start_time:,
|
228
236
|
end_time: start_time,
|
@@ -248,8 +256,9 @@ module Osb
|
|
248
256
|
# @param [Integer] start_time
|
249
257
|
# @param [Integer] end_time
|
250
258
|
# @param [Integer] easing
|
251
|
-
# @param [Osb::Color] start_color
|
252
|
-
# @param [Osb::Color] end_color
|
259
|
+
# @param [Osb::Color, Array<Integer>] start_color
|
260
|
+
# @param [Osb::Color, Array<Integer>] end_color
|
261
|
+
# @return [void]
|
253
262
|
def color(
|
254
263
|
start_time:,
|
255
264
|
end_time: start_time,
|
@@ -261,8 +270,19 @@ module Osb
|
|
261
270
|
Internal.raise_if_invalid_start_time!(start_time)
|
262
271
|
Internal.raise_if_invalid_end_time!(end_time)
|
263
272
|
Internal.raise_if_invalid_easing!(easing)
|
264
|
-
Internal.assert_type!(
|
265
|
-
|
273
|
+
Internal.assert_type!(
|
274
|
+
start_color,
|
275
|
+
[Osb::Color, Internal::T[Array][Integer]],
|
276
|
+
"start_color"
|
277
|
+
)
|
278
|
+
Internal.assert_type!(
|
279
|
+
end_color,
|
280
|
+
[Osb::Color, Internal::T[Array][Integer]],
|
281
|
+
"end_color"
|
282
|
+
)
|
283
|
+
|
284
|
+
start_color = Color.new(start_color) if start_color.is_a?(Array)
|
285
|
+
end_color = Color.new(end_color) if end_color.is_a?(Array)
|
266
286
|
|
267
287
|
end_time = "" if start_time == end_time
|
268
288
|
tabs = " " * self.tab_level
|
@@ -279,6 +299,7 @@ module Osb
|
|
279
299
|
# @param [Integer] end_time
|
280
300
|
# @param [Boolean] horizontally
|
281
301
|
# @param [Boolean] vertically
|
302
|
+
# @return [void]
|
282
303
|
def flip(start_time:, end_time:, horizontally: true, vertically: false)
|
283
304
|
self.raise_if_trigger_called!
|
284
305
|
Internal.raise_if_invalid_start_time!(start_time)
|
@@ -304,6 +325,7 @@ module Osb
|
|
304
325
|
# Use additive-color blending instead of alpha-blending.
|
305
326
|
# @param [Integer] start_time
|
306
327
|
# @param [Integer] end_time
|
328
|
+
# @return [void]
|
307
329
|
def additive_color_blending(start_time:, end_time:)
|
308
330
|
self.raise_if_trigger_called!
|
309
331
|
Internal.raise_if_invalid_start_time!(start_time)
|
@@ -338,7 +360,8 @@ module Osb
|
|
338
360
|
# @param [String] on indicates the trigger condition. It can be "Failing" or "Passing".
|
339
361
|
# @param [Integer] start_time the timestamp at which the trigger becomes valid.
|
340
362
|
# @param [Integer] end_time the timestamp at which the trigger stops being valid.
|
341
|
-
|
363
|
+
# @return [void]
|
364
|
+
def trigger(on:, start_time:, end_time:, &blk)
|
342
365
|
self.raise_if_trigger_called!
|
343
366
|
Internal.raise_if_invalid_start_time!(start_time)
|
344
367
|
Internal.raise_if_invalid_end_time!(end_time)
|
@@ -0,0 +1,252 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Osb
|
4
|
+
# @private
|
5
|
+
def current_object
|
6
|
+
return @sprite if @sprite
|
7
|
+
return @animation if @animation
|
8
|
+
return nil
|
9
|
+
end
|
10
|
+
|
11
|
+
# @private
|
12
|
+
def raise_unless_inside_object!
|
13
|
+
self.raise_unless_inside_storyboard!
|
14
|
+
unless self.current_object
|
15
|
+
raise RuntimeError,
|
16
|
+
"Do not call this method outside of a sprite/animation context."
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Change the opacity of the object (how transparent it is).
|
21
|
+
# @param [Integer] start_time
|
22
|
+
# @param [Integer] end_time
|
23
|
+
# @param [Integer] easing
|
24
|
+
# @param [Numeric] start_opacity
|
25
|
+
# @param [Numeric] end_opacity
|
26
|
+
# @return [void]
|
27
|
+
def fade(
|
28
|
+
start_time:,
|
29
|
+
end_time: start_time,
|
30
|
+
easing: Easing::Linear,
|
31
|
+
start_opacity:,
|
32
|
+
end_opacity: start_opacity
|
33
|
+
)
|
34
|
+
self.raise_unless_inside_object!
|
35
|
+
self.current_object.fade(
|
36
|
+
start_time: start_time,
|
37
|
+
end_time: end_time,
|
38
|
+
easing: easing,
|
39
|
+
start_opacity: start_opacity,
|
40
|
+
end_opacity: end_opacity
|
41
|
+
)
|
42
|
+
end
|
43
|
+
|
44
|
+
# Move the object to a new position in the play area.
|
45
|
+
# @param [Integer] start_time
|
46
|
+
# @param [Integer] end_time
|
47
|
+
# @param [Integer] easing
|
48
|
+
# @param [Osb::Vector2, Array<Numeric>] start_position
|
49
|
+
# @param [Osb::Vector2, Array<Numeric>] end_position
|
50
|
+
# @return [void]
|
51
|
+
def move(
|
52
|
+
start_time:,
|
53
|
+
end_time: start_time,
|
54
|
+
easing: Easing::Linear,
|
55
|
+
start_position:,
|
56
|
+
end_position: start_position
|
57
|
+
)
|
58
|
+
self.raise_unless_inside_object!
|
59
|
+
self.current_object.move(
|
60
|
+
start_time: start_time,
|
61
|
+
end_time: end_time,
|
62
|
+
easing: easing,
|
63
|
+
start_position: start_position,
|
64
|
+
end_position: end_position
|
65
|
+
)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Move the object along the x axis.
|
69
|
+
# @param [Integer] start_time
|
70
|
+
# @param [Integer] end_time
|
71
|
+
# @param [Integer] easing
|
72
|
+
# @param [Numeric] start_x
|
73
|
+
# @param [Numeric] end_x
|
74
|
+
# @return [void]
|
75
|
+
def move_x(
|
76
|
+
start_time:,
|
77
|
+
end_time: start_time,
|
78
|
+
easing: Easing::Linear,
|
79
|
+
start_x:,
|
80
|
+
end_x: start_x
|
81
|
+
)
|
82
|
+
self.raise_unless_inside_object!
|
83
|
+
self.current_object.move_x(
|
84
|
+
start_time: start_time,
|
85
|
+
end_time: end_time,
|
86
|
+
easing: easing,
|
87
|
+
start_x: start_x,
|
88
|
+
end_x: end_x
|
89
|
+
)
|
90
|
+
end
|
91
|
+
|
92
|
+
# Move the object along the y axis.
|
93
|
+
# @param [Integer] start_time
|
94
|
+
# @param [Integer] end_time
|
95
|
+
# @param [Integer] easing
|
96
|
+
# @param [Numeric] start_y
|
97
|
+
# @param [Numeric] end_y
|
98
|
+
# @return [void]
|
99
|
+
def move_y(
|
100
|
+
start_time:,
|
101
|
+
end_time: start_time,
|
102
|
+
easing: Easing::Linear,
|
103
|
+
start_y:,
|
104
|
+
end_y: start_y
|
105
|
+
)
|
106
|
+
self.raise_unless_inside_object!
|
107
|
+
self.current_object.move_x(
|
108
|
+
start_time: start_time,
|
109
|
+
end_time: end_time,
|
110
|
+
easing: easing,
|
111
|
+
start_y: start_y,
|
112
|
+
end_y: end_y
|
113
|
+
)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Change the size of the object relative to its original size. Will scale
|
117
|
+
# seperatedly if given +Osb::Vector2+s or +Array<Numeric>+s. The scaling is
|
118
|
+
# affected by the object's origin
|
119
|
+
# @param [Integer] start_time
|
120
|
+
# @param [Integer] end_time
|
121
|
+
# @param [Integer] easing
|
122
|
+
# @param [Numeric, Osb::Vector2, Array<Numeric>] start_scale
|
123
|
+
# @param [Numeric, Osb::Vector2, Array<Numeric>] end_scale
|
124
|
+
# @return [void]
|
125
|
+
def scale(
|
126
|
+
start_time:,
|
127
|
+
end_time: start_time,
|
128
|
+
easing: Easing::Linear,
|
129
|
+
start_scale:,
|
130
|
+
end_scale: start_scale
|
131
|
+
)
|
132
|
+
self.raise_unless_inside_object!
|
133
|
+
self.current_object.scale(
|
134
|
+
start_time: start_time,
|
135
|
+
end_time: end_time,
|
136
|
+
easing: easing,
|
137
|
+
start_scale: start_scale,
|
138
|
+
end_scale: end_scale
|
139
|
+
)
|
140
|
+
end
|
141
|
+
|
142
|
+
# Rotate the object around its origin.
|
143
|
+
# @param [Integer] start_time
|
144
|
+
# @param [Integer] end_time
|
145
|
+
# @param [Integer] easing
|
146
|
+
# @param [Float] start_angle start angle in radians.
|
147
|
+
# @param [Float] end_angle end angle in radians.
|
148
|
+
# @return [void]
|
149
|
+
def rotate(
|
150
|
+
start_time:,
|
151
|
+
end_time: start_time,
|
152
|
+
easing: Easing::Linear,
|
153
|
+
start_angle:,
|
154
|
+
end_angle: start_angle
|
155
|
+
)
|
156
|
+
self.raise_unless_inside_object!
|
157
|
+
self.current_object.rotate(
|
158
|
+
start_time: start_time,
|
159
|
+
end_time: end_time,
|
160
|
+
easing: easing,
|
161
|
+
start_angle: start_angle,
|
162
|
+
end_angle: end_angle
|
163
|
+
)
|
164
|
+
end
|
165
|
+
|
166
|
+
# The virtual light source colour on the object. The colours of the pixels on the object are determined subtractively.
|
167
|
+
# @param [Integer] start_time
|
168
|
+
# @param [Integer] end_time
|
169
|
+
# @param [Integer] easing
|
170
|
+
# @param [Osb::Color, Array<Integer>] start_color
|
171
|
+
# @param [Osb::Color, Array<Integer>] end_color
|
172
|
+
# @return [void]
|
173
|
+
def color(
|
174
|
+
start_time:,
|
175
|
+
end_time: start_time,
|
176
|
+
easing: Easing::Linear,
|
177
|
+
start_color:,
|
178
|
+
end_color: start_color
|
179
|
+
)
|
180
|
+
self.raise_unless_inside_object!
|
181
|
+
self.current_object.color(
|
182
|
+
start_time: start_time,
|
183
|
+
end_time: end_time,
|
184
|
+
easing: easing,
|
185
|
+
start_color: start_color,
|
186
|
+
end_color: end_color
|
187
|
+
)
|
188
|
+
end
|
189
|
+
|
190
|
+
# Flip the object horizontally or vertically.
|
191
|
+
# @param [Integer] start_time
|
192
|
+
# @param [Integer] end_time
|
193
|
+
# @param [Boolean] horizontally
|
194
|
+
# @param [Boolean] vertically
|
195
|
+
# @return [void]
|
196
|
+
def flip(start_time:, end_time:, horizontally: true, vertically: false)
|
197
|
+
self.raise_unless_inside_object!
|
198
|
+
self.current_object.flip(
|
199
|
+
start_time: start_time,
|
200
|
+
end_time: end_time,
|
201
|
+
horizontally: horizontally,
|
202
|
+
vertically: vertically
|
203
|
+
)
|
204
|
+
end
|
205
|
+
|
206
|
+
# Use additive-color blending instead of alpha-blending.
|
207
|
+
# @param [Integer] start_time
|
208
|
+
# @param [Integer] end_time
|
209
|
+
# @return [void]
|
210
|
+
def additive_color_blending(start_time:, end_time:)
|
211
|
+
self.raise_unless_inside_object!
|
212
|
+
self.current_object.additive_color_blending(
|
213
|
+
start_time: start_time,
|
214
|
+
end_time: end_time
|
215
|
+
)
|
216
|
+
end
|
217
|
+
|
218
|
+
# Add a group of commands on a specific condition.
|
219
|
+
# `#trigger` can only be called on an empty object declaration (no commands).
|
220
|
+
# Pass a block to this method call to specify which commands to run if
|
221
|
+
# the condition is met.
|
222
|
+
#
|
223
|
+
# @example
|
224
|
+
# img.trigger(on: "Passing", start_time: 0, end_time: 1000) do
|
225
|
+
# img.fade(start_time: 0, start_opacity: 0.5)
|
226
|
+
# end
|
227
|
+
#
|
228
|
+
# In addition to the "implicit" player feedback via the separate
|
229
|
+
# Pass/Fail layers, you can use one of several Trigger conditions
|
230
|
+
# to cause a series of events to happen whenever that condition is
|
231
|
+
# fulfilled within a certain time period.
|
232
|
+
# Note that `start_time` and `end_time` of any commands called inside
|
233
|
+
# the block become relative to the `start_time` and `end_time` of the
|
234
|
+
# `#trigger` command.
|
235
|
+
#
|
236
|
+
# While osu! supports trigger on hitsounds playing, we decided to not
|
237
|
+
# include it in because it is unreliable/unpredictable.
|
238
|
+
#
|
239
|
+
# @param [String] on indicates the trigger condition. It can be "Failing" or "Passing".
|
240
|
+
# @param [Integer] start_time the timestamp at which the trigger becomes valid.
|
241
|
+
# @param [Integer] end_time the timestamp at which the trigger stops being valid.
|
242
|
+
# @return [void]
|
243
|
+
def trigger(on:, start_time:, end_time:, &blk)
|
244
|
+
self.raise_unless_inside_object!
|
245
|
+
self.current_object.trigger(
|
246
|
+
on: on,
|
247
|
+
start_time: start_time,
|
248
|
+
end_time: end_time,
|
249
|
+
&blk
|
250
|
+
)
|
251
|
+
end
|
252
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Osb
|
4
|
+
# @private
|
5
|
+
def raise_unless_inside_storyboard!
|
6
|
+
unless @storyboard
|
7
|
+
raise RuntimeError,
|
8
|
+
"Do not call this method outside of a storyboard context."
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# Set the output directory of this storyboard.
|
13
|
+
# @param [String] path path to .osb or .osu file
|
14
|
+
def out_path(path)
|
15
|
+
self.raise_unless_inside_storyboard!
|
16
|
+
@out_path = path
|
17
|
+
end
|
18
|
+
|
19
|
+
# Create an osu! storyboard.
|
20
|
+
# @return [void]
|
21
|
+
def storyboard
|
22
|
+
if @storyboard
|
23
|
+
raise RuntimeError,
|
24
|
+
"Cannot create a new storyboard inside another storyboard."
|
25
|
+
end
|
26
|
+
@storyboard = Storyboard.new
|
27
|
+
yield
|
28
|
+
raise RuntimeError, "Output path is not set." unless @out_path
|
29
|
+
@storyboard.generate(@out_path)
|
30
|
+
@storyboard = nil
|
31
|
+
end
|
32
|
+
|
33
|
+
# Create a still image.
|
34
|
+
# @param [String] layer the layer the object appears on.
|
35
|
+
# @param [String] origin where on the image should osu! consider that image's origin (coordinate) to be.
|
36
|
+
# @param [String] file_path filename of the image.
|
37
|
+
# @param [Osb::Vector2, nil] initial_position where the object should be by default.
|
38
|
+
# @return [void]
|
39
|
+
def sprite(
|
40
|
+
layer: Layer::Background,
|
41
|
+
origin: Origin::Center,
|
42
|
+
file_path:,
|
43
|
+
initial_position: nil
|
44
|
+
)
|
45
|
+
self.raise_unless_inside_storyboard!
|
46
|
+
|
47
|
+
if @sprite || @animation
|
48
|
+
raise RuntimeError,
|
49
|
+
"Cannot create a new sprite inside another sprite/animation."
|
50
|
+
end
|
51
|
+
@sprite =
|
52
|
+
Sprite.new(
|
53
|
+
layer: layer,
|
54
|
+
origin: origin,
|
55
|
+
file_path: file_path,
|
56
|
+
initial_position: initial_position
|
57
|
+
)
|
58
|
+
@storyboard << @sprite
|
59
|
+
yield
|
60
|
+
@sprite = nil
|
61
|
+
end
|
62
|
+
|
63
|
+
# Group multiple objects for clarity.
|
64
|
+
# @return [void]
|
65
|
+
def group(name: nil)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Create a moving image.
|
69
|
+
# @param [String] layer the layer the object appears on.
|
70
|
+
# @param [String] origin where on the image should osu! consider that image's origin (coordinate) to be.
|
71
|
+
# @param [String] file_path filename of the image.
|
72
|
+
# @param [Vector2, nil] initial_position where the object should be by default.
|
73
|
+
# @param [Integer] frame_count how many frames the animation has.
|
74
|
+
# @param [Integer] frame_delay how many milliseconds should be in between each frame.
|
75
|
+
# @param [Boolean] repeat if the animation should loop or not.
|
76
|
+
# @return [void]
|
77
|
+
def animation(
|
78
|
+
layer: Osb::Layer::Background,
|
79
|
+
origin: Osb::Origin::Center,
|
80
|
+
file_path:,
|
81
|
+
initial_position: nil,
|
82
|
+
frame_count:,
|
83
|
+
frame_delay:,
|
84
|
+
repeat: false
|
85
|
+
)
|
86
|
+
self.raise_unless_inside_storyboard!
|
87
|
+
|
88
|
+
if @sprite || @animation
|
89
|
+
raise RuntimeError,
|
90
|
+
"Cannot create a new animation inside another animation/animation."
|
91
|
+
end
|
92
|
+
@animation =
|
93
|
+
Animation.new(
|
94
|
+
layer: layer,
|
95
|
+
origin: origin,
|
96
|
+
file_path: file_path,
|
97
|
+
initial_position: initial_position,
|
98
|
+
frame_count: frame_count,
|
99
|
+
frame_delay: frame_delay,
|
100
|
+
repeat: repeat
|
101
|
+
)
|
102
|
+
@storyboard << @animation
|
103
|
+
yield
|
104
|
+
@animation = nil
|
105
|
+
end
|
106
|
+
|
107
|
+
# Set the background image for the beatmap.
|
108
|
+
# @param [String] file_name location of the background image relative to the beatmap directory.
|
109
|
+
# @return [void]
|
110
|
+
def background(file_path:)
|
111
|
+
self.raise_unless_inside_storyboard!
|
112
|
+
|
113
|
+
@storyboard << Background.new(file_path: file_path)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Set the video for the beatmap.
|
117
|
+
# @param [String] file_name location of the video file relative to the beatmap directory.
|
118
|
+
# @param [Integer] start_time when the video starts.
|
119
|
+
# @return [void]
|
120
|
+
def video(file_path:, start_time:)
|
121
|
+
self.raise_unless_inside_storyboard!
|
122
|
+
|
123
|
+
@storyboard << Video.new(file_path: file_path, start_time: start_time)
|
124
|
+
end
|
125
|
+
|
126
|
+
# Add an audio sample to the storyboard.
|
127
|
+
# @param [Integer] time the timestamp that the sound should start playing.
|
128
|
+
# @param [String] layer the layer you want the sound to be on.
|
129
|
+
# @param [String] file_path filename of the audio.
|
130
|
+
# @param [Integer] volume indicate the relative loudness of the sound.
|
131
|
+
def sample(time:, layer:, file_path:, volume: 100)
|
132
|
+
self.raise_unless_inside_storyboard!
|
133
|
+
|
134
|
+
@storyboard << Sample.new(
|
135
|
+
time: time,
|
136
|
+
layer: layer,
|
137
|
+
file_path: file_path,
|
138
|
+
volume: volume
|
139
|
+
)
|
140
|
+
end
|
141
|
+
end
|
data/lib/osb/integer.rb
CHANGED
data/lib/osb/numeric.rb
CHANGED
data/lib/osb/sample.rb
CHANGED
data/lib/osb/sprite.rb
CHANGED
data/lib/osb/storyboard.rb
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Osb
|
4
|
-
# @
|
4
|
+
# @private
|
5
5
|
module Internal
|
6
|
-
# @
|
6
|
+
# @private
|
7
7
|
class LayerManager
|
8
8
|
attr_reader :background,
|
9
9
|
:foreground,
|
@@ -71,7 +71,7 @@ module Osb
|
|
71
71
|
# +Osb::Storyboard+ object, but we recommend you to split the project into multiple
|
72
72
|
# +Osb::Group+ so it will be easier to manage.
|
73
73
|
class Group
|
74
|
-
# @
|
74
|
+
# @private
|
75
75
|
attr_reader :layers
|
76
76
|
|
77
77
|
def initialize
|
@@ -115,11 +115,11 @@ module Osb
|
|
115
115
|
end
|
116
116
|
end
|
117
117
|
|
118
|
-
# Represent
|
118
|
+
# Represent an osu! storyboard. Each sprite or animation can be added directly
|
119
119
|
# to the storyboard instance, or through an intermediate group. A group can
|
120
120
|
# have multiple nested groups in itself.
|
121
121
|
class Storyboard
|
122
|
-
# @
|
122
|
+
# @private
|
123
123
|
attr_reader :layers
|
124
124
|
|
125
125
|
def initialize
|
data/lib/osb/vector2.rb
CHANGED
@@ -10,14 +10,16 @@ module Osb
|
|
10
10
|
# @return y coordinate of this vector
|
11
11
|
|
12
12
|
# @param [Numeric, Array<Numeric>] x
|
13
|
-
# x coordinate of this +Vector2+, or an +Array+ of 2 numbers.
|
14
|
-
# @param [Numeric] y y coordinate of this +Vector2+
|
13
|
+
# x coordinate of this +{Vector2}+, or an +Array+ of 2 numbers.
|
14
|
+
# @param [Numeric] y y coordinate of this +{Vector2}+
|
15
15
|
def initialize(x = 0, y = 0)
|
16
16
|
Internal.assert_type!(x, [Numeric, Internal::T[Array][Numeric]], "x")
|
17
17
|
Internal.assert_type!(y, Numeric, "y")
|
18
18
|
|
19
19
|
if x.is_a?(Array)
|
20
|
-
|
20
|
+
if x.size != 2
|
21
|
+
raise InvalidValueError, "Must be an Array of 2 Numeric values."
|
22
|
+
end
|
21
23
|
@x = x[0]
|
22
24
|
@y = x[1]
|
23
25
|
else
|
@@ -26,7 +28,7 @@ module Osb
|
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
29
|
-
# Add another +Vector2+ to this one.
|
31
|
+
# Add another +{Vector2}+ to this one.
|
30
32
|
# @param [Vector2] vector
|
31
33
|
# @return [Vector2]
|
32
34
|
def +(vector)
|
@@ -34,7 +36,7 @@ module Osb
|
|
34
36
|
Vector2.new(self.x + vector.x, self.y + vector.y)
|
35
37
|
end
|
36
38
|
|
37
|
-
# Subtract another +Vector2+ from this one.
|
39
|
+
# Subtract another +{Vector2}+ from this one.
|
38
40
|
# @param [Vector2] vector
|
39
41
|
# @return [Vector2]
|
40
42
|
def -(vector)
|
@@ -42,7 +44,7 @@ module Osb
|
|
42
44
|
Vector2.new(self.x - vector.x, self.y - vector.y)
|
43
45
|
end
|
44
46
|
|
45
|
-
# Returns whether two +Vector2+ are equal within tolerance
|
47
|
+
# Returns whether two +{Vector2}+ are equal within tolerance
|
46
48
|
# @param [Vector2] vector
|
47
49
|
# @return [Boolean]
|
48
50
|
def ==(vector)
|
@@ -50,14 +52,14 @@ module Osb
|
|
50
52
|
Math.fuzzy_equal(self.x, vector.x) && Math.fuzzy_equal(self.y, vector.y)
|
51
53
|
end
|
52
54
|
|
53
|
-
# Returns whether two +Vector2+ are not equal within tolerance
|
55
|
+
# Returns whether two +{Vector2}+ are not equal within tolerance
|
54
56
|
# @param [Vector2] vector
|
55
57
|
# @return [Boolean]
|
56
58
|
def !=(vector)
|
57
59
|
!(self == vector)
|
58
60
|
end
|
59
61
|
|
60
|
-
# Makes a copy of this +Vector2+.
|
62
|
+
# Makes a copy of this +{Vector2}+.
|
61
63
|
# @return [Vector2]
|
62
64
|
def clone
|
63
65
|
Vector2.new(self.x, self.y)
|
@@ -69,16 +71,24 @@ module Osb
|
|
69
71
|
[self.x, self.y]
|
70
72
|
end
|
71
73
|
|
72
|
-
# Returns a string representation of this +Vector2+.
|
74
|
+
# Returns a string representation of this +{Vector2}+.
|
73
75
|
# @return [String]
|
74
76
|
def to_s
|
75
77
|
self.to_a.to_s
|
76
78
|
end
|
77
79
|
|
78
|
-
# Returns the length of this +Vector2+.
|
80
|
+
# Returns the length of this +{Vector2}+.
|
79
81
|
# @return [Float]
|
80
82
|
def length
|
81
83
|
Math.sqrt(self.x**2 + self.y**2)
|
82
84
|
end
|
83
85
|
end
|
86
|
+
|
87
|
+
# Create a +{Vector2}+.
|
88
|
+
# @param [Numeric, Array<Numeric>] x
|
89
|
+
# x coordinate of this +{Vector2}+, or an +Array+ of 2 numbers.
|
90
|
+
# @param [Numeric] y y coordinate of this +{Vector2}+
|
91
|
+
def vec2(x = 0, y = 0)
|
92
|
+
Vector2.new(x, y)
|
93
|
+
end
|
84
94
|
end
|
data/lib/osb/video.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
module Osb
|
2
|
-
#
|
2
|
+
# Background video.
|
3
3
|
class Video
|
4
|
-
# @
|
4
|
+
# @private
|
5
5
|
attr_reader :commands, :layer
|
6
6
|
|
7
|
-
# @param [String] file_path location of the
|
7
|
+
# @param [String] file_path location of the video file relative to the beatmap directory.
|
8
8
|
# @param [Integer] start_time when the video starts.
|
9
9
|
def initialize(file_path:, start_time:)
|
10
10
|
Internal.assert_type!(file_path, String, "file_path")
|
11
|
-
Internal.assert_file_name_ext!(file_path,
|
11
|
+
Internal.assert_file_name_ext!(file_path, "mp4")
|
12
12
|
Internal.assert_type!(start_time, Integer, "start_time")
|
13
13
|
|
14
14
|
@command = "1,#{start_time},\"#{file_path}\""
|
data/lib/osb.rb
CHANGED
@@ -16,7 +16,12 @@ require_relative "osb/sample"
|
|
16
16
|
require_relative "osb/video"
|
17
17
|
require_relative "osb/background"
|
18
18
|
require_relative "osb/storyboard"
|
19
|
+
require_relative "osb/dsl/object"
|
20
|
+
require_relative "osb/dsl/commands"
|
19
21
|
|
20
22
|
module Osb
|
21
|
-
VERSION = "1.0
|
23
|
+
VERSION = "1.1.0"
|
22
24
|
end
|
25
|
+
|
26
|
+
# Extend the main object with the DSL commands.
|
27
|
+
extend Osb
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: osb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dinh Vu
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-08-
|
11
|
+
date: 2023-08-21 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A simple framework for building osu! storyboard.
|
14
14
|
email: dinhvu2509@gmail.com
|
@@ -22,6 +22,8 @@ files:
|
|
22
22
|
- lib/osb/background.rb
|
23
23
|
- lib/osb/color.rb
|
24
24
|
- lib/osb/commandable.rb
|
25
|
+
- lib/osb/dsl/commands.rb
|
26
|
+
- lib/osb/dsl/object.rb
|
25
27
|
- lib/osb/enums/easing.rb
|
26
28
|
- lib/osb/enums/layer.rb
|
27
29
|
- lib/osb/enums/origin.rb
|
@@ -52,7 +54,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
52
54
|
- !ruby/object:Gem::Version
|
53
55
|
version: '0'
|
54
56
|
requirements: []
|
55
|
-
rubygems_version: 3.
|
57
|
+
rubygems_version: 3.4.18
|
56
58
|
signing_key:
|
57
59
|
specification_version: 4
|
58
60
|
summary: osu! storyboard framework
|