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,142 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
module EventHandlers
|
3
|
+
class MouseButtons < Buttons
|
4
|
+
# This constant contains the IDs of all mouse buttons.
|
5
|
+
MOUSE_BUTTON_IDS = [
|
6
|
+
Gosu::MS_LEFT,
|
7
|
+
Gosu::MS_MIDDLE,
|
8
|
+
Gosu::MS_RIGHT,
|
9
|
+
Gosu::MS_WHEEL_DOWN,
|
10
|
+
Gosu::MS_WHEEL_UP
|
11
|
+
] .concat((0 .. 7).map do |n|
|
12
|
+
next Gosu.const_get "MS_OTHER_#{n.to_s}"
|
13
|
+
end)
|
14
|
+
|
15
|
+
DEFAULT_SETTINGS = Settings.new(
|
16
|
+
only_mouse_buttons: true
|
17
|
+
)
|
18
|
+
|
19
|
+
def initialize settings = {}
|
20
|
+
@settings = DEFAULT_SETTINGS.merge settings
|
21
|
+
@only_mouse_buttons = @settings.get :only_mouse_buttons
|
22
|
+
super @settings
|
23
|
+
end
|
24
|
+
|
25
|
+
def button_down btnid
|
26
|
+
super unless (@only_mouse_buttons)
|
27
|
+
trigger(
|
28
|
+
:mouse_down,
|
29
|
+
get_semantic_button_name(btnid),
|
30
|
+
shift: shift_button_pressed?,
|
31
|
+
control: control_button_pressed?,
|
32
|
+
alt: alt_button_pressed?
|
33
|
+
) if (MOUSE_BUTTON_IDS.include?(btnid))
|
34
|
+
end
|
35
|
+
|
36
|
+
def button_up btnid
|
37
|
+
return unless (MOUSE_BUTTON_IDS.include? btnid)
|
38
|
+
trigger(
|
39
|
+
:mouse_up,
|
40
|
+
get_semantic_button_name(btnid),
|
41
|
+
shift: shift_button_pressed?,
|
42
|
+
control: control_button_pressed?,
|
43
|
+
alt: alt_button_pressed?
|
44
|
+
)
|
45
|
+
end
|
46
|
+
|
47
|
+
def update
|
48
|
+
pressed_btnids = MOUSE_BUTTON_IDS.select do |btnid|
|
49
|
+
next Gosu.button_down?(btnid)
|
50
|
+
end
|
51
|
+
return unless (pressed_btnids.any?)
|
52
|
+
pressed_btnids.each do |btnid|
|
53
|
+
trigger(
|
54
|
+
:mouse_press,
|
55
|
+
get_semantic_button_name(btnid),
|
56
|
+
shift: shift_button_pressed?,
|
57
|
+
control: control_button_pressed?,
|
58
|
+
alt: alt_button_pressed?
|
59
|
+
)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def add_pressable_button *args
|
64
|
+
Helpers::Error.error(
|
65
|
+
"Cannot add pressable button(s) to #{self.class.name}."
|
66
|
+
)
|
67
|
+
end
|
68
|
+
|
69
|
+
private
|
70
|
+
|
71
|
+
def get_events
|
72
|
+
return super.concat([
|
73
|
+
get_event_mouse_down,
|
74
|
+
get_event_mouse_up,
|
75
|
+
get_event_mouse_press
|
76
|
+
])
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_event_mouse_down
|
80
|
+
event = Events::Mouse.new(:mouse_down)
|
81
|
+
event.on_trigger do |object, btn_name, mod_keys|
|
82
|
+
next unless (object.methods.include?(:on_mouse_down) && object.collides_with?(get_mouse_point))
|
83
|
+
case object.method(:on_mouse_down).arity.abs
|
84
|
+
when 0
|
85
|
+
object.on_mouse_down
|
86
|
+
when 1
|
87
|
+
object.on_mouse_down btn_name
|
88
|
+
when 2
|
89
|
+
object.on_mouse_down btn_name, mod_keys
|
90
|
+
end
|
91
|
+
end
|
92
|
+
return event
|
93
|
+
end
|
94
|
+
|
95
|
+
def get_event_mouse_up
|
96
|
+
event = Events::Mouse.new(:mouse_up)
|
97
|
+
event.on_trigger do |object, btn_name, mod_keys|
|
98
|
+
next unless (object.methods.include?(:on_mouse_up) && object.collides_with?(get_mouse_point))
|
99
|
+
case object.method(:on_mouse_up).arity.abs
|
100
|
+
when 0
|
101
|
+
object.on_mouse_up
|
102
|
+
when 1
|
103
|
+
object.on_mouse_up btn_name
|
104
|
+
when 2
|
105
|
+
object.on_mouse_up btn_name, mod_keys
|
106
|
+
end
|
107
|
+
end
|
108
|
+
return event
|
109
|
+
end
|
110
|
+
|
111
|
+
def get_event_mouse_press
|
112
|
+
event = Events::Mouse.new(:mouse_press)
|
113
|
+
event.on_trigger do |object, btn_name, mod_keys|
|
114
|
+
next unless (object.methods.include?(:on_mouse_press) && object.collides_with?(get_mouse_point))
|
115
|
+
case object.method(:on_mouse_press).arity.abs
|
116
|
+
when 0
|
117
|
+
object.on_mouse_press
|
118
|
+
when 1
|
119
|
+
object.on_mouse_press btn_name
|
120
|
+
when 2
|
121
|
+
object.on_mouse_press btn_name, mod_keys
|
122
|
+
end
|
123
|
+
end
|
124
|
+
return event
|
125
|
+
end
|
126
|
+
|
127
|
+
def get_mouse_point
|
128
|
+
window = Window.get_window
|
129
|
+
return nil unless (window)
|
130
|
+
return Point.new(window.mouse_x, window.mouse_y)
|
131
|
+
end
|
132
|
+
|
133
|
+
def get_semantic_button_name btnid
|
134
|
+
return Gosu.constants.map do |constant_name|
|
135
|
+
constant = Gosu.const_get constant_name
|
136
|
+
next constant_name.to_s.sub(/^MS_/,'').downcase.to_sym if (constant == btnid && constant_name.match?(/_/))
|
137
|
+
next nil
|
138
|
+
end .compact.first
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
module Events
|
3
|
+
class Event
|
4
|
+
def initialize name
|
5
|
+
@name = name
|
6
|
+
@objects = []
|
7
|
+
@trigger_method = nil
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns the <tt>name</tt> of the Event.
|
11
|
+
def get_name
|
12
|
+
return @name
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the objects that subscribed to this Event. (see #add_object)
|
16
|
+
def get_objects
|
17
|
+
return @objects
|
18
|
+
end
|
19
|
+
|
20
|
+
# Add one or multiple <tt>object</tt>(s) to this Event.
|
21
|
+
def add_object object
|
22
|
+
[object].flatten.each do |obj|
|
23
|
+
Helpers::Error.error(
|
24
|
+
"Object `#{obj.inspect}:#{obj.class.name}' cannot be given",
|
25
|
+
"to this Event `#{self.inspect}:#{self.class.name}'."
|
26
|
+
) unless (valid_object? obj)
|
27
|
+
@objects << obj unless (@objects.include? obj)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
alias_method :add, :add_object
|
31
|
+
alias_method :<<, :add_object
|
32
|
+
|
33
|
+
# Remove one or multiple <tt>object</tt>(s) from this Event.
|
34
|
+
def remove_object object
|
35
|
+
[object].flatten.each do |obj|
|
36
|
+
@objects.delete obj
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Pass a block, which will be called when this Event is triggered (see #trigger).
|
41
|
+
# The passed block takes an argument, which is a subscribed object.
|
42
|
+
def on_trigger &block
|
43
|
+
Helpers::Error.error(
|
44
|
+
"Method #on_trigger needs a block to be passed."
|
45
|
+
) unless (block_given?)
|
46
|
+
@trigger_method = block
|
47
|
+
end
|
48
|
+
|
49
|
+
# The block defined with #on_trigger will be called
|
50
|
+
# for every subscribed object.
|
51
|
+
# Optionally, additional <tt>args</tt> arguments can be passed,
|
52
|
+
# which will be passed to the trigger method.
|
53
|
+
def trigger *args
|
54
|
+
get_objects.each do |object|
|
55
|
+
@trigger_method.call object, *args
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
# Returns <tt>true</tt> if the passed <tt>object</tt> can be given to this Event,
|
62
|
+
# and <tt>false</tt> if not.
|
63
|
+
# This method should be overwritten to fit specific requirements.
|
64
|
+
def valid_object? object
|
65
|
+
return !!object
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
module Events
|
3
|
+
class Mouse < Event
|
4
|
+
def initialize *args
|
5
|
+
super
|
6
|
+
@quadtree = Quadtree.new
|
7
|
+
end
|
8
|
+
|
9
|
+
# Overwrite the #add_object method, so we can
|
10
|
+
# reset the object in the Quadtree if necessary,
|
11
|
+
# via the object's #move_by method.
|
12
|
+
def add_object object
|
13
|
+
super
|
14
|
+
[object].flatten.each do |obj|
|
15
|
+
get_quadtree.add_object obj
|
16
|
+
mouse_event = self
|
17
|
+
obj.define_singleton_method :move_by do |*args|
|
18
|
+
previous_position = get_position.dup
|
19
|
+
super(*args)
|
20
|
+
mouse_event.get_quadtree.reset_object self if (get_position != previous_position)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Overwrite the #remove_object method, so we can
|
26
|
+
# also remove the object(s) from the Quadtree.
|
27
|
+
def remove_object object
|
28
|
+
super
|
29
|
+
[object].flatten.each do |obj|
|
30
|
+
get_quadtree.remove_object obj
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
# Overwrite the #trigger method, to perform a
|
35
|
+
# Quadtree query for objects colliding with the mouse pointer.
|
36
|
+
# For improved performance.
|
37
|
+
def trigger *args
|
38
|
+
get_colliding_objects.each do |object|
|
39
|
+
@trigger_method.call object, *args
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
def get_quadtree
|
44
|
+
return @quadtree
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def get_colliding_objects
|
50
|
+
return get_quadtree.get_colliding_objects_for get_mouse_point
|
51
|
+
end
|
52
|
+
|
53
|
+
def get_mouse_point
|
54
|
+
window = Window.get_window
|
55
|
+
return nil unless (window)
|
56
|
+
return Point.new(window.mouse_x, window.mouse_y)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
# This is an abstract class, which is inherited by
|
3
|
+
# - Clip
|
4
|
+
# - Audio
|
5
|
+
class FileGroup
|
6
|
+
include Helpers::Error
|
7
|
+
|
8
|
+
# Initialize with either a path to a YAML settings file as a String,
|
9
|
+
# or a Hash containing your settings.
|
10
|
+
def initialize settings_arg
|
11
|
+
settings = Settings.new settings_arg
|
12
|
+
@settings = get_settings_with settings
|
13
|
+
@name = @settings.get :name
|
14
|
+
@directory = get_directory_from_settings @settings
|
15
|
+
validate_directory @directory
|
16
|
+
@files = get_file_paths
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns the settings as <tt>AdventureRL::Settings</tt>,
|
20
|
+
# unless <tt>*keys</tt> are given, then it returns the value of
|
21
|
+
# <tt>@settings.get(*keys)</tt>.
|
22
|
+
def get_settings *keys
|
23
|
+
return @settings if (keys.empty?)
|
24
|
+
return @settings.get(*keys)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the Clip's name.
|
28
|
+
def get_name
|
29
|
+
return @name
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns an Array of the filepaths.
|
33
|
+
def get_files
|
34
|
+
return @files
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns the filepath at index <tt>index</tt>.
|
38
|
+
def get_file index
|
39
|
+
return @files[index]
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the set directory of files.
|
43
|
+
def get_file_directory
|
44
|
+
return @directory
|
45
|
+
end
|
46
|
+
alias_method :get_directory, :get_file_directory
|
47
|
+
|
48
|
+
# Returns true if <tt>index</tt> file exists.
|
49
|
+
def has_file_index? index
|
50
|
+
return index < @files.size && index >= 0
|
51
|
+
end
|
52
|
+
alias_method :has_index?, :has_file_index?
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def get_settings_with custom_settings
|
57
|
+
return get_default_settings.merge custom_settings
|
58
|
+
end
|
59
|
+
|
60
|
+
# This method should be overwritten by the child class,
|
61
|
+
# and return their specific <tt>INTERNAL_DEFAULT_SETTINGS</tt>.
|
62
|
+
def get_default_settings
|
63
|
+
return {}
|
64
|
+
end
|
65
|
+
|
66
|
+
def get_directory_from_settings settings = @settings
|
67
|
+
directory = settings.get(:directory)
|
68
|
+
directory = directory.to_path if (directory.is_a? Pathname)
|
69
|
+
error(
|
70
|
+
"`:directory' key must be given in settings hash to #new."
|
71
|
+
) unless (directory)
|
72
|
+
return Pathname.new File.join(self.class.get_root_directory, directory)
|
73
|
+
end
|
74
|
+
|
75
|
+
def validate_directory directory = get_directory
|
76
|
+
error_no_directory directory unless (directory_exists? directory)
|
77
|
+
end
|
78
|
+
|
79
|
+
def get_file_paths
|
80
|
+
return sort_files(get_directory.each_child.select do |file|
|
81
|
+
next false unless (file.file?)
|
82
|
+
next file.basename.to_path.match? get_filename_regex
|
83
|
+
end)
|
84
|
+
end
|
85
|
+
|
86
|
+
def sort_files files
|
87
|
+
return files.sort do |file_one, file_two|
|
88
|
+
number_one = file_one.basename.to_path.match(/\A(\d+)\..+\z/)[1].to_i
|
89
|
+
number_two = file_two.basename.to_path.match(/\A(\d+)\..+\z/)[1].to_i
|
90
|
+
next number_one <=> number_two
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# This method should be overwritten by the child class.
|
95
|
+
# It should return the regex which must match the filenames.
|
96
|
+
def get_filename_regex
|
97
|
+
return /\A.+\..+\z/
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,226 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
# This is an abstract class, which is inherited by
|
3
|
+
# - ClipPlayer
|
4
|
+
# - AudioPlayer
|
5
|
+
# At its core, it takes a FileGroup in its #play method,
|
6
|
+
# and <em>"plays"</em> it.
|
7
|
+
class FileGroupPlayer
|
8
|
+
include Helpers::Error
|
9
|
+
|
10
|
+
# Pass settings Hash or Settings as argument.
|
11
|
+
# Supersedes the child class' <tt>DEFAULT_SETTINGS</tt>.
|
12
|
+
def initialize settings = {}
|
13
|
+
@settings = get_default_settings.merge settings
|
14
|
+
@playing = false
|
15
|
+
@speed = @settings.get(:speed)
|
16
|
+
@filegroup_index = 0
|
17
|
+
@filegroup = nil
|
18
|
+
@current_file = nil
|
19
|
+
@current_time = 0.0
|
20
|
+
@last_current_time = 0.0
|
21
|
+
@target_frame_delay = 1.0 / 24.0 # Default, will be overwritten in #play
|
22
|
+
@deltatime = Deltatime.new
|
23
|
+
end
|
24
|
+
|
25
|
+
# Returns the settings as <tt>AdventureRL::Settings</tt>,
|
26
|
+
# unless <tt>*keys</tt> are given, then it returns the value of
|
27
|
+
# <tt>@settings.get(*keys)</tt>.
|
28
|
+
def get_settings *keys
|
29
|
+
return @settings if (keys.empty?)
|
30
|
+
return @settings.get(*keys)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns the currently set FileGroup.
|
34
|
+
def get_filegroup
|
35
|
+
return @filegroup
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns the current playback time in seconds.
|
39
|
+
def get_current_time
|
40
|
+
return @current_time
|
41
|
+
end
|
42
|
+
alias_method :get_time, :get_current_time
|
43
|
+
|
44
|
+
# Set a new current playback time in seconds.
|
45
|
+
def set_current_time seconds
|
46
|
+
error(
|
47
|
+
"Passed seconds must be an Integer or Float,",
|
48
|
+
"but got #{seconds.inspect}:#{seconds.class.name}"
|
49
|
+
) unless ([Integer, Float].include? seconds.class)
|
50
|
+
@current_time = seconds
|
51
|
+
end
|
52
|
+
alias_method :set_time, :set_current_time
|
53
|
+
|
54
|
+
# Increase (or decrease) current_time.
|
55
|
+
def increase_current_time seconds
|
56
|
+
error(
|
57
|
+
"Passed seconds must be an Integer or Float,",
|
58
|
+
"but got #{seconds.inspect}:#{seconds.class.name}"
|
59
|
+
) unless ([Integer, Float].include? seconds.class)
|
60
|
+
@current_time += seconds
|
61
|
+
end
|
62
|
+
alias_method :increase_time, :increase_current_time
|
63
|
+
alias_method :seek, :increase_current_time
|
64
|
+
|
65
|
+
# Returns the current playback speed multiplier.
|
66
|
+
def get_speed
|
67
|
+
return @speed
|
68
|
+
end
|
69
|
+
|
70
|
+
# Set playback speed multiplier.
|
71
|
+
def set_speed speed
|
72
|
+
error(
|
73
|
+
"Argument passed to #set_speed must be a Float or Integer, but got",
|
74
|
+
"#{speed.inspect}:#{speed.class.name}"
|
75
|
+
) unless ([Float, Integer].include? speed.class)
|
76
|
+
@speed = speed
|
77
|
+
end
|
78
|
+
|
79
|
+
# Increment (or decrement) the speed value by <tt>amount</tt>.
|
80
|
+
def increase_speed amount
|
81
|
+
error(
|
82
|
+
"Argument passed to #increment_speed must be a Float or Integer, but got",
|
83
|
+
"#{seconds.inspect}:#{amount.class.name}"
|
84
|
+
) unless ([Float, Integer].include? amount.class)
|
85
|
+
@speed += amount
|
86
|
+
end
|
87
|
+
|
88
|
+
# Start playing FileGroup <tt>filegroup</tt>.
|
89
|
+
def play filegroup
|
90
|
+
load_filegroup filegroup
|
91
|
+
@playing = true
|
92
|
+
reset
|
93
|
+
end
|
94
|
+
|
95
|
+
# Load a FileGroup as active FileGroup.
|
96
|
+
def load_filegroup filegroup
|
97
|
+
error(
|
98
|
+
"Passed argument must be an instance of FileGroup, but got",
|
99
|
+
"#{filegroup.inspect}:#{filegroup.class.name}."
|
100
|
+
) unless (filegroup.is_a? FileGroup)
|
101
|
+
set_filegroup filegroup
|
102
|
+
@target_frame_delay = 1.0 / get_filegroup.get_settings(:fps).to_f
|
103
|
+
end
|
104
|
+
|
105
|
+
# Pause the currently playing FileGroup.
|
106
|
+
def pause
|
107
|
+
@playing = false
|
108
|
+
end
|
109
|
+
|
110
|
+
# Resumes playing paused FileGroup.
|
111
|
+
def resume
|
112
|
+
return unless (has_filegroup?)
|
113
|
+
@playing = true
|
114
|
+
@deltatime.reset
|
115
|
+
end
|
116
|
+
|
117
|
+
# Returns true if there is a currently active FileGroup.
|
118
|
+
def has_filegroup?
|
119
|
+
return !!get_filegroup
|
120
|
+
end
|
121
|
+
|
122
|
+
# Stop playing and clear active FileGroup.
|
123
|
+
# Cannot call #resume after this,
|
124
|
+
# before calling #play again.
|
125
|
+
def stop
|
126
|
+
@filegroup = nil
|
127
|
+
@playing = false
|
128
|
+
end
|
129
|
+
|
130
|
+
# Calls #resume if is paused,
|
131
|
+
# or calls #pause if is playing.
|
132
|
+
def toggle
|
133
|
+
if (is_playing?)
|
134
|
+
pause
|
135
|
+
elsif (has_filegroup?)
|
136
|
+
resume
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Reset the current playback.
|
141
|
+
# Start playing from the start again.
|
142
|
+
def reset
|
143
|
+
@deltatime.reset
|
144
|
+
@current_time = 0.0
|
145
|
+
@filegroup_index = 0
|
146
|
+
set_file
|
147
|
+
end
|
148
|
+
|
149
|
+
# Returns <tt>true</tt> if is currently _playing_,
|
150
|
+
# and <tt>false</tt> if is _paused_ or _stopped_.
|
151
|
+
def is_playing?
|
152
|
+
return @playing
|
153
|
+
end
|
154
|
+
|
155
|
+
# Check which file from FileGroup is supposed to be played.
|
156
|
+
# This should be called every frame.
|
157
|
+
def update
|
158
|
+
return unless (is_playing?)
|
159
|
+
set_filegroup_index
|
160
|
+
update_timing
|
161
|
+
end
|
162
|
+
|
163
|
+
private
|
164
|
+
|
165
|
+
# This method should be overwritten by the child class,
|
166
|
+
# and return their specific <tt>DEFAULT_SETTINGS</tt>.
|
167
|
+
def get_default_settings
|
168
|
+
return {}
|
169
|
+
end
|
170
|
+
|
171
|
+
def set_filegroup filegroup
|
172
|
+
@filegroup_index = 0
|
173
|
+
@filegroup = filegroup
|
174
|
+
set_file
|
175
|
+
end
|
176
|
+
|
177
|
+
def set_file
|
178
|
+
filegroup = get_filegroup
|
179
|
+
return if (
|
180
|
+
!filegroup ||
|
181
|
+
!filegroup.has_index?(get_filegroup_index)
|
182
|
+
)
|
183
|
+
load_file filegroup.get_file(get_filegroup_index).to_s
|
184
|
+
end
|
185
|
+
|
186
|
+
# This method should be overwritten by the child class.
|
187
|
+
# It is passed the filepath <tt>file</tt>.
|
188
|
+
def load_file file
|
189
|
+
end
|
190
|
+
|
191
|
+
def get_filegroup_index
|
192
|
+
return @filegroup_index
|
193
|
+
end
|
194
|
+
alias_method :get_index, :get_filegroup_index
|
195
|
+
|
196
|
+
def set_filegroup_index
|
197
|
+
previous_index = get_filegroup_index
|
198
|
+
index = (get_current_time / @target_frame_delay).floor
|
199
|
+
return if (previous_index == index)
|
200
|
+
@filegroup_index = index
|
201
|
+
filegroup = get_filegroup
|
202
|
+
unless (filegroup.has_index? get_filegroup_index)
|
203
|
+
if (get_settings(:loop))
|
204
|
+
reset
|
205
|
+
else
|
206
|
+
stop
|
207
|
+
end
|
208
|
+
return
|
209
|
+
end
|
210
|
+
set_file
|
211
|
+
end
|
212
|
+
|
213
|
+
def update_timing
|
214
|
+
@current_time += @deltatime.dt * @speed
|
215
|
+
@deltatime.update
|
216
|
+
end
|
217
|
+
|
218
|
+
def get_current_file
|
219
|
+
return @current_file
|
220
|
+
end
|
221
|
+
|
222
|
+
def set_current_file new_file
|
223
|
+
@current_file = new_file
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
module Helpers
|
3
|
+
module Error
|
4
|
+
PADDING = ' '
|
5
|
+
STACK_TRACE_SIZE = 20
|
6
|
+
STACK_TRACE_PADDING = 1
|
7
|
+
|
8
|
+
def self.error *messages
|
9
|
+
message = messages.join ?\n
|
10
|
+
message.gsub! /^/, PADDING
|
11
|
+
stack_trace_lines = caller[STACK_TRACE_PADDING ... (STACK_TRACE_SIZE + STACK_TRACE_PADDING)].map do |line|
|
12
|
+
next "#{PADDING}#{line}"
|
13
|
+
end .reverse
|
14
|
+
abort([
|
15
|
+
"#{DIR[:entry].to_s} Error:",
|
16
|
+
message,
|
17
|
+
"#{PADDING}Exiting.",
|
18
|
+
"Stack traceback (most recent call last):",
|
19
|
+
stack_trace_lines
|
20
|
+
].flatten.join(?\n))
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.error_no_file file
|
24
|
+
filepath = file
|
25
|
+
filepath = file.to_path if (file.is_a? Pathname)
|
26
|
+
error "File does not exist, or is a directory:", " '#{filepath}'"
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.error_no_directory directory
|
30
|
+
dirpath = directory
|
31
|
+
dirpath = directory.to_path if (directory.is_a? Pathname)
|
32
|
+
error "Directory does not exist, or is a file:", " '#{dirpath}'"
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.file_exists? file
|
36
|
+
return false unless (file)
|
37
|
+
return File.file? file
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.directory_exists? directory
|
41
|
+
return false unless (directory)
|
42
|
+
return File.directory? directory
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def error *messages
|
48
|
+
AdventureRL::Helpers::Error.error *messages
|
49
|
+
end
|
50
|
+
|
51
|
+
def error_no_file file
|
52
|
+
AdventureRL::Helpers::Error.error_no_file file
|
53
|
+
end
|
54
|
+
|
55
|
+
def error_no_directory directory
|
56
|
+
AdventureRL::Helpers::Error.error_no_directory directory
|
57
|
+
end
|
58
|
+
|
59
|
+
def file_exists? file
|
60
|
+
return AdventureRL::Helpers::Error.file_exists? file
|
61
|
+
end
|
62
|
+
|
63
|
+
def directory_exists? directory
|
64
|
+
return AdventureRL::Helpers::Error.directory_exists? directory
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
module Helpers
|
3
|
+
module MethodHelper
|
4
|
+
private
|
5
|
+
|
6
|
+
def method_exists? method_name
|
7
|
+
return (
|
8
|
+
methods.include?(method_name) ||
|
9
|
+
private_methods.include?(method_name)
|
10
|
+
)
|
11
|
+
end
|
12
|
+
|
13
|
+
def method_takes_arguments? method_name
|
14
|
+
return nil unless (method_exists?(method_name))
|
15
|
+
meth = method method_name
|
16
|
+
return meth.arity.abs > 0
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|