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.
Files changed (59) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +5 -0
  4. data/Gemfile +12 -0
  5. data/Gemfile.lock +47 -0
  6. data/LICENSE.txt +21 -0
  7. data/README.md +31 -0
  8. data/Rakefile +11 -0
  9. data/adventure_rl.gemspec +48 -0
  10. data/bin/console +7 -0
  11. data/bin/mkaudio +196 -0
  12. data/bin/mkclip +223 -0
  13. data/bin/rdoc +9 -0
  14. data/bin/setup +8 -0
  15. data/bin/vimall +5 -0
  16. data/doc/Mask.md +183 -0
  17. data/doc/Point.md +95 -0
  18. data/doc/Window.md +139 -0
  19. data/lib/AdventureRL/Animation.rb +63 -0
  20. data/lib/AdventureRL/Audio.rb +75 -0
  21. data/lib/AdventureRL/AudioPlayer.rb +65 -0
  22. data/lib/AdventureRL/Button.rb +51 -0
  23. data/lib/AdventureRL/Clip.rb +91 -0
  24. data/lib/AdventureRL/ClipPlayer.rb +187 -0
  25. data/lib/AdventureRL/Deltatime.rb +51 -0
  26. data/lib/AdventureRL/EventHandlers/Buttons.rb +225 -0
  27. data/lib/AdventureRL/EventHandlers/EventHandler.rb +62 -0
  28. data/lib/AdventureRL/EventHandlers/MouseButtons.rb +142 -0
  29. data/lib/AdventureRL/Events/Event.rb +69 -0
  30. data/lib/AdventureRL/Events/Mouse.rb +60 -0
  31. data/lib/AdventureRL/FileGroup.rb +100 -0
  32. data/lib/AdventureRL/FileGroupPlayer.rb +226 -0
  33. data/lib/AdventureRL/Helpers/Error.rb +68 -0
  34. data/lib/AdventureRL/Helpers/MethodHelper.rb +20 -0
  35. data/lib/AdventureRL/Helpers/PipeMethods.rb +26 -0
  36. data/lib/AdventureRL/Image.rb +77 -0
  37. data/lib/AdventureRL/Layer.rb +273 -0
  38. data/lib/AdventureRL/Mask.rb +462 -0
  39. data/lib/AdventureRL/Menu.rb +92 -0
  40. data/lib/AdventureRL/Modifiers/Gravity.rb +60 -0
  41. data/lib/AdventureRL/Modifiers/Inventory.rb +104 -0
  42. data/lib/AdventureRL/Modifiers/Pusher.rb +61 -0
  43. data/lib/AdventureRL/Modifiers/Solid.rb +302 -0
  44. data/lib/AdventureRL/Modifiers/Velocity.rb +163 -0
  45. data/lib/AdventureRL/Point.rb +188 -0
  46. data/lib/AdventureRL/Quadtree.rb +237 -0
  47. data/lib/AdventureRL/Rectangle.rb +62 -0
  48. data/lib/AdventureRL/Settings.rb +80 -0
  49. data/lib/AdventureRL/SolidsManager.rb +170 -0
  50. data/lib/AdventureRL/Textbox.rb +195 -0
  51. data/lib/AdventureRL/TimingHandler.rb +225 -0
  52. data/lib/AdventureRL/Window.rb +152 -0
  53. data/lib/AdventureRL/misc/extensions.rb +80 -0
  54. data/lib/AdventureRL/misc/require_files.rb +45 -0
  55. data/lib/AdventureRL/version.rb +3 -0
  56. data/lib/adventure_rl.rb +22 -0
  57. data/lib/default_settings.yml +20 -0
  58. data/vimrc +4 -0
  59. 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