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,91 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
class Clip < FileGroup
|
3
|
+
IMAGE_FILENAME_REGEX = /\A\d+\.(png|jpe?g)\z/i
|
4
|
+
INTERNAL_DEFAULT_SETTINGS = Settings.new({
|
5
|
+
name: :clip_name,
|
6
|
+
directory: nil,
|
7
|
+
fps: 24,
|
8
|
+
audio: false
|
9
|
+
})
|
10
|
+
@@default_settings = nil
|
11
|
+
@@root_directory = Pathname.new($0).dirname
|
12
|
+
|
13
|
+
class << self
|
14
|
+
# Set the root directory for the images directory.
|
15
|
+
# All settings 'directory' values will be relative to this.
|
16
|
+
# Defaults to the entry scripts (the script that was called, <tt>$0</tt>) directory.
|
17
|
+
# Pass either a String with the directory path, or an instance of Pathname.
|
18
|
+
def set_root_directory directory
|
19
|
+
directory = Pathname.new directory unless (directory.is_a? Pathname)
|
20
|
+
@@root_directory = Pathname.new directory
|
21
|
+
end
|
22
|
+
alias_method :root=, :set_root_directory
|
23
|
+
|
24
|
+
# Returns the currently set root images directory.
|
25
|
+
def get_root_directory
|
26
|
+
return @@root_directory
|
27
|
+
end
|
28
|
+
alias_method :root, :get_root_directory
|
29
|
+
|
30
|
+
# Set the default Settings.
|
31
|
+
# Pass either String to a YAML settings file,
|
32
|
+
# or a Hash with your default settings.
|
33
|
+
def set_default_settings settings
|
34
|
+
default_settings = nil
|
35
|
+
if ([String, Pathname].include? settings.class)
|
36
|
+
filepath = settings
|
37
|
+
filepath = Pathname.new filepath unless (filepath.is_a? Pathname)
|
38
|
+
if (filepath.absolute?)
|
39
|
+
default_settings = Settings.new filepath
|
40
|
+
else
|
41
|
+
if (File.file?(filepath))
|
42
|
+
default_settings = Settings.new filepath
|
43
|
+
else
|
44
|
+
default_settings = Settings.new get_root_directory.join(filepath)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
elsif (settings.is_a? Hash)
|
48
|
+
default_settings = Settings.new settings
|
49
|
+
end
|
50
|
+
@@default_settings = default_settings
|
51
|
+
end
|
52
|
+
alias_method :default_settings=, :set_default_settings
|
53
|
+
end
|
54
|
+
|
55
|
+
# Initialize with either a path to a YAML settings file as a String,
|
56
|
+
# or a Hash containing your settings.
|
57
|
+
def initialize settings
|
58
|
+
super
|
59
|
+
audio_settings = get_settings :audio
|
60
|
+
@audio = load_audio audio_settings if (audio_settings)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns this Clip's Audio, if one was provided at #new.
|
64
|
+
def get_audio
|
65
|
+
return @audio
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns true if this Clip has Audio.
|
69
|
+
def has_audio?
|
70
|
+
return !!get_audio
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
# Loads Audio, if one was provided
|
76
|
+
def load_audio audio_settings
|
77
|
+
return Audio.new audio_settings
|
78
|
+
end
|
79
|
+
|
80
|
+
# Returns this class' specific INTERNAL_DEFAULT_SETTINGS.
|
81
|
+
def get_default_settings
|
82
|
+
return INTERNAL_DEFAULT_SETTINGS.merge @@default_settings if (@@default_settings)
|
83
|
+
return INTERNAL_DEFAULT_SETTINGS
|
84
|
+
end
|
85
|
+
|
86
|
+
# Should return the regex which must match the filenames.
|
87
|
+
def get_filename_regex
|
88
|
+
return IMAGE_FILENAME_REGEX
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,187 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
class ClipPlayer < FileGroupPlayer
|
3
|
+
# Default settings for ClipPlayer.
|
4
|
+
# Are superseded by settings passed to #new.
|
5
|
+
DEFAULT_SETTINGS = Settings.new({
|
6
|
+
speed: 1.0,
|
7
|
+
loop: true,
|
8
|
+
mask: {
|
9
|
+
position: {
|
10
|
+
x: 0,
|
11
|
+
y: 0
|
12
|
+
},
|
13
|
+
size: {
|
14
|
+
width: 960,
|
15
|
+
height: 540
|
16
|
+
},
|
17
|
+
origin: {
|
18
|
+
x: :left,
|
19
|
+
y: :top
|
20
|
+
}
|
21
|
+
},
|
22
|
+
z_index: 0,
|
23
|
+
color: 0xff_ffffff,
|
24
|
+
image_options: {
|
25
|
+
retro: true
|
26
|
+
}
|
27
|
+
})
|
28
|
+
AUDIO_PLAYER_METHODS = [
|
29
|
+
:pause,
|
30
|
+
:resume,
|
31
|
+
:stop,
|
32
|
+
:reset,
|
33
|
+
:set_current_time,
|
34
|
+
:increase_current_time,
|
35
|
+
:set_speed,
|
36
|
+
:increase_speed,
|
37
|
+
:update
|
38
|
+
]
|
39
|
+
|
40
|
+
class << self
|
41
|
+
# Returns the method names of all methods aliased to method <tt>method_name</tt>.
|
42
|
+
def get_aliased_methods method_name
|
43
|
+
real_method = instance_method method_name
|
44
|
+
return instance_methods.select do |instance_method_name|
|
45
|
+
next (
|
46
|
+
real_method == instance_method(instance_method_name) &&
|
47
|
+
method_name != instance_method_name
|
48
|
+
)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# Overwrite a bunch of FileGroupPlayer methods,
|
53
|
+
# so they also handle Audio, if Clip has one.
|
54
|
+
# See AUDIO_PLAYER_METHODS for the list of methods.
|
55
|
+
def define_audio_player_methods
|
56
|
+
AUDIO_PLAYER_METHODS.each do |real_method_name|
|
57
|
+
[real_method_name, get_aliased_methods(real_method_name)].flatten.each do |method_name|
|
58
|
+
define_method(method_name) do |*args|
|
59
|
+
super *args
|
60
|
+
get_audio_player.method(method_name).call(*args) if (has_audio_player?)
|
61
|
+
# NOTE: Write #sync_audio_player method, maybe?
|
62
|
+
# Should be unnecessarilty doubled work,
|
63
|
+
# but it would garantee that both Players are synced.
|
64
|
+
# sync_audio_player
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
define_audio_player_methods
|
72
|
+
|
73
|
+
# Pass settings Hash or Settings as argument.
|
74
|
+
# Supersedes DEFAULT_SETTINGS.
|
75
|
+
def initialize settings = {}
|
76
|
+
super
|
77
|
+
@audio_player = nil
|
78
|
+
set_mask_from get_settings(:mask)
|
79
|
+
end
|
80
|
+
|
81
|
+
# Returns the current AudioPlayer, if there is one.
|
82
|
+
def get_audio_player
|
83
|
+
return @audio_player
|
84
|
+
end
|
85
|
+
|
86
|
+
# Returns true if an AudioPlayer was instantiated for this ClipPlayer.
|
87
|
+
def has_audio_player?
|
88
|
+
return !!get_audio_player
|
89
|
+
end
|
90
|
+
|
91
|
+
# Returns the currently active Clip.
|
92
|
+
# Wrapper for FileGroupPlayer#get_filegroup
|
93
|
+
alias_method :get_clip, :get_filegroup
|
94
|
+
|
95
|
+
# Returns true if there is a currently active Clip.
|
96
|
+
# Wrapper for FileGroupPlayer#has_filegroup?
|
97
|
+
alias_method :has_clip?, :has_filegroup?
|
98
|
+
|
99
|
+
# Overwrite FileGroupPlayer#play separately from above,
|
100
|
+
# because it should call #handle_play_for_audio_player
|
101
|
+
# to create a new AudioPlayer, if necessary.
|
102
|
+
def play *args
|
103
|
+
super
|
104
|
+
if (get_clip.has_audio?)
|
105
|
+
handle_play_for_audio_player
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
# Draw the current image in the currently active Clip.
|
110
|
+
# This should be called every frame.
|
111
|
+
def draw
|
112
|
+
image = get_current_file
|
113
|
+
return unless (image)
|
114
|
+
scale = get_scale_for_image image
|
115
|
+
image.draw(
|
116
|
+
get_side(:left), get_side(:top), get_settings(:z_index),
|
117
|
+
scale[:x], scale[:y],
|
118
|
+
get_settings(:color)
|
119
|
+
)
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
# Set the Mask for the ClipPlayer.
|
125
|
+
def set_mask_from mask
|
126
|
+
if (mask.is_a?(Mask))
|
127
|
+
mask.assign_to self
|
128
|
+
elsif (mask.is_a?(Hash))
|
129
|
+
Mask.new(
|
130
|
+
mask.merge(
|
131
|
+
assign_to: self
|
132
|
+
)
|
133
|
+
)
|
134
|
+
else
|
135
|
+
error "Cannot set Mask as #{mask.inspect}:#{mask.class.name} for ClipPlayer."
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
# Loads the image file <tt>file</tt>
|
140
|
+
def load_file file
|
141
|
+
if (get_current_image.is_a? Gosu::Image)
|
142
|
+
get_current_image.insert file, 0, 0
|
143
|
+
else
|
144
|
+
set_current_image Gosu::Image.new(
|
145
|
+
file,
|
146
|
+
get_settings(:image_options)
|
147
|
+
)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
# Returns the current image.
|
152
|
+
# Wrapper for FileGroupPlayer#get_current_file
|
153
|
+
alias_method :get_current_image, :get_current_file
|
154
|
+
|
155
|
+
# Set a new current image.
|
156
|
+
# Wrapper for FileGroupPlayer#set_current_file
|
157
|
+
alias_method :set_current_image, :set_current_file
|
158
|
+
|
159
|
+
def get_scale_for_image image = get_current_file
|
160
|
+
return {
|
161
|
+
x: (get_size(:width).to_f / image.width.to_f),
|
162
|
+
y: (get_size(:height).to_f / image.height.to_f)
|
163
|
+
}
|
164
|
+
end
|
165
|
+
|
166
|
+
# Create, change, or remove AudioPlayer,
|
167
|
+
# depending on if the current Clip has Audio.
|
168
|
+
def handle_play_for_audio_player
|
169
|
+
clip = get_clip
|
170
|
+
if (clip.has_audio?)
|
171
|
+
if (has_audio_player?)
|
172
|
+
@audio_player.play clip.get_audio
|
173
|
+
else
|
174
|
+
@audio_player = AudioPlayer.new get_settings
|
175
|
+
@audio_player.play clip.get_audio
|
176
|
+
end
|
177
|
+
elsif (has_audio_player?)
|
178
|
+
get_audio_player.stop
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
# Returns this class' DEFAULT_SETTINGS.
|
183
|
+
def get_default_settings
|
184
|
+
return DEFAULT_SETTINGS
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
class Deltatime
|
3
|
+
# This Array is filled with _all_ initialized Deltatime instances.
|
4
|
+
# The point of it is, that they are all reset once the Window opens ( Window#show ).
|
5
|
+
DELTATIMES = []
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@last_update_at = nil
|
9
|
+
@deltatime = nil
|
10
|
+
set_last_update_at
|
11
|
+
set_deltatime
|
12
|
+
DELTATIMES << self
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the value of the last calculated deltatime.
|
16
|
+
def get_deltatime
|
17
|
+
return @deltatime
|
18
|
+
end
|
19
|
+
alias_method :get, :get_deltatime
|
20
|
+
alias_method :dt, :get_deltatime
|
21
|
+
|
22
|
+
# Call this method every tick / frame
|
23
|
+
# to update the deltatime value.
|
24
|
+
def update
|
25
|
+
set_deltatime
|
26
|
+
set_last_update_at
|
27
|
+
end
|
28
|
+
|
29
|
+
# Resets last updated deltatime.
|
30
|
+
# Used when wanting to pause this deltatime's calculations,
|
31
|
+
# so when resumed, deltatime isn't a large number.
|
32
|
+
def reset
|
33
|
+
set_last_update_at
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def set_deltatime
|
39
|
+
diff_in_secs = get_elapsed_seconds - @last_update_at
|
40
|
+
@deltatime = diff_in_secs
|
41
|
+
end
|
42
|
+
|
43
|
+
def set_last_update_at
|
44
|
+
@last_update_at = get_elapsed_seconds
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_elapsed_seconds
|
48
|
+
return Gosu.milliseconds.to_f / 1000.0
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
module EventHandlers
|
3
|
+
class Buttons < EventHandler
|
4
|
+
# This constant will be filled with
|
5
|
+
# EventHandlers::Buttons and EventHandlers::MouseButtons
|
6
|
+
# instances as they are created.
|
7
|
+
# It is used by the following class methods
|
8
|
+
# EventHandler::Buttons#button_down,
|
9
|
+
# EventHandler::Buttons#button_up, and
|
10
|
+
# EventHandler::Buttons#update.
|
11
|
+
BUTTON_EVENT_HANDLERS = []
|
12
|
+
|
13
|
+
def self.button_down btnid
|
14
|
+
BUTTON_EVENT_HANDLERS.each do |handler|
|
15
|
+
handler.button_down btnid
|
16
|
+
end
|
17
|
+
end
|
18
|
+
def self.button_up btnid
|
19
|
+
BUTTON_EVENT_HANDLERS.each do |handler|
|
20
|
+
handler.button_up btnid
|
21
|
+
end
|
22
|
+
end
|
23
|
+
def self.update
|
24
|
+
BUTTON_EVENT_HANDLERS.each &:update
|
25
|
+
end
|
26
|
+
|
27
|
+
DEFAULT_SETTINGS = Settings.new(
|
28
|
+
pressable_buttons: [],
|
29
|
+
auto_update: false
|
30
|
+
)
|
31
|
+
|
32
|
+
def initialize settings = {}
|
33
|
+
@settings = DEFAULT_SETTINGS.merge settings
|
34
|
+
super
|
35
|
+
@pressable_buttons = []
|
36
|
+
pressable_buttons = [@settings.get(:pressable_buttons)].flatten
|
37
|
+
add_pressable_button pressable_buttons if (pressable_buttons.any?)
|
38
|
+
@events = get_events
|
39
|
+
BUTTON_EVENT_HANDLERS << self if (@settings.get(:auto_update))
|
40
|
+
end
|
41
|
+
|
42
|
+
# Add one or multiple button character(s) <tt>btns</tt>,
|
43
|
+
# which will trigger the #on_button_press methods on subscribed objects,
|
44
|
+
# when the given button is being pressed.
|
45
|
+
# Instead of passing single alphanumeric strings / symbols,
|
46
|
+
# you can pass hashes, whose keys will be passed to the #on_button_press methods,
|
47
|
+
# when _any_ of its values are pressed.
|
48
|
+
# Case-sensitive.
|
49
|
+
def add_pressable_button *btns
|
50
|
+
btns.flatten.each do |button|
|
51
|
+
if (button.is_a?(Symbol) || button.is_a?(String))
|
52
|
+
validate_button button
|
53
|
+
btnid = Gosu.char_to_button_id button
|
54
|
+
pressable_button = {
|
55
|
+
name: button,
|
56
|
+
ids: [btnid]
|
57
|
+
}
|
58
|
+
@pressable_buttons << pressable_button unless (@pressable_buttons.include? pressable_button)
|
59
|
+
elsif (button.is_a?(Hash))
|
60
|
+
button.each do |btn_name, btn_buttons|
|
61
|
+
pressable_button = {
|
62
|
+
name: btn_name,
|
63
|
+
ids: [btn_buttons].flatten.map do |btn|
|
64
|
+
validate_button btn
|
65
|
+
next Gosu.char_to_button_id btn
|
66
|
+
end
|
67
|
+
}
|
68
|
+
@pressable_buttons << pressable_button unless (@pressable_buttons.include? pressable_button)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
alias_method :add_pressable_buttons, :add_pressable_button
|
74
|
+
|
75
|
+
def button_down btnid
|
76
|
+
trigger(
|
77
|
+
:button_down,
|
78
|
+
get_semantic_button_name(btnid),
|
79
|
+
shift: shift_button_pressed?,
|
80
|
+
control: control_button_pressed?,
|
81
|
+
alt: alt_button_pressed?
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
def button_up btnid
|
86
|
+
trigger(
|
87
|
+
:button_up,
|
88
|
+
get_semantic_button_name(btnid),
|
89
|
+
shift: shift_button_pressed?,
|
90
|
+
control: control_button_pressed?,
|
91
|
+
alt: alt_button_pressed?
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
def update
|
96
|
+
return unless (get_pressable_buttons.any?)
|
97
|
+
pressed_btns = get_pressable_buttons.map do |btn|
|
98
|
+
next btn[:name] if (btn[:ids].any? { |id| Gosu.button_down?(id) })
|
99
|
+
next nil
|
100
|
+
end .compact.uniq
|
101
|
+
return unless (pressed_btns.any?)
|
102
|
+
pressed_btns.each do |btn|
|
103
|
+
trigger(
|
104
|
+
:button_press,
|
105
|
+
btn,
|
106
|
+
shift: shift_button_pressed?,
|
107
|
+
control: control_button_pressed?,
|
108
|
+
alt: alt_button_pressed?
|
109
|
+
)
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def get_pressable_buttons
|
114
|
+
return @pressable_buttons
|
115
|
+
end
|
116
|
+
|
117
|
+
private
|
118
|
+
|
119
|
+
def get_events
|
120
|
+
return [
|
121
|
+
get_event_button_down,
|
122
|
+
get_event_button_up,
|
123
|
+
get_event_button_press
|
124
|
+
]
|
125
|
+
end
|
126
|
+
|
127
|
+
def get_event_button_down
|
128
|
+
event = Events::Event.new(:button_down)
|
129
|
+
event.on_trigger do |object, btn_name, mod_keys|
|
130
|
+
next unless (object.methods.include? :on_button_down)
|
131
|
+
case object.method(:on_button_down).arity.abs
|
132
|
+
when 0
|
133
|
+
object.on_button_down
|
134
|
+
when 1
|
135
|
+
object.on_button_down btn_name
|
136
|
+
when 2
|
137
|
+
object.on_button_down btn_name, mod_keys
|
138
|
+
end
|
139
|
+
end
|
140
|
+
return event
|
141
|
+
end
|
142
|
+
|
143
|
+
def get_event_button_up
|
144
|
+
event = Events::Event.new(:button_up)
|
145
|
+
event.on_trigger do |object, btn_name, mod_keys|
|
146
|
+
next unless (object.methods.include? :on_button_up)
|
147
|
+
case object.method(:on_button_up).arity.abs
|
148
|
+
when 0
|
149
|
+
object.on_button_up
|
150
|
+
when 1
|
151
|
+
object.on_button_up btn_name
|
152
|
+
when 2
|
153
|
+
object.on_button_up btn_name, mod_keys
|
154
|
+
end
|
155
|
+
end
|
156
|
+
return event
|
157
|
+
end
|
158
|
+
|
159
|
+
def get_event_button_press
|
160
|
+
event = Events::Event.new(:button_press)
|
161
|
+
event.on_trigger do |object, btn_name, mod_keys|
|
162
|
+
next unless (object.methods.include? :on_button_press)
|
163
|
+
case object.method(:on_button_press).arity.abs
|
164
|
+
when 0
|
165
|
+
object.on_button_press
|
166
|
+
when 1
|
167
|
+
object.on_button_press btn_name
|
168
|
+
when 2
|
169
|
+
object.on_button_press btn_name, mod_keys
|
170
|
+
end
|
171
|
+
end
|
172
|
+
return event
|
173
|
+
end
|
174
|
+
|
175
|
+
def validate_button btn
|
176
|
+
Helpers::Error.error(
|
177
|
+
"Passed invalid button character. Expected a printable alphanumeric, but got",
|
178
|
+
"`#{btn.inspect}:#{btn.class.name}'."
|
179
|
+
) unless (Gosu.char_to_button_id btn)
|
180
|
+
end
|
181
|
+
|
182
|
+
def get_semantic_button_name btnid
|
183
|
+
pressable_button = get_pressable_buttons.detect do |pressable_button|
|
184
|
+
next pressable_button[:ids].include?(btnid)
|
185
|
+
end
|
186
|
+
return pressable_button[:name] if (pressable_button)
|
187
|
+
btn_char = Gosu.button_id_to_char btnid
|
188
|
+
return get_semantic_constant_button_name btnid if (btn_char.empty?)
|
189
|
+
return btn_char.to_sym
|
190
|
+
end
|
191
|
+
|
192
|
+
def get_semantic_constant_button_name btnid
|
193
|
+
return Gosu.constants.map do |constant_name|
|
194
|
+
constant = Gosu.const_get constant_name
|
195
|
+
next constant_name.to_s.sub(/^(KB_|MS_|GP_)/,'').downcase.to_sym if (constant == btnid && constant_name.match?(/_/))
|
196
|
+
next nil
|
197
|
+
end .compact.first
|
198
|
+
end
|
199
|
+
|
200
|
+
# Returns <tt>true</tt> if either <tt>LEFT_SHIFT</tt> or <tt>RIGHT_SHIFT</tt> is pressed,
|
201
|
+
# returns <tt>false</tt> otherwise.
|
202
|
+
def shift_button_pressed?
|
203
|
+
return Gosu.button_down?(Gosu::KB_LEFT_SHIFT) || Gosu.button_down?(Gosu::KB_RIGHT_SHIFT)
|
204
|
+
end
|
205
|
+
|
206
|
+
# Returns <tt>true</tt> if either <tt>LEFT_CONTROL</tt> or <tt>RIGHT_CONTROL</tt> is pressed,
|
207
|
+
# returns <tt>false</tt> otherwise.
|
208
|
+
def control_button_pressed?
|
209
|
+
return Gosu.button_down?(Gosu::KB_LEFT_CONTROL) || Gosu.button_down?(Gosu::KB_RIGHT_CONTROL)
|
210
|
+
end
|
211
|
+
|
212
|
+
# Returns <tt>true</tt> if either <tt>LEFT_ALT</tt> or <tt>RIGHT_ALT</tt> is pressed,
|
213
|
+
# returns <tt>false</tt> otherwise.
|
214
|
+
def alt_button_pressed?
|
215
|
+
return Gosu.button_down?(Gosu::KB_LEFT_ALT) || Gosu.button_down?(Gosu::KB_RIGHT_ALT)
|
216
|
+
end
|
217
|
+
|
218
|
+
# Subscribing objects must be a Mask or have a Mask assigned to them.
|
219
|
+
def valid_object? object
|
220
|
+
ret = object.has_mask? rescue false
|
221
|
+
return ret
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
module EventHandlers
|
3
|
+
# An EventHandler can have multiple Event s.
|
4
|
+
# You can subscribe an object to a specific Event using its name,
|
5
|
+
# through the EventHandler.
|
6
|
+
class EventHandler
|
7
|
+
def initialize settings = {}
|
8
|
+
@events = []
|
9
|
+
end
|
10
|
+
|
11
|
+
# Add an Event to this EventHandler.
|
12
|
+
def add_event event
|
13
|
+
Helpers::Error.error(
|
14
|
+
"Passed `event' is not an instance of `Event'.",
|
15
|
+
"Got `#{event.inspect}:#{event.class.name}'."
|
16
|
+
) unless (event.is_a? Event)
|
17
|
+
@events << event
|
18
|
+
end
|
19
|
+
alias_method :add, :add_event
|
20
|
+
alias_method :<<, :add_event
|
21
|
+
|
22
|
+
# Subscribe an <tt>object</tt> to all Event s in this EventHandler.
|
23
|
+
def subscribe object
|
24
|
+
Helpers::Error.error(
|
25
|
+
"Object `#{object.inspect}:#{object.class.name}' cannot subscribe",
|
26
|
+
"to this EventHandler `#{self.inspect}:#{self.class.name}'."
|
27
|
+
) unless (valid_object? object)
|
28
|
+
@events.each do |event|
|
29
|
+
event.add_object object
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# Unsubscribe an <tt>object</tt> from all Event s in this EventHandler.
|
34
|
+
def unsubscribe object
|
35
|
+
@events.each do |event|
|
36
|
+
event.remove_object object
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Trigger the Event with the name <tt>event_name</tt>.
|
41
|
+
# Returns <tt>true</tt> if the Event was found and <tt>false</tt> if not.
|
42
|
+
# Optionally, additional <tt>args</tt> arguments can be passed,
|
43
|
+
# which will be passed to the trigger methods on the Event s.
|
44
|
+
def trigger event_name, *args
|
45
|
+
event = @events.detect do |evnt|
|
46
|
+
evnt.get_name == event_name
|
47
|
+
end
|
48
|
+
event.trigger *args if (event)
|
49
|
+
return !!event
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
# Returns <tt>true</tt> if the passed <tt>object</tt> can be subscribed to this EventHandler,
|
55
|
+
# and <tt>false</tt> if not.
|
56
|
+
# This method should be overwritten to fit specific requirements.
|
57
|
+
def valid_object? object
|
58
|
+
return !!object
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|