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,26 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
module Helpers
|
3
|
+
module PipeMethods
|
4
|
+
# This method _pipes_ or forwards any methods called on the object
|
5
|
+
# to the target object. It defines the <tt>method_missing</tt> method
|
6
|
+
# on the origin object which calls the wanted method on the target object,
|
7
|
+
# if it exists.
|
8
|
+
def self.pipe_methods_from object_origin, pipe_args = {}
|
9
|
+
object_target = pipe_args[:to]
|
10
|
+
Error.error(
|
11
|
+
"AdventureRL::Helpers::PipeMethods#pipe_methods_from requires a hash with the key :to and the value of the target object, where the methods should be piped to."
|
12
|
+
) unless (object_target)
|
13
|
+
|
14
|
+
object_origin.define_singleton_method :method_missing do |method_name, *args|
|
15
|
+
if (object_target.methods.include?(method_name))
|
16
|
+
return object_target.method(method_name).call(*args)
|
17
|
+
elsif (object_target.methods.include?(:method_missing))
|
18
|
+
return object_target.method(:method_missing).call(method_name, *args)
|
19
|
+
else
|
20
|
+
raise NoMethodError, "undefined method `#{method_name}' for #{self} (PIPED)"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
class Image < Mask
|
3
|
+
include Helpers::Error
|
4
|
+
|
5
|
+
DEFAULT_SETTINGS = Settings.new(
|
6
|
+
file: 'DEFAULT_IMAGE_FILE.png',
|
7
|
+
retro: true,
|
8
|
+
z_index: 0,
|
9
|
+
dont_create_image: false, # Used by Animation
|
10
|
+
position: {
|
11
|
+
x: 0,
|
12
|
+
y: 0
|
13
|
+
},
|
14
|
+
size: {
|
15
|
+
width: 128,
|
16
|
+
height: 128
|
17
|
+
},
|
18
|
+
origin: {
|
19
|
+
x: :left,
|
20
|
+
y: :top
|
21
|
+
}
|
22
|
+
)
|
23
|
+
|
24
|
+
# Valid image option keys for the Gosu::Image constructor.
|
25
|
+
IMAGE_OPTION_KEYS = [
|
26
|
+
:tileable,
|
27
|
+
:retro,
|
28
|
+
:rect
|
29
|
+
]
|
30
|
+
|
31
|
+
# Pass the filepath to the image as the value of the key <tt>:file</tt>
|
32
|
+
# in your passed Settings instance or hash.
|
33
|
+
def initialize settings = {}
|
34
|
+
@settings = DEFAULT_SETTINGS.merge settings
|
35
|
+
@z_index = @settings.get :z_index
|
36
|
+
@image_options = get_image_options_from @settings
|
37
|
+
@image = get_image_from @settings.get(:file) unless (@settings.get(:dont_create_image))
|
38
|
+
super @settings
|
39
|
+
end
|
40
|
+
|
41
|
+
def draw
|
42
|
+
corner = get_corner :left, :top
|
43
|
+
scale = get_image_scale
|
44
|
+
@image.draw(
|
45
|
+
corner.x, corner.y,
|
46
|
+
@z_index,
|
47
|
+
scale[:x], scale[:y]
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def get_image_options_from settings = @settings
|
54
|
+
return IMAGE_OPTION_KEYS.map do |key|
|
55
|
+
setting = settings.get key
|
56
|
+
next [key, setting] if (setting)
|
57
|
+
next nil
|
58
|
+
end .compact.to_h
|
59
|
+
end
|
60
|
+
|
61
|
+
def get_image_from file
|
62
|
+
filepath = Pathname.new file
|
63
|
+
error_no_file filepath unless (file_exists? filepath)
|
64
|
+
return Gosu::Image.new(
|
65
|
+
filepath.to_path,
|
66
|
+
@image_options
|
67
|
+
)
|
68
|
+
end
|
69
|
+
|
70
|
+
def get_image_scale
|
71
|
+
return {
|
72
|
+
x: (get_size(:width).to_f / @image.width.to_f),
|
73
|
+
y: (get_size(:height).to_f / @image.height.to_f)
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,273 @@
|
|
1
|
+
module AdventureRL
|
2
|
+
# This class is supposed to be a sort of container
|
3
|
+
# for instances which have Mask s assigned to them.
|
4
|
+
# It can manipulate any drawing operations, which will
|
5
|
+
# effect all Mask s contained. See Gosu methods.
|
6
|
+
# Layer also has a Mask.
|
7
|
+
class Layer < Mask
|
8
|
+
include Helpers::Error
|
9
|
+
include Modifiers::Inventory
|
10
|
+
|
11
|
+
# Default settings.
|
12
|
+
# <tt>settings</tt> passed to #new take precedence.
|
13
|
+
DEFAULT_SETTINGS = Settings.new(
|
14
|
+
scale: {
|
15
|
+
x: 1,
|
16
|
+
y: 1
|
17
|
+
},
|
18
|
+
rotation: 0,
|
19
|
+
has_solids_manager: false,
|
20
|
+
solids_manager: {
|
21
|
+
use_cache: false
|
22
|
+
},
|
23
|
+
position: {
|
24
|
+
x: 0,
|
25
|
+
y: 0
|
26
|
+
},
|
27
|
+
size: {
|
28
|
+
width: 360,
|
29
|
+
height: 360
|
30
|
+
},
|
31
|
+
origin: {
|
32
|
+
x: :left,
|
33
|
+
y: :top
|
34
|
+
}
|
35
|
+
)
|
36
|
+
|
37
|
+
MASK_ID = :mask
|
38
|
+
|
39
|
+
# Initialize Layer with a <tt>settings</tt> Hash.
|
40
|
+
# See DEFAULT_SETTINGS for valid keys.
|
41
|
+
def initialize settings = {}
|
42
|
+
@settings = DEFAULT_SETTINGS.merge settings
|
43
|
+
@scale = @settings.get :scale
|
44
|
+
@rotation = @settings.get :rotation
|
45
|
+
@has_solids_manager = !!@settings.get(:has_solids_manager)
|
46
|
+
@solids_manager = SolidsManager.new if (has_solids_manager?)
|
47
|
+
super @settings #.get.reject { |key,val| next key == :assign_to }
|
48
|
+
end
|
49
|
+
|
50
|
+
# Add any object to this Layer.
|
51
|
+
# Pass an optional <tt>id</tt>, which can be used to
|
52
|
+
# access or remove the object afterwards.
|
53
|
+
def add_object object, id = nil
|
54
|
+
id = MASK_ID if (id.nil? && object.is_a?(Mask))
|
55
|
+
id ||= DEFAULT_INVENTORY_ID
|
56
|
+
super object, id
|
57
|
+
object.set_layer self if (object.methods.include?(:set_layer) || object_mask_has_method?(object, :set_layer))
|
58
|
+
end
|
59
|
+
alias_method :add_item, :add_object
|
60
|
+
alias_method :add, :add_object
|
61
|
+
alias_method :<<, :add_object
|
62
|
+
|
63
|
+
# Returns the current scale.
|
64
|
+
# <tt>target</tt> can be either <tt>:x</tt>, <tt>:y</tt>, or <tt>:all</tt>.
|
65
|
+
def get_scale target = :all
|
66
|
+
return @scale[target] if (@scale.key? target)
|
67
|
+
return @scale if (target == :all)
|
68
|
+
return nil
|
69
|
+
end
|
70
|
+
|
71
|
+
# Returns the real scale of this Layer.
|
72
|
+
# That is, this Layer's scale multiplied by all
|
73
|
+
# parent Layer's scales.
|
74
|
+
def get_real_scale target = :all
|
75
|
+
return get_scale target unless (has_layer?)
|
76
|
+
return get_layer.get_real_scale(target) * get_scale(target) if (@scale.key? target)
|
77
|
+
return {
|
78
|
+
x: (get_layer.get_real_scale(:x) * get_scale(:x)),
|
79
|
+
y: (get_layer.get_real_scale(:y) * get_scale(:y))
|
80
|
+
} if (target == :all)
|
81
|
+
return nil
|
82
|
+
end
|
83
|
+
|
84
|
+
# Set the layer scaling.
|
85
|
+
# Pass an <tt>axis</tt>, either <tt>:x</tt> or <tt>:y</tt>,
|
86
|
+
# and an <tt>amount</tt> as an Integer or Float.
|
87
|
+
def set_scale axis, amount
|
88
|
+
error(
|
89
|
+
"Passed argument `axis' needs to be one of the following:",
|
90
|
+
" #{@scale.keys.map(&:inspect).join(', ')}"
|
91
|
+
) unless (@scale.key? axis)
|
92
|
+
error(
|
93
|
+
"Passed argument `amount' needs to be an Integer or Float, but got",
|
94
|
+
" #{amount.inspect}.#{amount.class.name}"
|
95
|
+
) unless ([Integer, Float].include? amount.class)
|
96
|
+
@scale[axis] = amount
|
97
|
+
end
|
98
|
+
|
99
|
+
# Increase (or decrease) the layer scaling by an <tt>amount</tt>.
|
100
|
+
# Pass an <tt>axis</tt>, either <tt>:x</tt> or <tt>:y</tt>,
|
101
|
+
# and an <tt>amount</tt> as an Integer or Float.
|
102
|
+
def increase_scale axis, amount
|
103
|
+
error(
|
104
|
+
"Passed argument `axis' needs to be one of the following:",
|
105
|
+
" #{@scale.keys.map(&:inspect).join(', ')}"
|
106
|
+
) unless (@scale.key? axis)
|
107
|
+
error(
|
108
|
+
"Passed argument `amount' needs to be an Integer or Float, but got",
|
109
|
+
" #{amount.inspect}.#{amount.class.name}"
|
110
|
+
) unless ([Integer, Float].include? amount.class)
|
111
|
+
@scale[axis] += amount if (@scale.key? axis)
|
112
|
+
end
|
113
|
+
|
114
|
+
# Returns the current rotation.
|
115
|
+
def get_rotation
|
116
|
+
return @rotation
|
117
|
+
end
|
118
|
+
|
119
|
+
# Set the layer rotation.
|
120
|
+
# Pass an <tt>angle</tt> as an Integer or Float.
|
121
|
+
def set_rotation angle
|
122
|
+
error(
|
123
|
+
"Passed argument `angle' needs to be an Integer or Float, but got",
|
124
|
+
" #{angle.inspect}.#{angle.class.name}"
|
125
|
+
) unless ([Integer, Float].include? angle.class)
|
126
|
+
@rotation = angle
|
127
|
+
handle_rotation_overflow
|
128
|
+
end
|
129
|
+
|
130
|
+
# Increase (or decrease) the layer rotation.
|
131
|
+
# Pass an <tt>angle</tt> as an Integer or Float.
|
132
|
+
def increase_rotation angle
|
133
|
+
error(
|
134
|
+
"Passed argument `angle' needs to be an Integer or Float, but got",
|
135
|
+
" #{angle.inspect}.#{angle.class.name}"
|
136
|
+
) unless ([Integer, Float].include? angle.class)
|
137
|
+
@rotation += angle
|
138
|
+
handle_rotation_overflow
|
139
|
+
end
|
140
|
+
|
141
|
+
# Returns a new Point with this Layers real window position.
|
142
|
+
def get_real_point
|
143
|
+
pos_x = x * get_scale(:x)
|
144
|
+
pos_y = y * get_scale(:y)
|
145
|
+
return Point.new(pos_x, pos_y) unless (has_layer?)
|
146
|
+
real_point = get_layer.get_real_point
|
147
|
+
return Point.new(
|
148
|
+
(real_point.x + pos_x),
|
149
|
+
(real_point.y + pos_y)
|
150
|
+
)
|
151
|
+
end
|
152
|
+
|
153
|
+
# Returns <tt>true</tt> if this Layer has a SolidsManager.
|
154
|
+
def has_solids_manager?
|
155
|
+
return @has_solids_manager || (has_layer? ? get_layer.has_solids_manager? : false)
|
156
|
+
end
|
157
|
+
|
158
|
+
# Returns a SolidsManager, if it has one.
|
159
|
+
def get_solids_manager
|
160
|
+
return @solids_manager if (@solids_manager)
|
161
|
+
return get_layer.get_solids_manager if (has_layer?)
|
162
|
+
return nil
|
163
|
+
end
|
164
|
+
|
165
|
+
# Overwrite the method Point#move_by, so we can
|
166
|
+
# also call #move_by on all Mask children.
|
167
|
+
# We use a little hacky workaround, by moving all children back
|
168
|
+
# the amount of incremental movement, then move this Layer forward,
|
169
|
+
# and then move all the children Masks via #move_by.
|
170
|
+
def move_by *args
|
171
|
+
incremental_position = parse_position(*args)
|
172
|
+
incremental_position[:x] ||= 0
|
173
|
+
incremental_position[:y] ||= 0
|
174
|
+
objects = get_objects.select do |object|
|
175
|
+
next object.is_a?(Mask)
|
176
|
+
end
|
177
|
+
# Move all children Masks back via #set_position.
|
178
|
+
objects.each do |mask|
|
179
|
+
mask.set_position(
|
180
|
+
(mask.x - incremental_position[:x]),
|
181
|
+
(mask.y - incremental_position[:y])
|
182
|
+
)
|
183
|
+
end
|
184
|
+
super # Move Layer forward
|
185
|
+
# Move all children Masks forward via #move_by.
|
186
|
+
objects.each do |mask|
|
187
|
+
mask.move_by incremental_position
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Call this every frame.
|
192
|
+
# This updates all its inventory objects (its children),
|
193
|
+
# if they have an #update method.
|
194
|
+
def update
|
195
|
+
call_method_on_children :update
|
196
|
+
get_solids_manager.update if (has_solids_manager?)
|
197
|
+
end
|
198
|
+
|
199
|
+
# Call this every frame.
|
200
|
+
# This draws all its inventory objects (its children),
|
201
|
+
# if they have a #draw method.
|
202
|
+
def draw
|
203
|
+
Gosu.scale(@scale[:x], @scale[:y], x, y) do
|
204
|
+
Gosu.rotate(@rotation, *get_center.values) do
|
205
|
+
Gosu.translate(*get_corner(:left, :top).get_position.values) do
|
206
|
+
call_method_on_children :draw
|
207
|
+
end
|
208
|
+
#draw_debug # TODO: Clean up
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
private
|
214
|
+
|
215
|
+
def draw_debug
|
216
|
+
# Top
|
217
|
+
Gosu.draw_line(
|
218
|
+
*get_corner(:left, :top).values, 0xff_ff0000,
|
219
|
+
*get_corner(:right, :top).values, 0xff_ff0000
|
220
|
+
)
|
221
|
+
# Right
|
222
|
+
Gosu.draw_line(
|
223
|
+
*get_corner(:right, :top).values, 0xff_ff0000,
|
224
|
+
*get_corner(:right, :bottom).values, 0xff_ff0000,
|
225
|
+
)
|
226
|
+
# Bottom
|
227
|
+
Gosu.draw_line(
|
228
|
+
*get_corner(:right, :bottom).values, 0xff_ff0000,
|
229
|
+
*get_corner(:left, :bottom).values, 0xff_ff0000,
|
230
|
+
)
|
231
|
+
# Left
|
232
|
+
Gosu.draw_line(
|
233
|
+
*get_corner(:left, :bottom).values, 0xff_ff0000,
|
234
|
+
*get_corner(:left, :top).values, 0xff_ff0000,
|
235
|
+
)
|
236
|
+
end
|
237
|
+
|
238
|
+
def call_method_on_children method_name, *args
|
239
|
+
get_objects.each do |child|
|
240
|
+
meth = nil
|
241
|
+
if (child.methods.include?(method_name))
|
242
|
+
meth = child.method(method_name)
|
243
|
+
elsif (object_mask_has_method?(child, method_name))
|
244
|
+
meth = child.get_mask.method(method_name)
|
245
|
+
end
|
246
|
+
meth.call(*args) if (meth)
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
def object_mask_has_method? object, method_name
|
251
|
+
return (
|
252
|
+
object_has_mask?(object) &&
|
253
|
+
object.get_mask.methods.include?(method_name)
|
254
|
+
)
|
255
|
+
end
|
256
|
+
|
257
|
+
def object_has_mask? object
|
258
|
+
begin
|
259
|
+
object.has_mask?
|
260
|
+
rescue NoMethodError
|
261
|
+
return false
|
262
|
+
end
|
263
|
+
return true
|
264
|
+
end
|
265
|
+
|
266
|
+
def handle_rotation_overflow
|
267
|
+
return if ((0 ... 360).include? @rotation)
|
268
|
+
@rotation -= 360 if (@rotation >= 360)
|
269
|
+
@rotation += 360 if (@rotation < 0)
|
270
|
+
handle_rotation_overflow
|
271
|
+
end
|
272
|
+
end
|
273
|
+
end
|