adventure_rl 0.0.1.pre.ld42
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 +7 -0
- data/.gitignore +12 -0
- data/.travis.yml +5 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +47 -0
- data/LICENSE.txt +21 -0
- data/README.md +31 -0
- data/Rakefile +11 -0
- data/adventure_rl.gemspec +48 -0
- data/bin/console +7 -0
- data/bin/mkaudio +196 -0
- data/bin/mkclip +223 -0
- data/bin/rdoc +9 -0
- data/bin/setup +8 -0
- data/bin/vimall +5 -0
- data/doc/Mask.md +183 -0
- data/doc/Point.md +95 -0
- data/doc/Window.md +139 -0
- data/lib/AdventureRL/Animation.rb +63 -0
- data/lib/AdventureRL/Audio.rb +75 -0
- data/lib/AdventureRL/AudioPlayer.rb +65 -0
- data/lib/AdventureRL/Button.rb +51 -0
- data/lib/AdventureRL/Clip.rb +91 -0
- data/lib/AdventureRL/ClipPlayer.rb +187 -0
- data/lib/AdventureRL/Deltatime.rb +51 -0
- data/lib/AdventureRL/EventHandlers/Buttons.rb +225 -0
- data/lib/AdventureRL/EventHandlers/EventHandler.rb +62 -0
- data/lib/AdventureRL/EventHandlers/MouseButtons.rb +142 -0
- data/lib/AdventureRL/Events/Event.rb +69 -0
- data/lib/AdventureRL/Events/Mouse.rb +60 -0
- data/lib/AdventureRL/FileGroup.rb +100 -0
- data/lib/AdventureRL/FileGroupPlayer.rb +226 -0
- data/lib/AdventureRL/Helpers/Error.rb +68 -0
- data/lib/AdventureRL/Helpers/MethodHelper.rb +20 -0
- data/lib/AdventureRL/Helpers/PipeMethods.rb +26 -0
- data/lib/AdventureRL/Image.rb +77 -0
- data/lib/AdventureRL/Layer.rb +273 -0
- data/lib/AdventureRL/Mask.rb +462 -0
- data/lib/AdventureRL/Menu.rb +92 -0
- data/lib/AdventureRL/Modifiers/Gravity.rb +60 -0
- data/lib/AdventureRL/Modifiers/Inventory.rb +104 -0
- data/lib/AdventureRL/Modifiers/Pusher.rb +61 -0
- data/lib/AdventureRL/Modifiers/Solid.rb +302 -0
- data/lib/AdventureRL/Modifiers/Velocity.rb +163 -0
- data/lib/AdventureRL/Point.rb +188 -0
- data/lib/AdventureRL/Quadtree.rb +237 -0
- data/lib/AdventureRL/Rectangle.rb +62 -0
- data/lib/AdventureRL/Settings.rb +80 -0
- data/lib/AdventureRL/SolidsManager.rb +170 -0
- data/lib/AdventureRL/Textbox.rb +195 -0
- data/lib/AdventureRL/TimingHandler.rb +225 -0
- data/lib/AdventureRL/Window.rb +152 -0
- data/lib/AdventureRL/misc/extensions.rb +80 -0
- data/lib/AdventureRL/misc/require_files.rb +45 -0
- data/lib/AdventureRL/version.rb +3 -0
- data/lib/adventure_rl.rb +22 -0
- data/lib/default_settings.yml +20 -0
- data/vimrc +4 -0
- metadata +237 -0
@@ -0,0 +1,170 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
class SolidsManager
|
3
|
+
DEFAULT_SOLID_TAG = :default
|
4
|
+
|
5
|
+
DEFAULT_SETTINGS = Settings.new(
|
6
|
+
use_cache: false
|
7
|
+
)
|
8
|
+
|
9
|
+
def initialize settings = {}
|
10
|
+
@settings = DEFAULT_SETTINGS.merge settings
|
11
|
+
@quadtrees = {}
|
12
|
+
@reset_queue = {}
|
13
|
+
@cache = {}
|
14
|
+
@use_cache = @settings.get :use_cache
|
15
|
+
end
|
16
|
+
|
17
|
+
# Add one (or multiple) <tt>object</tt>(s)
|
18
|
+
# with one (or multiple) <tt>solid_tag</tt>(s).
|
19
|
+
def add_object object, solid_tag = DEFAULT_SOLID_TAG
|
20
|
+
objects = [object].flatten
|
21
|
+
solid_tags = [solid_tag].flatten
|
22
|
+
solid_tags.each do |tag|
|
23
|
+
if (@quadtrees[tag])
|
24
|
+
@quadtrees[tag].add_object objects
|
25
|
+
else
|
26
|
+
@quadtrees[tag] = Quadtree.new objects: objects
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
alias_method :add, :add_object
|
31
|
+
|
32
|
+
def remove_object object, solid_tag = DEFAULT_SOLID_TAG
|
33
|
+
objects = [object].flatten
|
34
|
+
solid_tags = [solid_tag].flatten
|
35
|
+
objects.each do |obj|
|
36
|
+
@cache.delete obj
|
37
|
+
end
|
38
|
+
get_quadtrees_for(solid_tags).each do |quadtree|
|
39
|
+
quadtree.remove_object objects
|
40
|
+
end
|
41
|
+
end
|
42
|
+
alias_method :remove, :remove_object
|
43
|
+
|
44
|
+
def remove_object_from_all_quadtrees object
|
45
|
+
objects = [object].flatten
|
46
|
+
objects.each do |obj|
|
47
|
+
@cache.delete obj
|
48
|
+
end
|
49
|
+
@quadtrees.values.flatten.each do |quadtree|
|
50
|
+
quadtree.remove_object objects
|
51
|
+
end
|
52
|
+
end
|
53
|
+
alias_method :remove_from_all_quadtrees, :remove_object_from_all_quadtrees
|
54
|
+
|
55
|
+
# Returns <tt>true</tt> if the given <tt>object</tt> (or multiple objects),
|
56
|
+
# collide with any other objects with a mutual <tt>solid_tag</tt>.
|
57
|
+
def collides? object, solid_tag = DEFAULT_SOLID_TAG
|
58
|
+
objects = [object].flatten
|
59
|
+
solid_tags = [solid_tag].flatten
|
60
|
+
return objects.any? do |obj|
|
61
|
+
handle_collides_cache_for obj, solid_tags
|
62
|
+
next @cache[obj][:collides?]
|
63
|
+
end if (@use_cache)
|
64
|
+
return objects.any? do |obj|
|
65
|
+
next get_quadtrees_for(solid_tags).any? do |quadtree|
|
66
|
+
next quadtree.collides?(obj)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns all objects colliding with <tt>object</tt>(s).
|
72
|
+
def get_colliding_objects object, solid_tag = DEFAULT_SOLID_TAG
|
73
|
+
objects = [object].flatten
|
74
|
+
solid_tags = [solid_tag].flatten
|
75
|
+
return objects.map do |obj|
|
76
|
+
handle_colliding_objects_cache_for obj, solid_tags
|
77
|
+
next @cache[obj][:colliding_objects]
|
78
|
+
end .flatten if (@use_cache)
|
79
|
+
return objects.map do |obj|
|
80
|
+
next get_quadtrees_for(solid_tags).map do |quadtree|
|
81
|
+
next quadtree.get_colliding_objects(obj)
|
82
|
+
end
|
83
|
+
end .flatten
|
84
|
+
end
|
85
|
+
|
86
|
+
# Pass an <tt>object</tt> (or multiple), to queue it/them for
|
87
|
+
# resetting next update.
|
88
|
+
def reset_object object, solid_tag = DEFAULT_SOLID_TAG
|
89
|
+
objects = [object].flatten
|
90
|
+
solid_tags = [solid_tag].flatten
|
91
|
+
solid_tags.each do |tag|
|
92
|
+
@reset_queue[tag] ||= []
|
93
|
+
@reset_queue[tag].concat objects
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# Resets for every object in <tt>@reset_queue</tt>.
|
98
|
+
def reset
|
99
|
+
@reset_queue.each do |solid_tag, objects|
|
100
|
+
@quadtrees.map do |quadtree_tag, quadtree|
|
101
|
+
next quadtree if (solid_tag == quadtree_tag)
|
102
|
+
next nil
|
103
|
+
end .compact.each do |quadtree|
|
104
|
+
quadtree.reset_object objects
|
105
|
+
end
|
106
|
+
@reset_queue[solid_tag] = []
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def reset_cache_for object
|
111
|
+
@collides_cache.delete object
|
112
|
+
@colliding_objects_cache.delete object
|
113
|
+
end
|
114
|
+
|
115
|
+
# Called once every frame by Window.
|
116
|
+
def update
|
117
|
+
reset
|
118
|
+
end
|
119
|
+
|
120
|
+
private
|
121
|
+
|
122
|
+
def get_quadtrees_for solid_tag = DEFAULT_SOLID_TAG
|
123
|
+
solid_tags = [solid_tag].flatten
|
124
|
+
return @quadtrees.map do |quadtree_tag, quadtree|
|
125
|
+
next quadtree if (solid_tags.include?(quadtree_tag))
|
126
|
+
next nil
|
127
|
+
end .compact
|
128
|
+
end
|
129
|
+
|
130
|
+
def handle_collides_cache_for object, solid_tags
|
131
|
+
cached = @cache[object]
|
132
|
+
update_collides_cache_for object, solid_tags unless (
|
133
|
+
# TODO: Remove cache or improve, it can break stuff
|
134
|
+
@use_cache &&
|
135
|
+
cached &&
|
136
|
+
(cached[:position] == object.get_position) &&
|
137
|
+
(cached[:size] == object.get_size)
|
138
|
+
)
|
139
|
+
end
|
140
|
+
|
141
|
+
def update_collides_cache_for object, solid_tags
|
142
|
+
@cache[object] ||= {}
|
143
|
+
@cache[object][:position] = object.get_position.dup
|
144
|
+
@cache[object][:size] = object.get_size.dup
|
145
|
+
@cache[object][:collides?] = get_quadtrees_for(solid_tags).any? do |quadtree|
|
146
|
+
next quadtree.collides?(object)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
def handle_colliding_objects_cache_for object, solid_tags
|
151
|
+
cached = @cache[object]
|
152
|
+
update_colliding_objects_cache_for object, solid_tags unless (
|
153
|
+
# TODO: Remove cache or improve, it can break stuff
|
154
|
+
@use_cache &&
|
155
|
+
cached &&
|
156
|
+
(cached[:position] == object.get_position) &&
|
157
|
+
(cached[:size] == object.get_size)
|
158
|
+
)
|
159
|
+
end
|
160
|
+
|
161
|
+
def update_colliding_objects_cache_for object, solid_tags
|
162
|
+
@cache[object] ||= {}
|
163
|
+
@cache[object][:position] = object.get_position.dup
|
164
|
+
@cache[object][:size] = object.get_size.dup
|
165
|
+
@cache[object][:colliding_objects] = get_quadtrees_for(solid_tags).map do |quadtree|
|
166
|
+
next quadtree.get_colliding_objects(object)
|
167
|
+
end .flatten
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
@@ -0,0 +1,195 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
# This is similar to a Rectangle, but it can display text
|
3
|
+
# with basic formatting.
|
4
|
+
class Textbox < Rectangle
|
5
|
+
DEFAULT_SETTINGS = Settings.new(
|
6
|
+
text: '',
|
7
|
+
font_size: 24,
|
8
|
+
font_name: 'MonoSpace',
|
9
|
+
font_color: 0xff_ffffff,
|
10
|
+
text_alignment: {
|
11
|
+
x: :center,
|
12
|
+
y: :center
|
13
|
+
},
|
14
|
+
border_padding: {
|
15
|
+
x: 16,
|
16
|
+
y: 8
|
17
|
+
},
|
18
|
+
border_color: 0xff_000000,
|
19
|
+
border_size: {
|
20
|
+
width: 0,
|
21
|
+
height: 0
|
22
|
+
},
|
23
|
+
background_color: 0xff_000000,
|
24
|
+
z_index: 0,
|
25
|
+
position: {
|
26
|
+
x: 0,
|
27
|
+
y: 0
|
28
|
+
},
|
29
|
+
size: {
|
30
|
+
width: 256,
|
31
|
+
height: 64
|
32
|
+
},
|
33
|
+
origin: {
|
34
|
+
x: :left,
|
35
|
+
y: :top
|
36
|
+
}
|
37
|
+
)
|
38
|
+
|
39
|
+
def initialize settings = {}
|
40
|
+
@settings = DEFAULT_SETTINGS.merge settings
|
41
|
+
@font_cache = {} # This Hash will be filled with any loaded Gosu::Font (see #set_font_size)
|
42
|
+
set_font_size @settings.get(:font_size)
|
43
|
+
@text = @settings.get :text
|
44
|
+
@font_color = @settings.get :font_color
|
45
|
+
@text_alignment = @settings.get :text_alignment
|
46
|
+
@border_padding = @settings.get :border_padding
|
47
|
+
@border_color = @settings.get :border_color
|
48
|
+
@border_size = @settings.get :border_size
|
49
|
+
super @settings
|
50
|
+
@color_original = @settings.get :background_color
|
51
|
+
end
|
52
|
+
|
53
|
+
def get_text
|
54
|
+
return @text
|
55
|
+
end
|
56
|
+
|
57
|
+
def set_text text
|
58
|
+
@text = text.to_s
|
59
|
+
end
|
60
|
+
|
61
|
+
# NOTE:
|
62
|
+
# This method is expensive, because it loads a new Gosu::Font.
|
63
|
+
# Call this sparingly.
|
64
|
+
# Once a new Gosu::Font is created, it is cached,
|
65
|
+
# wo when you resize to a previously used font it will not need to load a new Gosu::Font.
|
66
|
+
def set_font_size size
|
67
|
+
@font = @font_cache[size]
|
68
|
+
return if (@font)
|
69
|
+
@font = Gosu::Font.new(
|
70
|
+
size,
|
71
|
+
name: @settings.get(:font_name)
|
72
|
+
)
|
73
|
+
@font_cache[size] = @font
|
74
|
+
end
|
75
|
+
|
76
|
+
# TODO: This doesn't really work, it still takes a while to draw a Font the first time; look into this.
|
77
|
+
# Pass any amount of integers, which will each preload a new Gosu::Font,
|
78
|
+
# with the size of the integer.
|
79
|
+
def preload_font_sizes *sizes
|
80
|
+
sizes.flatten.each do |size|
|
81
|
+
Helpers::Error.error(
|
82
|
+
"Expected size to be an Integer, but got",
|
83
|
+
"`#{size.inspect}:#{size.class.name}'."
|
84
|
+
) unless (size.is_a? Integer)
|
85
|
+
@font_cache[size] ||= Gosu::Font.new(
|
86
|
+
size,
|
87
|
+
name: @settings.get(:font_name)
|
88
|
+
)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def draw
|
93
|
+
draw_border
|
94
|
+
draw_background
|
95
|
+
draw_text
|
96
|
+
@color_temporary = nil
|
97
|
+
end
|
98
|
+
|
99
|
+
private
|
100
|
+
|
101
|
+
def draw_border
|
102
|
+
return unless (has_border?)
|
103
|
+
corner = get_corner :left, :top
|
104
|
+
Gosu.draw_rect(
|
105
|
+
corner.x, corner.y,
|
106
|
+
get_size(:width), get_size(:height),
|
107
|
+
@border_color,
|
108
|
+
@z_index
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
def draw_background
|
113
|
+
pos = get_position_for_background
|
114
|
+
size = get_size_for_background
|
115
|
+
Gosu.draw_rect(
|
116
|
+
pos.x, pos.y,
|
117
|
+
size[:width], size[:height],
|
118
|
+
get_color,
|
119
|
+
@z_index
|
120
|
+
)
|
121
|
+
end
|
122
|
+
|
123
|
+
def draw_text
|
124
|
+
pos = get_position_for_text
|
125
|
+
rel = get_relative_for_text
|
126
|
+
@font.draw_rel(
|
127
|
+
@text,
|
128
|
+
pos[:x], pos[:y], @z_index,
|
129
|
+
rel[:x], rel[:y],
|
130
|
+
1, 1, # Scale
|
131
|
+
@font_color
|
132
|
+
)
|
133
|
+
end
|
134
|
+
|
135
|
+
def has_border?
|
136
|
+
return @border_size.values.any? do |size|
|
137
|
+
next size > 0
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def get_position_for_background
|
142
|
+
corner = get_corner :left, :top
|
143
|
+
return corner unless (has_border?)
|
144
|
+
pos = corner.dup
|
145
|
+
pos.set_position(
|
146
|
+
x: (corner.x + @border_size[:width]),
|
147
|
+
y: (corner.y + @border_size[:height])
|
148
|
+
)
|
149
|
+
return pos
|
150
|
+
end
|
151
|
+
|
152
|
+
def get_size_for_background
|
153
|
+
size = get_size
|
154
|
+
return size unless (has_border?)
|
155
|
+
return {
|
156
|
+
width: (size[:width] - (@border_size[:width] * 2)),
|
157
|
+
height: (size[:height] - (@border_size[:height] * 2))
|
158
|
+
}
|
159
|
+
end
|
160
|
+
|
161
|
+
def get_position_for_text
|
162
|
+
return [:x, :y].map do |axis|
|
163
|
+
alignment = @text_alignment[axis]
|
164
|
+
case alignment
|
165
|
+
when :center
|
166
|
+
pos = get_center axis
|
167
|
+
else
|
168
|
+
mult = 1 if ([:left, :top].include? alignment)
|
169
|
+
mult = -1 if ([:right, :bottom].include? alignment)
|
170
|
+
pos = (
|
171
|
+
(@border_size[(axis == :x) ? :width : :height] * mult) +
|
172
|
+
(@border_padding[axis] * mult) +
|
173
|
+
get_side(alignment)
|
174
|
+
)
|
175
|
+
end
|
176
|
+
next [axis, pos]
|
177
|
+
end .to_h
|
178
|
+
end
|
179
|
+
|
180
|
+
def get_relative_for_text
|
181
|
+
return [:x, :y].map do |axis|
|
182
|
+
alignment = @text_alignment[axis]
|
183
|
+
case alignment
|
184
|
+
when :center
|
185
|
+
pos = 0.5
|
186
|
+
when :left, :top
|
187
|
+
pos = 0.0
|
188
|
+
when :right, :bottom
|
189
|
+
pos = 1.0
|
190
|
+
end
|
191
|
+
next [axis, pos]
|
192
|
+
end .to_h
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
# The TimingHandler has nice methods to handle timing.
|
3
|
+
# It can #set_timeout or #set_interval for methods.
|
4
|
+
class TimingHandler
|
5
|
+
include Helpers::Error
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@queue = {
|
9
|
+
timeouts: [],
|
10
|
+
intervals: []
|
11
|
+
}
|
12
|
+
@elapsed_seconds = 0.0
|
13
|
+
@deltatime = Deltatime.new
|
14
|
+
@is_running = true
|
15
|
+
end
|
16
|
+
|
17
|
+
# #update should be called every frame,
|
18
|
+
# this is where it checks if any methods need to be called
|
19
|
+
# and calls them if necessary.
|
20
|
+
def update
|
21
|
+
return if (is_paused?)
|
22
|
+
handle_timeouts
|
23
|
+
handle_intervals
|
24
|
+
@elapsed_seconds += @deltatime.dt
|
25
|
+
@deltatime.update
|
26
|
+
end
|
27
|
+
|
28
|
+
def continue
|
29
|
+
return if (is_running?)
|
30
|
+
@is_running = true
|
31
|
+
reset
|
32
|
+
end
|
33
|
+
|
34
|
+
def pause
|
35
|
+
return if (is_paused?)
|
36
|
+
@is_running = false
|
37
|
+
end
|
38
|
+
|
39
|
+
def is_running?
|
40
|
+
return !!@is_running
|
41
|
+
end
|
42
|
+
|
43
|
+
def is_paused?
|
44
|
+
return !is_running?
|
45
|
+
end
|
46
|
+
|
47
|
+
# Reset the Deltatime
|
48
|
+
def reset
|
49
|
+
@deltatime.reset
|
50
|
+
end
|
51
|
+
|
52
|
+
# Set a timeout for a method.
|
53
|
+
# Call a method after a specified amount of time has passed.
|
54
|
+
# The passed <tt>args</tt> Hash should include the following keys:
|
55
|
+
# <tt>:method</tt>:: The method to be called. Can be one of the following:
|
56
|
+
# - a Method -- <tt>method(:my_method)</tt>
|
57
|
+
# - a Proc -- <tt>Proc.new { puts 'My method!' }</tt>
|
58
|
+
# - a method name as a Symbol -- <tt>:my_method</tt>
|
59
|
+
# <tt>:seconds</tt> _or_ <tt>:secs</tt>:: Integer or Float. The time to wait in seconds, before calling the method.
|
60
|
+
# <tt>:arguments</tt> _or_ <tt>:args</tt>:: Optional Array of arguments, which will be passed to the target method.
|
61
|
+
# <tt>:id</tt>:: Optional value which can be used to remove the timeout afterwards. See #remove_timeout.
|
62
|
+
# You can also pass a block to the method,
|
63
|
+
# which will be used instead of the <tt>:method</tt> key's value.
|
64
|
+
def set_timeout args = {}, &block
|
65
|
+
validate_args args, !!block
|
66
|
+
_args = get_unified_args args, &block
|
67
|
+
at = get_time_in _args[:seconds]
|
68
|
+
@queue[:timeouts] << {
|
69
|
+
method: _args[:method],
|
70
|
+
at: at,
|
71
|
+
arguments: _args[:arguments],
|
72
|
+
id: _args[:id]
|
73
|
+
}
|
74
|
+
end
|
75
|
+
alias_method :in, :set_timeout
|
76
|
+
|
77
|
+
# Set an interval for a method.
|
78
|
+
# Call a method in regular intervals.
|
79
|
+
# The passed <tt>args</tt> Hash should include the following keys:
|
80
|
+
# <tt>:method</tt>:: The method to be called. Can be one of the following:
|
81
|
+
# - a Method -- <tt>method(:my_method)</tt>
|
82
|
+
# - a Proc -- <tt>Proc.new { puts 'My method!' }</tt>
|
83
|
+
# - a method name as a Symbol -- <tt>:my_method</tt>
|
84
|
+
# <tt>:seconds</tt> _or_ <tt>:secs</tt>:: Integer or Float. The time to wait in seconds, before calling the method.
|
85
|
+
# <tt>:arguments</tt> _or_ <tt>:args</tt>:: Optional Array of arguments, which will be passed to the target method.
|
86
|
+
# <tt>:id</tt>:: Optional value which can be used to remove the interval afterwards. See #remove_interval.
|
87
|
+
# You can also pass a block to the method,
|
88
|
+
# which will be used instead of the <tt>:method</tt> key's value.
|
89
|
+
def set_interval args = {}, &block
|
90
|
+
validate_args args, !!block
|
91
|
+
_args = get_unified_args args, &block
|
92
|
+
at = get_time_in _args[:seconds]
|
93
|
+
@queue[:intervals] << {
|
94
|
+
method: _args[:method],
|
95
|
+
interval: _args[:seconds],
|
96
|
+
at: at,
|
97
|
+
arguments: _args[:arguments],
|
98
|
+
id: _args[:id]
|
99
|
+
}
|
100
|
+
end
|
101
|
+
alias_method :every, :set_interval
|
102
|
+
|
103
|
+
# If you passed an <tt>:id</tt> to your timeout when you set it with #set_timeout,
|
104
|
+
# then you can remove / clear it before it executes by calling this method and
|
105
|
+
# passing the same <tt>id</tt>.
|
106
|
+
def remove_timeout id
|
107
|
+
@queue[:timeouts].reject! do |timeout|
|
108
|
+
next timeout[:id] == id
|
109
|
+
end
|
110
|
+
end
|
111
|
+
alias_method :clear_timeout, :remove_timeout
|
112
|
+
|
113
|
+
# If you passed an <tt>:id</tt> to your interval when you set it with #set_interval,
|
114
|
+
# then you can remove / clear it by calling this method and
|
115
|
+
# passing the same <tt>id</tt>.
|
116
|
+
# If you did _not_ pass an <tt>id</tt>, then your interval will be running endlessly!
|
117
|
+
def remove_interval id
|
118
|
+
@queue[:intervals].reject! do |interval|
|
119
|
+
next interval[:id] == id
|
120
|
+
end
|
121
|
+
end
|
122
|
+
alias_method :clear_interval, :remove_interval
|
123
|
+
|
124
|
+
# Returns <tt>true</tt> if the given <tt>id</tt> exists as a timeout,
|
125
|
+
# and <tt>false</tt> if not.
|
126
|
+
def has_timeout? id
|
127
|
+
return @queue[:timeouts].any? do |timeout|
|
128
|
+
next timeout[:id] == id
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Returns <tt>true</tt> if the given <tt>id</tt> exists as an interval,
|
133
|
+
# and <tt>false</tt> if not.
|
134
|
+
def has_interval? id
|
135
|
+
return @queue[:intervals].any? do |interval|
|
136
|
+
next interval[:id] == id
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
private
|
141
|
+
|
142
|
+
def handle_timeouts
|
143
|
+
current_seconds = get_elapsed_seconds
|
144
|
+
@queue[:timeouts].reject! do |timeout|
|
145
|
+
next false unless (current_seconds >= timeout[:at])
|
146
|
+
timeout[:method].call *timeout[:arguments]
|
147
|
+
next true
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def handle_intervals
|
152
|
+
current_seconds = get_elapsed_seconds
|
153
|
+
@queue[:intervals].each do |interval|
|
154
|
+
next unless (current_seconds >= interval[:at])
|
155
|
+
interval[:method].call *interval[:arguments]
|
156
|
+
interval[:at] = get_time_in interval[:interval]
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def validate_args args, block_given = false
|
161
|
+
error(
|
162
|
+
"Passed argument must be a Hash."
|
163
|
+
) unless (args.is_a? Hash)
|
164
|
+
unless (block_given)
|
165
|
+
error(
|
166
|
+
"Passed args Hash must include the key `:method'."
|
167
|
+
) unless (args.key? :method)
|
168
|
+
method_class = args[:method].class
|
169
|
+
error(
|
170
|
+
"Key `:method' must be a Method, Proc, or Symbol, but is a `#{method_class.name}'"
|
171
|
+
) unless ([Method, Proc, Symbol].include? method_class)
|
172
|
+
end
|
173
|
+
error(
|
174
|
+
"Passed args Hash must include the key `:seconds' or `:secs'."
|
175
|
+
) unless (args.key?(:seconds) || args.key?(:secs))
|
176
|
+
seconds_key = :secs if (args.key? :secs)
|
177
|
+
seconds_key = :seconds if (args.key? :seconds)
|
178
|
+
seconds_class = args[seconds_key].class
|
179
|
+
error(
|
180
|
+
"Key `:#{seconds_key.to_s}' must be an Integer or Float, but is a `#{seconds_class.name}'"
|
181
|
+
) unless ([Integer, Float].include? seconds_class)
|
182
|
+
if (args.key?(:arguments) || args.key?(:args))
|
183
|
+
arguments_key = :args if (args.key? :args)
|
184
|
+
arguments_key = :arguments if (args.key? :arguments)
|
185
|
+
arguments_class = args[arguments_key].class
|
186
|
+
error(
|
187
|
+
"Key `:#{arguments_key.to_s}' must be an Array, but is a `#{arguments_class.name}'"
|
188
|
+
) unless (arguments_class == Array)
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
def get_unified_args args, &block
|
193
|
+
prc = get_proc_from(block || args[:method])
|
194
|
+
return {
|
195
|
+
method: prc,
|
196
|
+
seconds: args[:seconds] || args[:secs],
|
197
|
+
arguments: args[:arguments] || args[:args] || [],
|
198
|
+
id: args[:id]
|
199
|
+
}
|
200
|
+
end
|
201
|
+
|
202
|
+
def get_proc_from meth
|
203
|
+
prc = nil
|
204
|
+
if (meth.is_a? Method)
|
205
|
+
prc = meth.to_proc
|
206
|
+
elsif (meth.is_a? Proc)
|
207
|
+
prc = meth
|
208
|
+
elsif (meth.is_a? Symbol)
|
209
|
+
error(
|
210
|
+
"Method `:#{meth.to_s}' is not available in this scope."
|
211
|
+
) unless (methods.include? meth)
|
212
|
+
prc = method(meth).to_proc
|
213
|
+
end
|
214
|
+
return prc
|
215
|
+
end
|
216
|
+
|
217
|
+
def get_time_in seconds
|
218
|
+
return get_elapsed_seconds + seconds
|
219
|
+
end
|
220
|
+
|
221
|
+
def get_elapsed_seconds
|
222
|
+
return @elapsed_seconds
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|